Flutter Engine
The Flutter Engine
GrShape.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
10#include "include/core/SkArc.h"
12#include "src/core/SkPathPriv.h"
14
15#include <algorithm>
16
18 switch (shape.type()) {
19 case Type::kEmpty:
20 this->reset();
21 break;
22 case Type::kPoint:
23 this->setPoint(shape.fPoint);
24 break;
25 case Type::kRect:
26 this->setRect(shape.fRect);
27 break;
28 case Type::kRRect:
29 this->setRRect(shape.fRRect);
30 break;
31 case Type::kPath:
32 this->setPath(shape.fPath);
33 break;
34 case Type::kArc:
35 this->setArc(shape.fArc);
36 break;
37 case Type::kLine:
38 this->setLine(shape.fLine);
39 break;
40 }
41
42 fStart = shape.fStart;
43 fCW = shape.fCW;
44 fInverted = shape.fInverted;
45
46 return *this;
47}
48
49uint32_t GrShape::stateKey() const {
50 // Use the path's full fill type instead of just whether or not it's inverted.
51 uint32_t key = this->isPath() ? static_cast<uint32_t>(fPath.getFillType())
52 : (fInverted ? 1 : 0);
53 key |= ((uint32_t) fType) << 2; // fill type was 2 bits
54 key |= fStart << 5; // type was 3 bits, total 5 bits so far
55 key |= (fCW ? 1 : 0) << 8; // start was 3 bits, total 8 bits so far
56 return key;
57}
58
59bool GrShape::simplifyPath(unsigned flags) {
60 SkASSERT(this->isPath());
61
64 SkPoint pts[2];
65
67 unsigned start;
68
69 if (fPath.isEmpty()) {
70 this->setType(Type::kEmpty);
71 return false;
72 } else if (fPath.isLine(pts)) {
73 this->simplifyLine(pts[0], pts[1], flags);
74 return false;
75 } else if (SkPathPriv::IsRRect(fPath, &rrect, &dir, &start)) {
76 this->simplifyRRect(rrect, dir, start, flags);
77 return true;
78 } else if (SkPathPriv::IsOval(fPath, &rect, &dir, &start)) {
79 // Convert to rrect indexing since oval is not represented explicitly
80 this->simplifyRRect(SkRRect::MakeOval(rect), dir, start * 2, flags);
81 return true;
83 // When there is a path effect we restrict rect detection to the narrower API that
84 // gives us the starting position. Otherwise, we will retry with the more aggressive
85 // isRect().
86 this->simplifyRect(rect, dir, start, flags);
87 return true;
88 } else if (flags & kIgnoreWinding_Flag) {
89 // Attempt isRect() since we don't have to preserve any winding info
90 bool closed;
91 if (fPath.isRect(&rect, &closed) && (closed || (flags & kSimpleFill_Flag))) {
92 this->simplifyRect(rect, kDefaultDir, kDefaultStart, flags);
93 return true;
94 }
95 }
96 // No further simplification for a path. For performance reasons, we don't query the path to
97 // determine it was closed, as whether or not it was closed when it remains a path type is not
98 // important for styling.
99 return false;
100}
101
102bool GrShape::simplifyArc(unsigned flags) {
103 SkASSERT(this->isArc());
104
105 // Arcs can simplify to rrects, lines, points, or empty; regardless of what it simplifies to
106 // it was closed if went through the center point.
107 bool wasClosed = fArc.isWedge();
108 if (fArc.fOval.isEmpty() || !fArc.fSweepAngle) {
109 if (flags & kSimpleFill_Flag) {
110 // Go straight to empty, since the other degenerate shapes all have 0 area anyway.
111 this->setType(Type::kEmpty);
112 } else if (!fArc.fSweepAngle) {
115 SkPoint start = {center.fX + 0.5f * fArc.fOval.width() * SkScalarCos(startRad),
116 center.fY + 0.5f * fArc.fOval.height() * SkScalarSin(startRad)};
117 // Either just the starting point, or a line from the center to the start
118 if (fArc.isWedge()) {
119 this->simplifyLine(center, start, flags);
120 } else {
121 this->simplifyPoint(start, flags);
122 }
123 } else {
124 // TODO: Theoretically, we could analyze the arc projected into the empty bounds to
125 // determine a line, but that is somewhat complex for little value (since the arc
126 // can backtrack on itself if the sweep angle is large enough).
127 this->setType(Type::kEmpty);
128 }
129 } else {
130 if ((flags & kSimpleFill_Flag) ||
132 // Eligible to turn into an oval if it sweeps a full circle
133 if (fArc.fSweepAngle <= -360.f || fArc.fSweepAngle >= 360.f) {
134 this->simplifyRRect(SkRRect::MakeOval(fArc.fOval),
136 return true;
137 }
138 }
139
141 // Map start to 0 to 360, sweep is always positive
142 if (fArc.fSweepAngle < 0) {
145 }
146
147 if (fArc.fStartAngle < 0 || fArc.fStartAngle >= 360.f) {
149 }
150 }
151 }
152
153 return wasClosed;
154}
155
156void GrShape::simplifyRRect(const SkRRect& rrect, SkPathDirection dir, unsigned start,
157 unsigned flags) {
158 if (rrect.isEmpty() || rrect.isRect()) {
159 // Change index from rrect to rect
160 start = ((start + 1) / 2) % 4;
161 this->simplifyRect(rrect.rect(), dir, start, flags);
162 } else if (!this->isRRect()) {
163 this->setType(Type::kRRect);
164 fRRect = rrect;
165 this->setPathWindingParams(dir, start);
166 // A round rect is already canonical, so there's nothing more to do
167 } else {
168 // If starting as a round rect, the provided rrect/winding params should be already set
169 SkASSERT(fRRect == rrect && this->dir() == dir && this->startIndex() == start);
170 }
171}
172
173void GrShape::simplifyRect(const SkRect& rect, SkPathDirection dir, unsigned start,
174 unsigned flags) {
175 if (!rect.width() || !rect.height()) {
176 if (flags & kSimpleFill_Flag) {
177 // A zero area, filled shape so go straight to empty
178 this->setType(Type::kEmpty);
179 } else if (!rect.width() ^ !rect.height()) {
180 // A line, choose the first point that best matches the starting index
181 SkPoint p1 = {rect.fLeft, rect.fTop};
183 if (start >= 2 && !(flags & kIgnoreWinding_Flag)) {
184 using std::swap;
185 swap(p1, p2);
186 }
187 this->simplifyLine(p1, p2, flags);
188 } else {
189 // A point (all edges are equal, so start+dir doesn't affect choice)
190 this->simplifyPoint({rect.fLeft, rect.fTop}, flags);
191 }
192 } else {
193 if (!this->isRect()) {
194 this->setType(Type::kRect);
195 fRect = rect;
196 this->setPathWindingParams(dir, start);
197 } else {
198 // If starting as a rect, the provided rect/winding params should already be set
199 SkASSERT(fRect == rect && this->dir() == dir && this->startIndex() == start);
200 }
202 fRect.sort();
203 }
204 }
205}
206
207void GrShape::simplifyLine(const SkPoint& p1, const SkPoint& p2, unsigned flags) {
208 if (flags & kSimpleFill_Flag) {
209 this->setType(Type::kEmpty);
210 } else if (p1 == p2) {
211 this->simplifyPoint(p1, false);
212 } else {
213 if (!this->isLine()) {
214 this->setType(Type::kLine);
215 fLine.fP1 = p1;
216 fLine.fP2 = p2;
217 } else {
218 // If starting as a line, the provided points should already be set
219 SkASSERT(fLine.fP1 == p1 && fLine.fP2 == p2);
220 }
222 // Sort the end points
223 if (fLine.fP2.fY < fLine.fP1.fY ||
224 (fLine.fP2.fY == fLine.fP1.fY && fLine.fP2.fX < fLine.fP1.fX)) {
225 using std::swap;
227 }
228 }
229 }
230}
231
232void GrShape::simplifyPoint(const SkPoint& point, unsigned flags) {
233 if (flags & kSimpleFill_Flag) {
234 this->setType(Type::kEmpty);
235 } else if (!this->isPoint()) {
236 this->setType(Type::kPoint);
237 fPoint = point;
238 } else {
239 // If starting as a point, the provided position should already be set
241 }
242}
243
244bool GrShape::simplify(unsigned flags) {
245 // Verify that winding parameters are valid for the current type.
246 SkASSERT((fType == Type::kRect || fType == Type::kRRect) ||
247 (this->dir() == kDefaultDir && this->startIndex() == kDefaultStart));
248
249 // The type specific functions automatically fall through to the simpler shapes, so
250 // we only need to start in the right place.
251 bool wasClosed = false;
252 switch (fType) {
253 case Type::kEmpty:
254 // do nothing
255 break;
256 case Type::kPoint:
257 this->simplifyPoint(fPoint, flags);
258 break;
259 case Type::kLine:
260 this->simplifyLine(fLine.fP1, fLine.fP2, flags);
261 break;
262 case Type::kRect:
263 this->simplifyRect(fRect, this->dir(), this->startIndex(), flags);
264 wasClosed = true;
265 break;
266 case Type::kRRect:
267 this->simplifyRRect(fRRect, this->dir(), this->startIndex(), flags);
268 wasClosed = true;
269 break;
270 case Type::kPath:
271 wasClosed = this->simplifyPath(flags);
272 break;
273 case Type::kArc:
274 wasClosed = this->simplifyArc(flags);
275 break;
276
277 default:
279 }
280
281 if (((flags & kIgnoreWinding_Flag) || (fType != Type::kRect && fType != Type::kRRect))) {
282 // Reset winding parameters if we don't need them anymore
284 }
285
286 return wasClosed;
287}
288
290 switch (this->type()) {
291 case Type::kEmpty:
292 case Type::kPoint: // fall through since a point has 0 area
293 case Type::kLine: // fall through, "" (currently choosing not to test if 'rect' == line)
294 return false;
295 case Type::kRect:
296 return fRect.contains(rect);
297 case Type::kRRect:
298 return fRRect.contains(rect);
299 case Type::kPath:
301 case Type::kArc:
303 SkPath arc;
304 this->asPath(&arc);
305 return arc.conservativelyContainsRect(rect);
306 } else {
307 return false;
308 }
309 }
311}
312
313bool GrShape::conservativeContains(const SkPoint& point) const {
314 switch (this->type()) {
315 case Type::kEmpty:
316 case Type::kPoint: // fall through, currently choosing not to test if shape == point
317 case Type::kLine: // fall through, ""
318 case Type::kArc:
319 return false;
320 case Type::kRect:
321 return fRect.contains(point.fX, point.fY);
322 case Type::kRRect:
324 case Type::kPath:
325 return fPath.contains(point.fX, point.fY);
326 }
328}
329
330bool GrShape::closed() const {
331 switch (this->type()) {
332 case Type::kEmpty: // fall through
333 case Type::kRect: // fall through
334 case Type::kRRect:
335 return true;
336 case Type::kPath:
337 // SkPath doesn't keep track of the closed status of each contour.
339 case Type::kArc:
341 case Type::kPoint: // fall through
342 case Type::kLine:
343 return false;
344 }
346}
347
348bool GrShape::convex(bool simpleFill) const {
349 switch (this->type()) {
350 case Type::kEmpty: // fall through
351 case Type::kRect: // fall through
352 case Type::kRRect:
353 return true;
354 case Type::kPath:
355 // SkPath.isConvex() really means "is this path convex were it to be closed".
356 // Convex paths may only have one contour hence isLastContourClosed() is sufficient.
357 return (simpleFill || fPath.isLastContourClosed()) && fPath.isConvex();
358 case Type::kArc:
360 case Type::kPoint: // fall through
361 case Type::kLine:
362 return false;
363 }
365}
366
368 // Bounds where left == bottom or top == right can indicate a line or point shape. We return
369 // inverted bounds for a truly empty shape.
370 static constexpr SkRect kInverted = SkRect::MakeLTRB(1, 1, -1, -1);
371 switch (this->type()) {
372 case Type::kEmpty:
373 return kInverted;
374 case Type::kPoint:
375 return {fPoint.fX, fPoint.fY, fPoint.fX, fPoint.fY};
376 case Type::kRect:
377 return fRect.makeSorted();
378 case Type::kRRect:
379 return fRRect.getBounds();
380 case Type::kPath:
381 return fPath.getBounds();
382 case Type::kArc:
383 return fArc.fOval;
384 case Type::kLine: {
387 b.sort();
388 return b; }
389 }
391}
392
393uint32_t GrShape::segmentMask() const {
394 // In order to match what a path would report, this has to inspect the shapes slightly
395 // to reflect what they might simplify to.
396 switch (this->type()) {
397 case Type::kEmpty:
398 return 0;
399 case Type::kRRect:
400 if (fRRect.isEmpty() || fRRect.isRect()) {
402 } else if (fRRect.isOval()) {
404 } else {
406 }
407 case Type::kPath:
408 return fPath.getSegmentMasks();
409 case Type::kArc:
412 } else {
414 }
415 case Type::kPoint: // fall through
416 case Type::kLine: // ""
417 case Type::kRect:
419 }
421}
422
423void GrShape::asPath(SkPath* out, bool simpleFill) const {
424 if (!this->isPath() && !this->isArc()) {
425 // When not a path, we need to set fill type on the path to match invertedness.
426 // All the non-path geometries produce equivalent shapes with either even-odd or winding
427 // so we can use the default fill type.
428 out->reset();
429 out->setFillType(kDefaultFillType);
430 if (fInverted) {
431 out->toggleInverseFillType();
432 }
433 } // Else when we're already a path, that will assign the fill type directly to 'out'.
434
435 switch (this->type()) {
436 case Type::kEmpty:
437 return;
438 case Type::kPoint:
439 // A plain moveTo() or moveTo+close() does not match the expected path for a
440 // point that is being dashed (see SkDashPath's handling of zero-length segments).
441 out->moveTo(fPoint);
442 out->lineTo(fPoint);
443 return;
444 case Type::kRect:
445 out->addRect(fRect, this->dir(), this->startIndex());
446 return;
447 case Type::kRRect:
448 out->addRRect(fRRect, this->dir(), this->startIndex());
449 return;
450 case Type::kPath:
451 *out = fPath;
452 return;
453 case Type::kArc:
455 // CreateDrawArcPath resets the output path and configures its fill type, so we just
456 // have to ensure invertedness is correct.
457 if (fInverted) {
458 out->toggleInverseFillType();
459 }
460 return;
461 case Type::kLine:
462 out->moveTo(fLine.fP1);
463 out->lineTo(fLine.fP2);
464 return;
465 }
467}
#define SkUNREACHABLE
Definition: SkAssert.h:135
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkPathDirection
Definition: SkPathTypes.h:34
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define SkDegreesToRadians(degrees)
Definition: SkScalar.h:77
#define SkScalarMod(x, y)
Definition: SkScalar.h:41
#define SkScalarSin(radians)
Definition: SkScalar.h:45
#define SkScalarCos(radians)
Definition: SkScalar.h:46
static SkScalar center(float pos0, float pos1)
bool closed() const
Definition: GrShape.cpp:330
SkRRect fRRect
Definition: GrShape.h:272
GrShape & operator=(const GrShape &shape)
Definition: GrShape.cpp:17
SkRect & rect()
Definition: GrShape.h:134
GrLineSegment fLine
Definition: GrShape.h:275
Type type() const
Definition: GrShape.h:92
uint32_t stateKey() const
Definition: GrShape.cpp:49
bool isPath() const
Definition: GrShape.h:88
void setRRect(const SkRRect &rrect)
Definition: GrShape.h:163
uint32_t segmentMask() const
Definition: GrShape.cpp:393
void reset()
Definition: GrShape.h:188
bool isRRect() const
Definition: GrShape.h:87
bool isLine() const
Definition: GrShape.h:90
SkRRect & rrect()
Definition: GrShape.h:137
bool isRect() const
Definition: GrShape.h:86
void setPath(const SkPath &path)
Definition: GrShape.h:175
SkRect bounds() const
Definition: GrShape.cpp:367
void setLine(const GrLineSegment &line)
Definition: GrShape.h:171
@ kMakeCanonical_Flag
Definition: GrShape.h:203
@ kIgnoreWinding_Flag
Definition: GrShape.h:200
@ kSimpleFill_Flag
Definition: GrShape.h:197
bool isPoint() const
Definition: GrShape.h:85
SkRect fRect
Definition: GrShape.h:271
SkArc & arc()
Definition: GrShape.h:143
SkPath fPath
Definition: GrShape.h:273
void setPathWindingParams(SkPathDirection dir, unsigned start)
Definition: GrShape.h:112
SkArc fArc
Definition: GrShape.h:274
SkPathDirection dir() const
Definition: GrShape.h:105
static constexpr SkPathDirection kDefaultDir
Definition: GrShape.h:60
static constexpr SkPathFillType kDefaultFillType
Definition: GrShape.h:63
bool isArc() const
Definition: GrShape.h:89
void setArc(const SkArc &arc)
Definition: GrShape.h:167
bool conservativeContains(const SkRect &rect) const
Definition: GrShape.cpp:289
SkPoint fPoint
Definition: GrShape.h:270
unsigned startIndex() const
Definition: GrShape.h:108
static constexpr unsigned kDefaultStart
Definition: GrShape.h:61
void asPath(SkPath *out, bool simpleFill=true) const
Definition: GrShape.cpp:423
SkPoint & point()
Definition: GrShape.h:131
void setPoint(const SkPoint &point)
Definition: GrShape.h:155
bool convex(bool simpleFill=true) const
Definition: GrShape.cpp:348
void setRect(const SkRect &rect)
Definition: GrShape.h:159
bool simplify(unsigned flags=kAll_Flags)
Definition: GrShape.cpp:244
static bool IsClosedSingleContour(const SkPath &path)
Definition: SkPathPriv.h:67
static bool IsRRect(const SkPath &path, SkRRect *rrect, SkPathDirection *dir, unsigned *start)
Definition: SkPathPriv.h:272
static bool IsSimpleRect(const SkPath &path, bool isSimpleFill, SkRect *rect, SkPathDirection *direction, unsigned *start)
Definition: SkPath.cpp:3244
static bool IsOval(const SkPath &path, SkRect *rect, SkPathDirection *dir, unsigned *start)
Definition: SkPathPriv.h:245
static void CreateDrawArcPath(SkPath *path, const SkArc &arc, bool isFillNoPathEffect)
Definition: SkPath.cpp:3356
static bool DrawArcIsConvex(SkScalar sweepAngle, SkArc::Type arcType, bool isFillNoPathEffect)
Definition: SkPath.cpp:3340
Definition: SkPath.h:59
@ kLine_SegmentMask
Definition: SkPath.h:1445
@ kConic_SegmentMask
Definition: SkPath.h:1447
bool isEmpty() const
Definition: SkPath.cpp:416
bool conservativelyContainsRect(const SkRect &rect) const
Definition: SkPath.cpp:291
SkPath & moveTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:688
bool isLine(SkPoint line[2]) const
Definition: SkPath.cpp:398
SkPathFillType getFillType() const
Definition: SkPath.h:230
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1000
SkPath & reset()
Definition: SkPath.cpp:370
bool isConvex() const
Definition: SkPath.cpp:426
const SkRect & getBounds() const
Definition: SkPath.cpp:430
uint32_t getSegmentMasks() const
Definition: SkPath.cpp:434
bool isLastContourClosed() const
Definition: SkPath.cpp:390
bool isRect(SkRect *rect, bool *isClosed=nullptr, SkPathDirection *direction=nullptr) const
Definition: SkPath.cpp:516
bool contains(SkScalar x, SkScalar y) const
Definition: SkPath.cpp:3118
static bool ContainsPoint(const SkRRect &rr, const SkPoint &p)
Definition: SkRRectPriv.h:48
bool isOval() const
Definition: SkRRect.h:85
const SkRect & rect() const
Definition: SkRRect.h:264
static SkRRect MakeOval(const SkRect &oval)
Definition: SkRRect.h:162
bool isRect() const
Definition: SkRRect.h:84
bool contains(const SkRect &rect) const
Definition: SkRRect.cpp:360
bool isEmpty() const
Definition: SkRRect.h:83
const SkRect & getBounds() const
Definition: SkRRect.h:279
float SkScalar
Definition: extension.cpp:12
static bool b
FlutterSemanticsFlag flags
SkRRect rrect
Definition: SkRecords.h:232
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
SkPoint fP2
Definition: GrShape.h:28
SkPoint fP1
Definition: GrShape.h:27
Type fType
Definition: SkArc.h:62
SkScalar fSweepAngle
Definition: SkArc.h:60
SkScalar fStartAngle
Definition: SkArc.h:58
SkRect fOval
Definition: SkArc.h:55
bool isWedge() const
Definition: SkArc.h:28
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165
SkRect makeSorted() const
Definition: SkRect.h:1330
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
bool contains(SkScalar x, SkScalar y) const
Definition: extension.cpp:19
constexpr float centerX() const
Definition: SkRect.h:776
constexpr float height() const
Definition: SkRect.h:769
constexpr float centerY() const
Definition: SkRect.h:785
constexpr float width() const
Definition: SkRect.h:762
bool isEmpty() const
Definition: SkRect.h:693
void sort()
Definition: SkRect.h:1313
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15