1/*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "experimental/graphite/src/geom/Shape.h"
9
10#include "src/core/SkPathPriv.h"
11#include "src/core/SkRRectPriv.h"
12#include "src/utils/SkPolyUtils.h"
13
14namespace skgpu {
15
16Shape& Shape::operator=(const Shape& shape) {
17    switch (shape.type()) {
18        case Type::kEmpty: this->reset();                         break;
19        case Type::kLine:  this->setLine(shape.p0(), shape.p1()); break;
20        case Type::kRect:  this->setRect(shape.rect());           break;
21        case Type::kRRect: this->setRRect(shape.rrect());         break;
22        case Type::kPath:  this->setPath(shape.path());           break;
23    }
24
25    fInverted = shape.fInverted;
26    return *this;
27}
28
29bool Shape::conservativeContains(const Rect& rect) const {
30    switch (fType) {
31        case Type::kEmpty: return false;
32        case Type::kLine:  return false;
33        case Type::kRect:  return fRect.contains(rect);
34        case Type::kRRect: return fRRect.contains(rect.asSkRect());
35        case Type::kPath:  return fPath.conservativelyContainsRect(rect.asSkRect());
36    }
37    SkUNREACHABLE;
38}
39
40bool Shape::conservativeContains(float2 point) const {
41    switch (fType) {
42        case Type::kEmpty: return false;
43        case Type::kLine:  return false;
44        case Type::kRect:  return fRect.contains(Rect::Point(point));
45        case Type::kRRect: return SkRRectPriv::ContainsPoint(fRRect, {point.x(), point.y()});
46        case Type::kPath:  return fPath.contains(point.x(), point.y());
47    }
48    SkUNREACHABLE;
49}
50
51bool Shape::closed() const {
52    switch (fType) {
53        case Type::kEmpty: return true;
54        case Type::kLine:  return false;
55        case Type::kRect:  return true;
56        case Type::kRRect: return true;
57        case Type::kPath:  return SkPathPriv::IsClosedSingleContour(fPath);
58    }
59    SkUNREACHABLE;
60}
61
62bool Shape::convex(bool simpleFill) const {
63    if (this->isPath()) {
64        // SkPath.isConvex() really means "is this path convex were it to be closed".
65        return (simpleFill || fPath.isLastContourClosed()) && fPath.isConvex();
66    } else {
67        // Every other shape type is convex by construction.
68        return true;
69    }
70}
71
72Rect Shape::bounds() const {
73    switch (fType) {
74        case Type::kEmpty: return Rect(0, 0, 0, 0);
75        case Type::kLine:  return fRect.makeSorted(); // sorting corners computes bbox of segment
76        case Type::kRect:  return fRect; // assuming it's sorted
77        case Type::kRRect: return fRRect.getBounds();
78        case Type::kPath:  return fPath.getBounds();
79    }
80    SkUNREACHABLE;
81}
82
83SkPath Shape::asPath() const {
84    if (fType == Type::kPath) {
85        return fPath;
86    }
87
88    SkPathBuilder builder(this->fillType());
89    switch (fType) {
90        case Type::kEmpty: /* do nothing */                            break;
91        case Type::kLine:  builder.moveTo(fRect.left(), fRect.top())
92                                  .lineTo(fRect.right(), fRect.bot()); break;
93        case Type::kRect:  builder.addRect(fRect.asSkRect());          break;
94        case Type::kRRect: builder.addRRect(fRRect);                   break;
95        case Type::kPath:  SkUNREACHABLE;
96    }
97    return builder.detach();
98}
99
100} // namespace skgpu
101