Flutter Engine
The Flutter Engine
Shape.cpp
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
9
11#include "src/core/SkPathPriv.h"
14
15namespace {
16// Keys for paths may be extracted from the path data for small paths, to maximize matches
17// even when the genIDs may differ. The value is based on emperical experience, to trade off
18// matches vs. key size.
19constexpr int kMaxKeyFromDataVerbCnt = 10;
20}
21
22namespace skgpu::graphite {
23
25 switch (shape.type()) {
26 case Type::kEmpty: this->reset(); break;
27 case Type::kLine: this->setLine(shape.p0(), shape.p1()); break;
28 case Type::kRect: this->setRect(shape.rect()); break;
29 case Type::kRRect: this->setRRect(shape.rrect()); break;
30 case Type::kPath: this->setPath(shape.path()); break;
31 }
32
33 fInverted = shape.fInverted;
34 return *this;
35}
36
38 switch (fType) {
39 case Type::kEmpty: return false;
40 case Type::kLine: return false;
41 case Type::kRect: return fRect.contains(rect);
44 }
46}
47
49 switch (fType) {
50 case Type::kEmpty: return false;
51 case Type::kLine: return false;
52 case Type::kRect: return fRect.contains(Rect::Point(point));
53 case Type::kRRect: return SkRRectPriv::ContainsPoint(fRRect, {point.x(), point.y()});
54 case Type::kPath: return fPath.contains(point.x(), point.y());
55 }
57}
58
59bool Shape::convex(bool simpleFill) const {
60 if (this->isPath()) {
61 // SkPath.isConvex() really means "is this path convex were it to be closed".
62 return (simpleFill || fPath.isLastContourClosed()) && fPath.isConvex();
63 } else {
64 // Every other shape type is convex by construction.
65 return true;
66 }
67}
68
70 switch (fType) {
71 case Type::kEmpty: return Rect(0, 0, 0, 0);
72 case Type::kLine: return fRect.makeSorted(); // sorting corners computes bbox of segment
73 case Type::kRect: return fRect; // assuming it's sorted
74 case Type::kRRect: return fRRect.getBounds();
75 case Type::kPath: return fPath.getBounds();
76 }
78}
79
81 if (fType == Type::kPath) {
82 return fPath;
83 }
84
86 switch (fType) {
87 case Type::kEmpty: /* do nothing */ break;
88 case Type::kLine: builder.moveTo(fRect.left(), fRect.top())
89 .lineTo(fRect.right(), fRect.bot()); break;
90 case Type::kRect: builder.addRect(fRect.asSkRect()); break;
91 case Type::kRRect: builder.addRRect(fRRect); break;
93 }
94 return builder.detach();
95}
96
97namespace {
99 const int verbCnt = path.countVerbs();
100 if (verbCnt > kMaxKeyFromDataVerbCnt) {
101 return -1;
102 }
103 const int pointCnt = path.countPoints();
104 const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
105
106 static_assert(sizeof(SkPoint) == 2 * sizeof(uint32_t));
107 static_assert(sizeof(SkScalar) == sizeof(uint32_t));
108 // 1 is for the verb count. Each verb is a byte but we'll pad the verb data out to
109 // a uint32_t length.
110 return 1 + (SkAlign4(verbCnt) >> 2) + 2 * pointCnt + conicWeightCnt;
111}
112
113// Writes the path data key into the passed pointer.
114void write_path_key_from_data(const SkPath& path, uint32_t* origKey) {
115 uint32_t* key = origKey;
116 // The check below should take care of negative values casted positive.
117 const int verbCnt = path.countVerbs();
118 const int pointCnt = path.countPoints();
119 const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
120 SkASSERT(verbCnt <= kMaxKeyFromDataVerbCnt);
121 SkASSERT(pointCnt && verbCnt);
122 *key++ = verbCnt;
123 memcpy(key, SkPathPriv::VerbData(path), verbCnt * sizeof(uint8_t));
124 int verbKeySize = SkAlign4(verbCnt);
125 // pad out to uint32_t alignment using value that will stand out when debugging.
126 uint8_t* pad = reinterpret_cast<uint8_t*>(key)+ verbCnt;
127 memset(pad, 0xDE, verbKeySize - verbCnt);
128 key += verbKeySize >> 2;
129
130 memcpy(key, SkPathPriv::PointData(path), sizeof(SkPoint) * pointCnt);
131 static_assert(sizeof(SkPoint) == 2 * sizeof(uint32_t));
132 key += 2 * pointCnt;
134 static_assert(sizeof(SkScalar) == sizeof(uint32_t));
135 SkDEBUGCODE(key += conicWeightCnt);
137}
138} // anonymous namespace
139
140int Shape::keySize() const {
141 int count = 1; // Every key has the state flags from the Shape
142 switch(this->type()) {
143 case Type::kLine:
144 static_assert(0 == sizeof(skvx::float4) % sizeof(uint32_t));
145 count += sizeof(skvx::float4) / sizeof(uint32_t);
146 break;
147 case Type::kRect:
148 static_assert(0 == sizeof(Rect) % sizeof(uint32_t));
149 count += sizeof(Rect) / sizeof(uint32_t);
150 break;
151 case Type::kRRect:
152 static_assert(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
153 count += SkRRect::kSizeInMemory / sizeof(uint32_t);
154 break;
155 case Type::kPath: {
156 if (this->path().isVolatile()) {
157 return -1; // volatile, so won't be keyed
158 }
159 if (this->path().isEmpty()) {
160 return -1; // empty, so won't be keyed
161 }
162 int dataKeySize = path_key_from_data_size(this->path());
163 if (dataKeySize >= 0) {
164 count += dataKeySize;
165 } else {
166 count++; // Just adds the gen ID.
167 }
168 break;
169 }
170 default:
171 // else it's empty, which just needs the state flags for its key
172 SkASSERT(this->isEmpty());
173 }
174 return count;
175}
176
177void Shape::writeKey(uint32_t* key, bool includeInverted) const {
178 SkASSERT(this->keySize());
179 SkDEBUGCODE(uint32_t* origKey = key;)
180
181 // Every key starts with the state from the Shape (this includes path fill type,
182 // and any tracked inversion, as well as the class of geometry).
183 *key++ = this->stateKey(includeInverted);
184
185 switch(this->type()) {
186 case Type::kPath: {
187 SkASSERT(!this->path().isVolatile());
188 SkASSERT(!this->path().isEmpty());
189 // Ensure that the path's inversion matches our state so that the path's key suffices.
190 SkASSERT(this->inverted() == this->path().isInverseFillType());
191
192 int dataKeySize = path_key_from_data_size(this->path());
193 if (dataKeySize >= 0) {
194 write_path_key_from_data(this->path(), key);
195 return;
196 } else {
197 *key++ = this->path().getGenerationID();
198 }
199 break;
200 }
201 case Type::kRect:
202 memcpy(key, &this->rect(), sizeof(Rect));
203 key += sizeof(Rect) / sizeof(uint32_t);
204 break;
205 case Type::kRRect:
206 this->rrect().writeToMemory(key);
207 key += SkRRect::kSizeInMemory / sizeof(uint32_t);
208 break;
209 case Type::kLine: {
210 skvx::float4 line = this->line();
211 memcpy(key, &line, sizeof(skvx::float4));
212 key += sizeof(skvx::float4) / sizeof(uint32_t);
213 break;
214 }
215 default:
216 // Nothing other than the flag state is needed in the key for an empty shape
217 SkASSERT(this->isEmpty());
218 }
219 SkASSERT(key - origKey == this->keySize());
220}
221
222namespace {
223SkPathFillType noninverted_fill_type(SkPathFillType fillType) {
224 switch (fillType) {
231 }
233}
234} // anonymous namespace
235
236uint32_t Shape::stateKey(bool includeInverted) const {
237 uint32_t key;
238 if (includeInverted) {
239 // Use the path's full fill type instead of just whether or not it's inverted.
240 key = this->isPath() ? static_cast<uint32_t>(fPath.getFillType())
241 : (fInverted ? 1 : 0);
242 } else {
243 // Use the path's noninverted fill type.
244 key = this->isPath() ? static_cast<uint32_t>(noninverted_fill_type(fPath.getFillType()))
245 : 0;
246 }
247 key |= ((uint32_t) fType) << 2; // fill type was 2 bits
248 return key;
249}
250
251} // namespace skgpu::graphite
int count
Definition: FontMgrTest.cpp:50
static int path_key_from_data_size(const SkPath &path)
static void write_path_key_from_data(const SkPath &path, uint32_t *origKey)
static constexpr T SkAlign4(T x)
Definition: SkAlign.h:16
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SkASSERT(cond)
Definition: SkAssert.h:116
static void * sk_careful_memcpy(void *dst, const void *src, size_t len)
Definition: SkMalloc.h:125
SkPathFillType
Definition: SkPathTypes.h:11
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static const uint8_t * VerbData(const SkPath &path)
Definition: SkPathPriv.h:198
static const SkScalar * ConicWeightData(const SkPath &path)
Definition: SkPathPriv.h:213
static const SkPoint * PointData(const SkPath &path)
Definition: SkPathPriv.h:203
static int ConicWeightCnt(const SkPath &path)
Definition: SkPathPriv.h:208
Definition: SkPath.h:59
bool isEmpty() const
Definition: SkPath.cpp:416
uint32_t getGenerationID() const
Definition: SkPath.cpp:366
bool conservativelyContainsRect(const SkRect &rect) const
Definition: SkPath.cpp:291
SkPathFillType getFillType() const
Definition: SkPath.h:230
bool isVolatile() const
Definition: SkPath.h:350
bool isConvex() const
Definition: SkPath.cpp:426
const SkRect & getBounds() const
Definition: SkPath.cpp:430
bool isLastContourClosed() const
Definition: SkPath.cpp:390
bool contains(SkScalar x, SkScalar y) const
Definition: SkPath.cpp:3118
static bool ContainsPoint(const SkRRect &rr, const SkPoint &p)
Definition: SkRRectPriv.h:48
size_t writeToMemory(void *buffer) const
Definition: SkRRect.cpp:599
bool contains(const SkRect &rect) const
Definition: SkRRect.cpp:360
static constexpr size_t kSizeInMemory
Definition: SkRRect.h:422
const SkRect & getBounds() const
Definition: SkRRect.h:279
AI bool contains(Rect rect) const
Definition: Rect.h:127
AI float bot() const
Definition: Rect.h:79
AI float top() const
Definition: Rect.h:77
AI float left() const
Definition: Rect.h:76
AI Rect makeSorted() const
Definition: Rect.h:141
AI SkRect asSkRect() const
Definition: Rect.h:91
static AI Rect Point(float2 p)
Definition: Rect.h:52
AI float right() const
Definition: Rect.h:78
bool convex(bool simpleFill=true) const
Definition: Shape.cpp:59
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
bool inverted() const
Definition: Shape.h:65
void setRRect(const SkRRect &rrect)
Definition: Shape.h:131
bool isEmpty() const
Definition: Shape.h:59
skvx::float2 p1() const
Definition: Shape.h:103
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
const Rect & rect() const
Definition: Shape.h:105
bool conservativeContains(const Rect &rect) const
Definition: Shape.cpp:37
void setRect(const SkRect &rect)
Definition: Shape.h:125
void setPath(const SkPath &path)
Definition: Shape.h:136
bool isPath() const
Definition: Shape.h:63
Type type() const
Definition: Shape.h:57
float SkScalar
Definition: extension.cpp:12
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
TRect< Scalar > Rect
Definition: rect.h:769
Vec< 4, float > float4
Definition: SkVx.h:1146
Definition: SkVx.h:83