Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
37bool Shape::conservativeContains(const Rect& rect) const {
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
85 SkPathBuilder builder(this->fillType());
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 {
98int path_key_from_data_size(const SkPath& path) {
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;
133 sk_careful_memcpy(key, SkPathPriv::ConicWeightData(path), sizeof(SkScalar) * conicWeightCnt);
134 static_assert(sizeof(SkScalar) == sizeof(uint32_t));
135 SkDEBUGCODE(key += conicWeightCnt);
136 SkASSERT(key - origKey == path_key_from_data_size(path));
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
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
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static void * sk_careful_memcpy(void *dst, const void *src, size_t len)
Definition SkMalloc.h:125
SkPathFillType
Definition SkPathTypes.h:11
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
bool isEmpty() const
Definition SkPath.cpp:406
uint32_t getGenerationID() const
Definition SkPath.cpp:356
bool conservativelyContainsRect(const SkRect &rect) const
Definition SkPath.cpp:289
SkPathFillType getFillType() const
Definition SkPath.h:230
bool isVolatile() const
Definition SkPath.h:350
bool isConvex() const
Definition SkPath.cpp:416
const SkRect & getBounds() const
Definition SkPath.cpp:420
bool isLastContourClosed() const
Definition SkPath.cpp:380
bool contains(SkScalar x, SkScalar y) const
Definition SkPath.cpp:3054
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
Vec< 4, float > float4
Definition SkVx.h:1146