Flutter Engine
The Flutter Engine
Shape.h
Go to the documentation of this file.
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#ifndef skgpu_graphite_geom_Shape_DEFINED
9#define skgpu_graphite_geom_Shape_DEFINED
10
11#include "include/core/SkM44.h"
12#include "include/core/SkPath.h"
14#include "include/core/SkRect.h"
15
16#include "src/base/SkVx.h"
18
19#include <array>
20
21namespace skgpu::graphite {
22
23/**
24 * Shape is effectively a std::variant over different geometric shapes, with the most complex
25 * being an SkPath. It provides a consistent way to query geometric properties, such as convexity,
26 * point containment, or iteration.
27 */
28class Shape {
29public:
30 enum class Type : uint8_t {
31 kEmpty, kLine, kRect, kRRect, kPath
32 };
33 inline static constexpr int kTypeCount = static_cast<int>(Type::kPath) + 1;
34
35 Shape() {}
36 Shape(const Shape& shape) { *this = shape; }
37 Shape(Shape&&) = delete;
38
39 Shape(SkPoint p0, SkPoint p1) { this->setLine(p0, p1); }
40 Shape(SkV2 p0, SkV2 p1) { this->setLine(p0, p1); }
42 explicit Shape(const Rect& rect) { this->setRect(rect); }
43 explicit Shape(const SkRect& rect) { this->setRect(rect); }
44 explicit Shape(const SkRRect& rrect) { this->setRRect(rrect); }
45 explicit Shape(const SkPath& path) { this->setPath(path); }
46
47 ~Shape() { this->reset(); }
48
49 // NOTE: None of the geometry types benefit from move semantics, so we don't bother
50 // defining a move assignment operator for Shape.
51 Shape& operator=(Shape&&) = delete;
52 Shape& operator=(const Shape&);
53
54 // Return the type of the data last stored in the Shape, which does not incorporate any possible
55 // simplifications that could be applied to it (e.g. a degenerate round rect with 0 radius
56 // corners is kRRect and not kRect).
57 Type type() const { return fType; }
58
59 bool isEmpty() const { return fType == Type::kEmpty; }
60 bool isLine() const { return fType == Type::kLine; }
61 bool isRect() const { return fType == Type::kRect; }
62 bool isRRect() const { return fType == Type::kRRect; }
63 bool isPath() const { return fType == Type::kPath; }
64
65 bool inverted() const {
66 SkASSERT(fType != Type::kPath || fInverted == fPath.isInverseFillType());
67 return fInverted;
68 }
69
70 void setInverted(bool inverted) {
71 if (fType == Type::kPath && inverted != fPath.isInverseFillType()) {
73 }
74 fInverted = inverted;
75 }
76
78 if (fType == Type::kPath) {
79 return fPath.getFillType(); // already incorporates invertedness
80 } else {
82 }
83 }
84
85 // True if the given bounding box is completely inside the shape, if it's conservatively treated
86 // as a filled, closed shape.
87 bool conservativeContains(const Rect& rect) const;
88 bool conservativeContains(skvx::float2 point) const;
89
90 // True if the underlying shape is known to be convex, assuming no other styles. If 'simpleFill'
91 // is true, it is assumed the contours will be implicitly closed when drawn or used.
92 bool convex(bool simpleFill = true) const;
93
94 // The bounding box of the shape.
95 Rect bounds() const;
96
97 // Convert the shape into a path that describes the same geometry.
98 SkPath asPath() const;
99
100 // Access the actual geometric description of the shape. May only access the appropriate type
101 // based on what was last set.
102 skvx::float2 p0() const { SkASSERT(this->isLine()); return fRect.topLeft(); }
103 skvx::float2 p1() const { SkASSERT(this->isLine()); return fRect.botRight(); }
104 skvx::float4 line() const { SkASSERT(this->isLine()); return fRect.ltrb(); }
105 const Rect& rect() const { SkASSERT(this->isRect()); return fRect; }
106 const SkRRect& rrect() const { SkASSERT(this->isRRect()); return fRRect; }
107 const SkPath& path() const { SkASSERT(this->isPath()); return fPath; }
108
109 // Update the geometry stored in the Shape and update its associated type to match. This
110 // performs no simplification, so calling setRRect() with a round rect that has isRect() return
111 // true will still be considered an rrect by Shape.
112 //
113 // These reset inversion to the default for the geometric type.
115 this->setLine(skvx::float2{p0.fX, p0.fY}, skvx::float2{p1.fX, p1.fY});
116 }
118 this->setLine(skvx::float2{p0.x, p0.y}, skvx::float2{p1.x, p1.y});
119 }
121 this->setType(Type::kLine);
122 fRect = Rect(p0, p1);
123 fInverted = false;
124 }
125 void setRect(const SkRect& rect) { this->setRect(Rect(rect)); }
126 void setRect(const Rect& rect) {
127 this->setType(Type::kRect);
128 fRect = rect;
129 fInverted = false;
130 }
131 void setRRect(const SkRRect& rrect) {
132 this->setType(Type::kRRect);
133 fRRect = rrect;
134 fInverted = false;
135 }
136 void setPath(const SkPath& path) {
137 if (fType == Type::kPath) {
138 // Assign directly
139 fPath = path;
140 } else {
141 // In-place initialize
142 this->setType(Type::kPath);
143 new (&fPath) SkPath(path);
144 }
145 fInverted = path.isInverseFillType();
146 }
147
148 void reset() {
149 this->setType(Type::kEmpty);
150 fInverted = false;
151 }
152
153 /**
154 * Gets the size of the key for the shape represented by this Shape.
155 * A negative value is returned if the shape has no key (shouldn't be cached).
156 */
157 int keySize() const;
158
159 bool hasKey() const { return this->keySize() >= 0; }
160
161 /**
162 * Writes keySize() bytes into the provided pointer. Assumes that there is enough
163 * space allocated for the key and that keySize() does not return a negative value
164 * for this shape. If includeInverted is false, non-inverted state will be written
165 * into the key regardless of the Shape's state.
166 */
167 void writeKey(uint32_t* key, bool includeInverted) const;
168
169private:
170 void setType(Type type) {
171 if (this->isPath() && type != Type::kPath) {
172 fPath.~SkPath();
173 }
174 fType = type;
175 }
176
177 /**
178 * Key for the state data in the shape. This includes path fill type,
179 * and any tracked inversion, as well as the class of geometry.
180 * If includeInverted is false, non-inverted state will be written into
181 * the key regardless of the Shape's state.
182 */
183 uint32_t stateKey(bool includeInverted) const;
184
185 union {
186 Rect fRect; // p0 = top-left, p1 = bot-right if type is kLine (may be unsorted)
189 };
190
191 Type fType = Type::kEmpty;
192 bool fInverted = false;
193};
194
195} // namespace skgpu::graphite
196
197#endif // skgpu_graphite_geom_Shape_DEFINED
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkPathFillType
Definition: SkPathTypes.h:11
@ kRRect
Definition: SkPath.h:59
bool isInverseFillType() const
Definition: SkPath.h:244
SkPathFillType getFillType() const
Definition: SkPath.h:230
void toggleInverseFillType()
Definition: SkPath.h:249
~SkPath()
Definition: SkPath.cpp:186
AI float2 topLeft() const
Definition: Rect.h:80
AI float2 botRight() const
Definition: Rect.h:81
AI float4 ltrb() const
Definition: Rect.h:82
bool convex(bool simpleFill=true) const
Definition: Shape.cpp:59
Shape(const SkPath &path)
Definition: Shape.h:45
void setLine(SkPoint p0, SkPoint p1)
Definition: Shape.h:114
const SkPath & path() const
Definition: Shape.h:107
skvx::float2 p0() const
Definition: Shape.h:102
Rect bounds() const
Definition: Shape.cpp:69
Shape(const Rect &rect)
Definition: Shape.h:42
bool inverted() const
Definition: Shape.h:65
Shape(SkPoint p0, SkPoint p1)
Definition: Shape.h:39
Shape(SkV2 p0, SkV2 p1)
Definition: Shape.h:40
void setRRect(const SkRRect &rrect)
Definition: Shape.h:131
Shape(const SkRRect &rrect)
Definition: Shape.h:44
void setRect(const Rect &rect)
Definition: Shape.h:126
bool isRect() const
Definition: Shape.h:61
bool isEmpty() const
Definition: Shape.h:59
void setLine(SkV2 p0, SkV2 p1)
Definition: Shape.h:117
bool hasKey() const
Definition: Shape.h:159
bool isLine() const
Definition: Shape.h:60
skvx::float2 p1() const
Definition: Shape.h:103
Shape(skvx::float2 p0, skvx::float2 p1)
Definition: Shape.h:41
int keySize() const
Definition: Shape.cpp:140
Shape & operator=(Shape &&)=delete
void writeKey(uint32_t *key, bool includeInverted) const
Definition: Shape.cpp:177
SkPath asPath() const
Definition: Shape.cpp:80
skvx::float4 line() const
Definition: Shape.h:104
SkPathFillType fillType() const
Definition: Shape.h:77
const SkRRect & rrect() const
Definition: Shape.h:106
bool isRRect() const
Definition: Shape.h:62
void setInverted(bool inverted)
Definition: Shape.h:70
const Rect & rect() const
Definition: Shape.h:105
bool conservativeContains(const Rect &rect) const
Definition: Shape.cpp:37
Shape(const Shape &shape)
Definition: Shape.h:36
void setRect(const SkRect &rect)
Definition: Shape.h:125
static constexpr int kTypeCount
Definition: Shape.h:33
Shape(Shape &&)=delete
void setPath(const SkPath &path)
Definition: Shape.h:136
void setLine(skvx::float2 p0, skvx::float2 p1)
Definition: Shape.h:120
Shape(const SkRect &rect)
Definition: Shape.h:43
bool isPath() const
Definition: Shape.h:63
Type type() const
Definition: Shape.h:57
TRect< Scalar > Rect
Definition: rect.h:769
Definition: SkM44.h:19
Definition: SkVx.h:83