Flutter Engine
The Flutter Engine
SkEdgeClipper.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2009 The Android Open Source Project
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/SkRect.h"
13#include "src/core/SkGeometry.h"
15#include "src/core/SkPathPriv.h"
16
17#include <algorithm>
18#include <cstring>
19
20static bool quick_reject(const SkRect& bounds, const SkRect& clip) {
21 return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
22}
23
24static inline void clamp_le(SkScalar& value, SkScalar max) {
25 if (value > max) {
26 value = max;
27 }
28}
29
30static inline void clamp_ge(SkScalar& value, SkScalar min) {
31 if (value < min) {
32 value = min;
33 }
34}
35
36/* src[] must be monotonic in Y. This routine copies src into dst, and sorts
37 it to be increasing in Y. If it had to reverse the order of the points,
38 it returns true, otherwise it returns false
39 */
40static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
41 // we need the data to be monotonically increasing in Y
42 if (src[0].fY > src[count - 1].fY) {
43 for (int i = 0; i < count; i++) {
44 dst[i] = src[count - i - 1];
45 }
46 return true;
47 } else {
48 memcpy(dst, src, count * sizeof(SkPoint));
49 return false;
50 }
51}
52
54 fCurrPoint = fPoints;
55 fCurrVerb = fVerbs;
56
58 const SkPoint pts[] = { p0, p1 };
59 int lineCount = SkLineClipper::ClipLine(pts, clip, lines, fCanCullToTheRight);
60 for (int i = 0; i < lineCount; i++) {
61 this->appendLine(lines[i], lines[i + 1]);
62 }
63
64 *fCurrVerb = SkPath::kDone_Verb;
65 fCurrPoint = fPoints;
66 fCurrVerb = fVerbs;
67 return SkPath::kDone_Verb != fVerbs[0];
68}
69
70///////////////////////////////////////////////////////////////////////////////
71
74 /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
75 * We solve for t, using quadratic equation, hence we have to rearrange
76 * our cooefficents to look like At^2 + Bt + C
77 */
78 SkScalar A = c0 - c1 - c1 + c2;
79 SkScalar B = 2*(c1 - c0);
80 SkScalar C = c0 - target;
81
82 SkScalar roots[2]; // we only expect one, but make room for 2 for safety
84 if (count) {
85 *t = roots[0];
86 return true;
87 }
88 return false;
89}
90
91static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
92 return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
93}
94
95static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
96 return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
97}
98
99// Modify pts[] in place so that it is clipped in Y to the clip rect
100static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
101 SkScalar t;
102 SkPoint tmp[5]; // for SkChopQuadAt
103
104 // are we partially above
105 if (pts[0].fY < clip.fTop) {
106 if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
107 // take the 2nd chopped quad
108 SkChopQuadAt(pts, tmp, t);
109 // clamp to clean up imprecise numerics in the chop
110 tmp[2].fY = clip.fTop;
111 clamp_ge(tmp[3].fY, clip.fTop);
112
113 pts[0] = tmp[2];
114 pts[1] = tmp[3];
115 } else {
116 // if chopMonoQuadAtY failed, then we may have hit inexact numerics
117 // so we just clamp against the top
118 for (int i = 0; i < 3; i++) {
119 if (pts[i].fY < clip.fTop) {
120 pts[i].fY = clip.fTop;
121 }
122 }
123 }
124 }
125
126 // are we partially below
127 if (pts[2].fY > clip.fBottom) {
128 if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
129 SkChopQuadAt(pts, tmp, t);
130 // clamp to clean up imprecise numerics in the chop
131 clamp_le(tmp[1].fY, clip.fBottom);
132 tmp[2].fY = clip.fBottom;
133
134 pts[1] = tmp[1];
135 pts[2] = tmp[2];
136 } else {
137 // if chopMonoQuadAtY failed, then we may have hit inexact numerics
138 // so we just clamp against the bottom
139 for (int i = 0; i < 3; i++) {
140 if (pts[i].fY > clip.fBottom) {
141 pts[i].fY = clip.fBottom;
142 }
143 }
144 }
145 }
146}
147
148// srcPts[] must be monotonic in X and Y
149void SkEdgeClipper::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
150 SkPoint pts[3];
151 bool reverse = sort_increasing_Y(pts, srcPts, 3);
152
153 // are we completely above or below
154 if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
155 return;
156 }
157
158 // Now chop so that pts is contained within clip in Y
159 chop_quad_in_Y(pts, clip);
160
161 if (pts[0].fX > pts[2].fX) {
162 using std::swap;
163 swap(pts[0], pts[2]);
164 reverse = !reverse;
165 }
166 SkASSERT(pts[0].fX <= pts[1].fX);
167 SkASSERT(pts[1].fX <= pts[2].fX);
168
169 // Now chop in X has needed, and record the segments
170
171 if (pts[2].fX <= clip.fLeft) { // wholly to the left
172 this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
173 return;
174 }
175 if (pts[0].fX >= clip.fRight) { // wholly to the right
176 if (!this->canCullToTheRight()) {
177 this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
178 }
179 return;
180 }
181
182 SkScalar t;
183 SkPoint tmp[5]; // for SkChopQuadAt
184
185 // are we partially to the left
186 if (pts[0].fX < clip.fLeft) {
187 if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
188 SkChopQuadAt(pts, tmp, t);
189 this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
190 // clamp to clean up imprecise numerics in the chop
191 tmp[2].fX = clip.fLeft;
192 clamp_ge(tmp[3].fX, clip.fLeft);
193
194 pts[0] = tmp[2];
195 pts[1] = tmp[3];
196 } else {
197 // if chopMonoQuadAtY failed, then we may have hit inexact numerics
198 // so we just clamp against the left
199 this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
200 return;
201 }
202 }
203
204 // are we partially to the right
205 if (pts[2].fX > clip.fRight) {
206 if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
207 SkChopQuadAt(pts, tmp, t);
208 // clamp to clean up imprecise numerics in the chop
209 clamp_le(tmp[1].fX, clip.fRight);
210 tmp[2].fX = clip.fRight;
211
212 this->appendQuad(tmp, reverse);
213 this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
214 } else {
215 // if chopMonoQuadAtY failed, then we may have hit inexact numerics
216 // so we just clamp against the right
217 pts[1].fX = std::min(pts[1].fX, clip.fRight);
218 pts[2].fX = std::min(pts[2].fX, clip.fRight);
219 this->appendQuad(pts, reverse);
220 }
221 } else { // wholly inside the clip
222 this->appendQuad(pts, reverse);
223 }
224}
225
226bool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
227 fCurrPoint = fPoints;
228 fCurrVerb = fVerbs;
229
231 bounds.setBounds(srcPts, 3);
232
233 if (!quick_reject(bounds, clip)) {
234 SkPoint monoY[5];
235 int countY = SkChopQuadAtYExtrema(srcPts, monoY);
236 for (int y = 0; y <= countY; y++) {
237 SkPoint monoX[5];
238 int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
239 for (int x = 0; x <= countX; x++) {
240 this->clipMonoQuad(&monoX[x * 2], clip);
241 SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
242 SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
243 }
244 }
245 }
246
247 *fCurrVerb = SkPath::kDone_Verb;
248 fCurrPoint = fPoints;
249 fCurrVerb = fVerbs;
250 return SkPath::kDone_Verb != fVerbs[0];
251}
252
253///////////////////////////////////////////////////////////////////////////////
254
256 SkScalar t = 0.5f;
257 SkScalar lastT;
259 SkScalar step = 0.25f;
260 SkScalar D = src[0];
261 SkScalar A = src[6] + 3*(src[2] - src[4]) - D;
262 SkScalar B = 3*(src[4] - src[2] - src[2] + D);
263 SkScalar C = 3*(src[2] - D);
264 x -= D;
265 SkScalar closest = SK_ScalarMax;
266 do {
267 SkScalar loc = ((A * t + B) * t + C) * t;
268 SkScalar dist = SkScalarAbs(loc - x);
269 if (closest > dist) {
270 closest = dist;
271 bestT = t;
272 }
273 lastT = t;
274 t += loc < x ? step : -step;
275 step *= 0.5f;
276 } while (closest > 0.25f && lastT != t);
277 return bestT;
278}
279
281 if (SkChopMonoCubicAtY(src, y, dst)) {
282 return;
283 }
285}
286
287// Modify pts[] in place so that it is clipped in Y to the clip rect
288static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
289
290 // are we partially above
291 if (pts[0].fY < clip.fTop) {
292 SkPoint tmp[7];
293 chop_mono_cubic_at_y(pts, clip.fTop, tmp);
294
295 /*
296 * For a large range in the points, we can do a poor job of chopping, such that the t
297 * we computed resulted in the lower cubic still being partly above the clip.
298 *
299 * If just the first or first 2 Y values are above the fTop, we can just smash them
300 * down. If the first 3 Ys are above fTop, we can't smash all 3, as that can really
301 * distort the cubic. In this case, we take the first output (tmp[3..6] and treat it as
302 * a guess, and re-chop against fTop. Then we fall through to checking if we need to
303 * smash the first 1 or 2 Y values.
304 */
305 if (tmp[3].fY < clip.fTop && tmp[4].fY < clip.fTop && tmp[5].fY < clip.fTop) {
306 SkPoint tmp2[4];
307 memcpy(tmp2, &tmp[3].fX, 4 * sizeof(SkPoint));
308 chop_mono_cubic_at_y(tmp2, clip.fTop, tmp);
309 }
310
311 // tmp[3, 4].fY should all be to the below clip.fTop.
312 // Since we can't trust the numerics of the chopper, we force those conditions now
313 tmp[3].fY = clip.fTop;
314 clamp_ge(tmp[4].fY, clip.fTop);
315
316 pts[0] = tmp[3];
317 pts[1] = tmp[4];
318 pts[2] = tmp[5];
319 }
320
321 // are we partially below
322 if (pts[3].fY > clip.fBottom) {
323 SkPoint tmp[7];
324 chop_mono_cubic_at_y(pts, clip.fBottom, tmp);
325 tmp[3].fY = clip.fBottom;
326 clamp_le(tmp[2].fY, clip.fBottom);
327
328 pts[1] = tmp[1];
329 pts[2] = tmp[2];
330 pts[3] = tmp[3];
331 }
332}
333
335 if (SkChopMonoCubicAtX(src, x, dst)) {
336 return;
337 }
339}
340
341// srcPts[] must be monotonic in X and Y
342void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
343 SkPoint pts[4];
344 bool reverse = sort_increasing_Y(pts, src, 4);
345
346 // are we completely above or below
347 if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
348 return;
349 }
350
351 // Now chop so that pts is contained within clip in Y
352 chop_cubic_in_Y(pts, clip);
353
354 if (pts[0].fX > pts[3].fX) {
355 using std::swap;
356 swap(pts[0], pts[3]);
357 swap(pts[1], pts[2]);
358 reverse = !reverse;
359 }
360
361 // Now chop in X has needed, and record the segments
362
363 if (pts[3].fX <= clip.fLeft) { // wholly to the left
364 this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
365 return;
366 }
367 if (pts[0].fX >= clip.fRight) { // wholly to the right
368 if (!this->canCullToTheRight()) {
369 this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
370 }
371 return;
372 }
373
374 // are we partially to the left
375 if (pts[0].fX < clip.fLeft) {
376 SkPoint tmp[7];
377 chop_mono_cubic_at_x(pts, clip.fLeft, tmp);
378 this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
379
380 // tmp[3, 4].fX should all be to the right of clip.fLeft.
381 // Since we can't trust the numerics of
382 // the chopper, we force those conditions now
383 tmp[3].fX = clip.fLeft;
384 clamp_ge(tmp[4].fX, clip.fLeft);
385
386 pts[0] = tmp[3];
387 pts[1] = tmp[4];
388 pts[2] = tmp[5];
389 }
390
391 // are we partially to the right
392 if (pts[3].fX > clip.fRight) {
393 SkPoint tmp[7];
394 chop_mono_cubic_at_x(pts, clip.fRight, tmp);
395 tmp[3].fX = clip.fRight;
396 clamp_le(tmp[2].fX, clip.fRight);
397
398 this->appendCubic(tmp, reverse);
399 this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
400 } else { // wholly inside the clip
401 this->appendCubic(pts, reverse);
402 }
403}
404
405static SkRect compute_cubic_bounds(const SkPoint pts[4]) {
406 SkRect r;
407 r.setBounds(pts, 4);
408 return r;
409}
410
412 // limit set as the largest float value for which we can still reliably compute things like
413 // - chopping at XY extrema
414 // - chopping at Y or X values for clipping
415 //
416 // Current value chosen just by experiment. Larger (and still succeeds) is always better.
417 //
418 const SkScalar limit = 1 << 22;
419 return r.fLeft < -limit || r.fTop < -limit || r.fRight > limit || r.fBottom > limit;
420}
421
422bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
423 fCurrPoint = fPoints;
424 fCurrVerb = fVerbs;
425
426 const SkRect bounds = compute_cubic_bounds(srcPts);
427 // check if we're clipped out vertically
428 if (bounds.fBottom > clip.fTop && bounds.fTop < clip.fBottom) {
430 // can't safely clip the cubic, so we give up and draw a line (which we can safely clip)
431 //
432 // If we rewrote chopcubicat*extrema and chopmonocubic using doubles, we could very
433 // likely always handle the cubic safely, but (it seems) at a big loss in speed, so
434 // we'd only want to take that alternate impl if needed. Perhaps a TODO to try it.
435 //
436 return this->clipLine(srcPts[0], srcPts[3], clip);
437 } else {
438 SkPoint monoY[10];
439 int countY = SkChopCubicAtYExtrema(srcPts, monoY);
440 for (int y = 0; y <= countY; y++) {
441 SkPoint monoX[10];
442 int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
443 for (int x = 0; x <= countX; x++) {
444 this->clipMonoCubic(&monoX[x * 3], clip);
445 SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
446 SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
447 }
448 }
449 }
450 }
451
452 *fCurrVerb = SkPath::kDone_Verb;
453 fCurrPoint = fPoints;
454 fCurrVerb = fVerbs;
455 return SkPath::kDone_Verb != fVerbs[0];
456}
457
458///////////////////////////////////////////////////////////////////////////////
459
460void SkEdgeClipper::appendLine(SkPoint p0, SkPoint p1) {
461 *fCurrVerb++ = SkPath::kLine_Verb;
462 fCurrPoint[0] = p0;
463 fCurrPoint[1] = p1;
464 fCurrPoint += 2;
465}
466
467void SkEdgeClipper::appendVLine(SkScalar x, SkScalar y0, SkScalar y1, bool reverse) {
468 *fCurrVerb++ = SkPath::kLine_Verb;
469
470 if (reverse) {
471 using std::swap;
472 swap(y0, y1);
473 }
474 fCurrPoint[0].set(x, y0);
475 fCurrPoint[1].set(x, y1);
476 fCurrPoint += 2;
477}
478
479void SkEdgeClipper::appendQuad(const SkPoint pts[3], bool reverse) {
480 *fCurrVerb++ = SkPath::kQuad_Verb;
481
482 if (reverse) {
483 fCurrPoint[0] = pts[2];
484 fCurrPoint[2] = pts[0];
485 } else {
486 fCurrPoint[0] = pts[0];
487 fCurrPoint[2] = pts[2];
488 }
489 fCurrPoint[1] = pts[1];
490 fCurrPoint += 3;
491}
492
493void SkEdgeClipper::appendCubic(const SkPoint pts[4], bool reverse) {
494 *fCurrVerb++ = SkPath::kCubic_Verb;
495
496 if (reverse) {
497 for (int i = 0; i < 4; i++) {
498 fCurrPoint[i] = pts[3 - i];
499 }
500 } else {
501 memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
502 }
503 fCurrPoint += 4;
504}
505
507 SkPath::Verb verb = *fCurrVerb;
508
509 switch (verb) {
511 memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
512 fCurrPoint += 2;
513 fCurrVerb += 1;
514 break;
516 memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
517 fCurrPoint += 3;
518 fCurrVerb += 1;
519 break;
521 memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
522 fCurrPoint += 4;
523 fCurrVerb += 1;
524 break;
526 break;
527 default:
528 SkDEBUGFAIL("unexpected verb in quadclippper2 iter");
529 break;
530 }
531 return verb;
532}
533
534///////////////////////////////////////////////////////////////////////////////
535
536#ifdef SK_DEBUG
537static void assert_monotonic(const SkScalar coord[], int count) {
538 if (coord[0] > coord[(count - 1) * 2]) {
539 for (int i = 1; i < count; i++) {
540 SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
541 }
542 } else if (coord[0] < coord[(count - 1) * 2]) {
543 for (int i = 1; i < count; i++) {
544 SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
545 }
546 } else {
547 for (int i = 1; i < count; i++) {
548 SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
549 }
550 }
551}
552
553void sk_assert_monotonic_y(const SkPoint pts[], int count) {
554 if (count > 1) {
555 assert_monotonic(&pts[0].fY, count);
556 }
557}
558
559void sk_assert_monotonic_x(const SkPoint pts[], int count) {
560 if (count > 1) {
561 assert_monotonic(&pts[0].fX, count);
562 }
563}
564#endif
565
566void SkEdgeClipper::ClipPath(const SkPath& path, const SkRect& clip, bool canCullToTheRight,
567 void (*consume)(SkEdgeClipper*, bool newCtr, void* ctx), void* ctx) {
568 SkASSERT(path.isFinite());
569
570 SkAutoConicToQuads quadder;
571 const SkScalar conicTol = SK_Scalar1 / 4;
572
573 SkPathEdgeIter iter(path);
575
576 while (auto e = iter.next()) {
577 switch (e.fEdge) {
579 if (clipper.clipLine(e.fPts[0], e.fPts[1], clip)) {
580 consume(&clipper, e.fIsNewContour, ctx);
581 }
582 break;
584 if (clipper.clipQuad(e.fPts, clip)) {
585 consume(&clipper, e.fIsNewContour, ctx);
586 }
587 break;
589 const SkPoint* quadPts = quadder.computeQuads(e.fPts, iter.conicWeight(), conicTol);
590 for (int i = 0; i < quadder.countQuads(); ++i) {
591 if (clipper.clipQuad(quadPts, clip)) {
592 consume(&clipper, e.fIsNewContour, ctx);
593 }
594 quadPts += 2;
595 }
596 } break;
598 if (clipper.clipCubic(e.fPts, clip)) {
599 consume(&clipper, e.fIsNewContour, ctx);
600 }
601 break;
602 }
603 }
604}
static int step(int x, SkScalar min, SkScalar max)
Definition: BlurTest.cpp:215
int count
Definition: FontMgrTest.cpp:50
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
static void clamp_le(SkScalar &value, SkScalar max)
static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar *t)
static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar target, SkScalar *t)
static void chop_mono_cubic_at_x(SkPoint src[4], SkScalar x, SkPoint dst[7])
static bool too_big_for_reliable_float_math(const SkRect &r)
static void chop_mono_cubic_at_y(SkPoint src[4], SkScalar y, SkPoint dst[7])
static bool quick_reject(const SkRect &bounds, const SkRect &clip)
static void chop_quad_in_Y(SkPoint pts[3], const SkRect &clip)
static void chop_cubic_in_Y(SkPoint pts[4], const SkRect &clip)
static SkScalar mono_cubic_closestT(const SkScalar src[], SkScalar x)
static void clamp_ge(SkScalar &value, SkScalar min)
static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count)
static SkRect compute_cubic_bounds(const SkPoint pts[4])
static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar *t)
#define sk_assert_monotonic_y(pts, count)
Definition: SkEdgeClipper.h:66
#define sk_assert_monotonic_x(pts, count)
Definition: SkEdgeClipper.h:65
void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
Definition: SkGeometry.cpp:175
int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5])
Definition: SkGeometry.cpp:307
int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10])
Definition: SkGeometry.cpp:698
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
Definition: SkGeometry.cpp:473
int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2])
Definition: SkGeometry.cpp:95
bool SkChopMonoCubicAtY(const SkPoint src[4], SkScalar y, SkPoint dst[7])
int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10])
Definition: SkGeometry.cpp:714
bool SkChopMonoCubicAtX(const SkPoint src[4], SkScalar x, SkPoint dst[7])
int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
Definition: SkGeometry.cpp:279
#define SK_INIT_TO_AVOID_WARNING
Definition: SkMacros.h:58
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define SK_ScalarMax
Definition: SkScalar.h:24
#define SK_Scalar1
Definition: SkScalar.h:18
#define SkScalarAbs(x)
Definition: SkScalar.h:39
const SkPoint * computeQuads(const SkConic &conic, SkScalar tol)
Definition: SkGeometry.h:524
int countQuads() const
Definition: SkGeometry.h:539
bool canCullToTheRight() const
Definition: SkEdgeClipper.h:32
static void ClipPath(const SkPath &path, const SkRect &clip, bool canCullToTheRight, void(*consume)(SkEdgeClipper *, bool newCtr, void *ctx), void *ctx)
SkPath::Verb next(SkPoint pts[])
bool clipCubic(const SkPoint pts[4], const SkRect &clip)
bool clipLine(SkPoint p0, SkPoint p1, const SkRect &clip)
bool clipQuad(const SkPoint pts[3], const SkRect &clip)
static int ClipLine(const SkPoint pts[2], const SkRect &clip, SkPoint lines[kMaxPoints], bool canCullToTheRight)
Result next()
Definition: SkPathPriv.h:485
SkScalar conicWeight() const
Definition: SkPathPriv.h:460
Definition: SkPath.h:59
@ kDone_Verb
Definition: SkPath.h:1472
@ kCubic_Verb
Definition: SkPath.h:1470
@ kQuad_Verb
Definition: SkPath.h:1468
@ kLine_Verb
Definition: SkPath.h:1467
float SkScalar
Definition: extension.cpp:12
uint8_t value
uint32_t * target
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
#define B
double y
double x
Optional< SkRect > bounds
Definition: SkRecords.h:189
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
dst
Definition: cp.py:12
float fX
x-axis value
Definition: SkPoint_impl.h:164
void set(float x, float y)
Definition: SkPoint_impl.h:200
float fY
y-axis value
Definition: SkPoint_impl.h:165
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
void setBounds(const SkPoint pts[], int count)
Definition: SkRect.h:881
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15