Flutter Engine
The Flutter Engine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
SkContourMeasure.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google Inc.
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 "include/core/SkPath.h"
16#include "src/core/SkGeometry.h"
18#include "src/core/SkPathPriv.h"
19
20#include <algorithm>
21#include <utility>
22
23#define kMaxTValue 0x3FFFFFFF
24
25constexpr static inline SkScalar tValue2Scalar(int t) {
26 SkASSERT((unsigned)t <= kMaxTValue);
27 // 1/kMaxTValue can't be represented as a float, but it's close and the limits work fine.
28 const SkScalar kMaxTReciprocal = 1.0f / (SkScalar)kMaxTValue;
29 return t * kMaxTReciprocal;
30}
31
32static_assert(0.0f == tValue2Scalar( 0), "Lower limit should be exact.");
33static_assert(1.0f == tValue2Scalar(kMaxTValue), "Upper limit should be exact.");
34
35SkScalar SkContourMeasure::Segment::getScalarT() const {
36 return tValue2Scalar(fTValue);
37}
38
39void SkContourMeasure_segTo(const SkPoint pts[], unsigned segType,
40 SkScalar startT, SkScalar stopT, SkPath* dst) {
41 SkASSERT(startT >= 0 && startT <= SK_Scalar1);
42 SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
43 SkASSERT(startT <= stopT);
44
45 if (startT == stopT) {
46 if (!dst->isEmpty()) {
47 /* if the dash as a zero-length on segment, add a corresponding zero-length line.
48 The stroke code will add end caps to zero length lines as appropriate */
49 SkPoint lastPt;
50 SkAssertResult(dst->getLastPt(&lastPt));
51 dst->lineTo(lastPt);
52 }
53 return;
54 }
55
56 SkPoint tmp0[7], tmp1[7];
57
58 switch (segType) {
59 case kLine_SegType:
60 if (SK_Scalar1 == stopT) {
61 dst->lineTo(pts[1]);
62 } else {
63 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
64 SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
65 }
66 break;
67 case kQuad_SegType:
68 if (0 == startT) {
69 if (SK_Scalar1 == stopT) {
70 dst->quadTo(pts[1], pts[2]);
71 } else {
72 SkChopQuadAt(pts, tmp0, stopT);
73 dst->quadTo(tmp0[1], tmp0[2]);
74 }
75 } else {
76 SkChopQuadAt(pts, tmp0, startT);
77 if (SK_Scalar1 == stopT) {
78 dst->quadTo(tmp0[3], tmp0[4]);
79 } else {
80 SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT));
81 dst->quadTo(tmp1[1], tmp1[2]);
82 }
83 }
84 break;
85 case kConic_SegType: {
86 SkConic conic(pts[0], pts[2], pts[3], pts[1].fX);
87
88 if (0 == startT) {
89 if (SK_Scalar1 == stopT) {
90 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW);
91 } else {
92 SkConic tmp[2];
93 if (conic.chopAt(stopT, tmp)) {
94 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW);
95 }
96 }
97 } else {
98 if (SK_Scalar1 == stopT) {
99 SkConic tmp[2];
100 if (conic.chopAt(startT, tmp)) {
101 dst->conicTo(tmp[1].fPts[1], tmp[1].fPts[2], tmp[1].fW);
102 }
103 } else {
104 SkConic tmp;
105 conic.chopAt(startT, stopT, &tmp);
106 dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW);
107 }
108 }
109 } break;
110 case kCubic_SegType:
111 if (0 == startT) {
112 if (SK_Scalar1 == stopT) {
113 dst->cubicTo(pts[1], pts[2], pts[3]);
114 } else {
115 SkChopCubicAt(pts, tmp0, stopT);
116 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
117 }
118 } else {
119 SkChopCubicAt(pts, tmp0, startT);
120 if (SK_Scalar1 == stopT) {
121 dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
122 } else {
123 SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT));
124 dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
125 }
126 }
127 break;
128 default:
129 SK_ABORT("unknown segType");
130 }
131}
132
133///////////////////////////////////////////////////////////////////////////////
134
135static inline int tspan_big_enough(int tspan) {
136 SkASSERT((unsigned)tspan <= kMaxTValue);
137 return tspan >> 10;
138}
139
140// can't use tangents, since we need [0..1..................2] to be seen
141// as definitely not a line (it is when drawn, but not parametrically)
142// so we compare midpoints
143#define CHEAP_DIST_LIMIT (SK_Scalar1/2) // just made this value up
144
145static bool quad_too_curvy(const SkPoint pts[3], SkScalar tolerance) {
146 // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
147 // diff = -a/4 + b/2 - c/4
148 SkScalar dx = SkScalarHalf(pts[1].fX) -
149 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
150 SkScalar dy = SkScalarHalf(pts[1].fY) -
151 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
152
154 return dist > tolerance;
155}
156
157static bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt,
158 const SkPoint& lastPt, SkScalar tolerance) {
159 SkPoint midEnds = firstPt + lastPt;
160 midEnds *= 0.5f;
161 SkVector dxy = midTPt - midEnds;
162 SkScalar dist = std::max(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY));
163 return dist > tolerance;
164}
165
167 SkScalar tolerance) {
168 SkScalar dist = std::max(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
169 // just made up the 1/2
170 return dist > tolerance;
171}
172
173static bool cubic_too_curvy(const SkPoint pts[4], SkScalar tolerance) {
174 return cheap_dist_exceeds_limit(pts[1],
175 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
176 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3), tolerance)
177 ||
179 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
180 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3), tolerance);
181}
182
183// puts a cap on the total size of our output, since the client can pass in
184// arbitrarily large values for resScale.
185constexpr int kMaxRecursionDepth = 8;
186
188public:
189 Impl(const SkPath& path, bool forceClosed, SkScalar resScale)
190 : fPath(path)
191 , fIter(SkPathPriv::Iterate(fPath).begin())
192 , fTolerance(CHEAP_DIST_LIMIT * sk_ieee_float_divide(1.0f, resScale))
193 , fForceClosed(forceClosed) {}
194
195 bool hasNextSegments() const { return fIter != SkPathPriv::Iterate(fPath).end(); }
197
198private:
199 SkPath fPath;
201 SkScalar fTolerance;
202 bool fForceClosed;
203
204 // temporary
206 SkTDArray<SkPoint> fPts; // Points used to define the segments
207
208 SkDEBUGCODE(void validate() const;)
209 SkScalar compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance, unsigned ptIndex);
210 SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance,
211 int mint, int maxt, unsigned ptIndex, int recursionDepth = 0);
212 SkScalar compute_conic_segs(const SkConic& conic, SkScalar distance,
213 int mint, const SkPoint& minPt,
214 int maxt, const SkPoint& maxPt,
215 unsigned ptIndex, int recursionDepth = 0);
216 SkScalar compute_cubic_segs(const SkPoint pts[4], SkScalar distance,
217 int mint, int maxt, unsigned ptIndex, int recursionDepth = 0);
218};
219
220SkScalar SkContourMeasureIter::Impl::compute_quad_segs(const SkPoint pts[3], SkScalar distance,
221 int mint, int maxt, unsigned ptIndex,
222 int recursionDepth) {
223 if (recursionDepth < kMaxRecursionDepth &&
224 tspan_big_enough(maxt - mint) && quad_too_curvy(pts, fTolerance)) {
225 SkPoint tmp[5];
226 int halft = (mint + maxt) >> 1;
227
228 SkChopQuadAtHalf(pts, tmp);
229 recursionDepth += 1;
230 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex, recursionDepth);
231 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex, recursionDepth);
232 } else {
233 SkScalar d = SkPoint::Distance(pts[0], pts[2]);
234 SkScalar prevD = distance;
235 distance += d;
236 if (distance > prevD) {
237 SkASSERT(ptIndex < (unsigned)fPts.size());
238 SkContourMeasure::Segment* seg = fSegments.append();
239 seg->fDistance = distance;
240 seg->fPtIndex = ptIndex;
241 seg->fType = kQuad_SegType;
242 seg->fTValue = maxt;
243 }
244 }
245 return distance;
246}
247
248SkScalar SkContourMeasureIter::Impl::compute_conic_segs(const SkConic& conic, SkScalar distance,
249 int mint, const SkPoint& minPt,
250 int maxt, const SkPoint& maxPt,
251 unsigned ptIndex, int recursionDepth) {
252 int halft = (mint + maxt) >> 1;
253 SkPoint halfPt = conic.evalAt(tValue2Scalar(halft));
254 if (!halfPt.isFinite()) {
255 return distance;
256 }
257 if (recursionDepth < kMaxRecursionDepth &&
258 tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt, fTolerance))
259 {
260 recursionDepth += 1;
261 distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt,
262 ptIndex, recursionDepth);
263 distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt,
264 ptIndex, recursionDepth);
265 } else {
266 SkScalar d = SkPoint::Distance(minPt, maxPt);
267 SkScalar prevD = distance;
268 distance += d;
269 if (distance > prevD) {
270 SkASSERT(ptIndex < (unsigned)fPts.size());
271 SkContourMeasure::Segment* seg = fSegments.append();
272 seg->fDistance = distance;
273 seg->fPtIndex = ptIndex;
274 seg->fType = kConic_SegType;
275 seg->fTValue = maxt;
276 }
277 }
278 return distance;
279}
280
281SkScalar SkContourMeasureIter::Impl::compute_cubic_segs(const SkPoint pts[4], SkScalar distance,
282 int mint, int maxt, unsigned ptIndex,
283 int recursionDepth) {
284 if (recursionDepth < kMaxRecursionDepth &&
285 tspan_big_enough(maxt - mint) && cubic_too_curvy(pts, fTolerance))
286 {
287 SkPoint tmp[7];
288 int halft = (mint + maxt) >> 1;
289
290 SkChopCubicAtHalf(pts, tmp);
291 recursionDepth += 1;
292 distance = this->compute_cubic_segs(tmp, distance, mint, halft,
293 ptIndex, recursionDepth);
294 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt,
295 ptIndex, recursionDepth);
296 } else {
297 SkScalar d = SkPoint::Distance(pts[0], pts[3]);
298 SkScalar prevD = distance;
299 distance += d;
300 if (distance > prevD) {
301 SkASSERT(ptIndex < (unsigned)fPts.size());
302 SkContourMeasure::Segment* seg = fSegments.append();
303 seg->fDistance = distance;
304 seg->fPtIndex = ptIndex;
305 seg->fType = kCubic_SegType;
306 seg->fTValue = maxt;
307 }
308 }
309 return distance;
310}
311
312SkScalar SkContourMeasureIter::Impl::compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance,
313 unsigned ptIndex) {
314 SkScalar d = SkPoint::Distance(p0, p1);
315 SkASSERT(d >= 0);
316 SkScalar prevD = distance;
317 distance += d;
318 if (distance > prevD) {
319 SkASSERT((unsigned)ptIndex < (unsigned)fPts.size());
320 SkContourMeasure::Segment* seg = fSegments.append();
321 seg->fDistance = distance;
322 seg->fPtIndex = ptIndex;
323 seg->fType = kLine_SegType;
324 seg->fTValue = kMaxTValue;
325 }
326 return distance;
327}
328
329#ifdef SK_DEBUG
330void SkContourMeasureIter::Impl::validate() const {
331 const SkContourMeasure::Segment* seg = fSegments.begin();
332 const SkContourMeasure::Segment* stop = fSegments.end();
333 unsigned ptIndex = 0;
334 SkScalar distance = 0;
335 // limit the loop to a reasonable number; pathological cases can run for minutes
336 int maxChecks = 10000000; // set to INT_MAX to defeat the check
337 while (seg < stop) {
338 SkASSERT(seg->fDistance > distance);
339 SkASSERT(seg->fPtIndex >= ptIndex);
340 SkASSERT(seg->fTValue > 0);
341
342 const SkContourMeasure::Segment* s = seg;
343 while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) {
344 SkASSERT(s[0].fType == s[1].fType);
345 SkASSERT(s[0].fTValue < s[1].fTValue);
346 s += 1;
347 }
348
349 distance = seg->fDistance;
350 ptIndex = seg->fPtIndex;
351 seg += 1;
352 }
353}
354#endif
355
357 int ptIndex = -1;
358 SkScalar distance = 0;
359 bool haveSeenClose = fForceClosed;
360 bool haveSeenMoveTo = false;
361
362 /* Note:
363 * as we accumulate distance, we have to check that the result of +=
364 * actually made it larger, since a very small delta might be > 0, but
365 * still have no effect on distance (if distance >>> delta).
366 *
367 * We do this check below, and in compute_quad_segs and compute_cubic_segs
368 */
369
370 fSegments.reset();
371 fPts.reset();
372
374 for (; fIter != end; ++fIter) {
375 auto [verb, pts, w] = *fIter;
376 if (haveSeenMoveTo && verb == SkPathVerb::kMove) {
377 break;
378 }
379 switch (verb) {
381 ptIndex += 1;
382 fPts.append(1, pts);
383 SkASSERT(!haveSeenMoveTo);
384 haveSeenMoveTo = true;
385 break;
386
387 case SkPathVerb::kLine: {
388 SkASSERT(haveSeenMoveTo);
389 SkScalar prevD = distance;
390 distance = this->compute_line_seg(pts[0], pts[1], distance, ptIndex);
391 if (distance > prevD) {
392 fPts.append(1, pts + 1);
393 ptIndex++;
394 }
395 } break;
396
397 case SkPathVerb::kQuad: {
398 SkASSERT(haveSeenMoveTo);
399 SkScalar prevD = distance;
400 distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex);
401 if (distance > prevD) {
402 fPts.append(2, pts + 1);
403 ptIndex += 2;
404 }
405 } break;
406
407 case SkPathVerb::kConic: {
408 SkASSERT(haveSeenMoveTo);
409 const SkConic conic(pts, *w);
410 SkScalar prevD = distance;
411 distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0],
412 kMaxTValue, conic.fPts[2], ptIndex);
413 if (distance > prevD) {
414 // we store the conic weight in our next point, followed by the last 2 pts
415 // thus to reconstitue a conic, you'd need to say
416 // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX)
417 fPts.append()->set(conic.fW, 0);
418 fPts.append(2, pts + 1);
419 ptIndex += 3;
420 }
421 } break;
422
423 case SkPathVerb::kCubic: {
424 SkASSERT(haveSeenMoveTo);
425 SkScalar prevD = distance;
426 distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex);
427 if (distance > prevD) {
428 fPts.append(3, pts + 1);
429 ptIndex += 3;
430 }
431 } break;
432
434 haveSeenClose = true;
435 break;
436 }
437
438 }
439
440 if (!SkIsFinite(distance)) {
441 return nullptr;
442 }
443 if (fSegments.empty()) {
444 return nullptr;
445 }
446
447 if (haveSeenClose) {
448 SkScalar prevD = distance;
449 SkPoint firstPt = fPts[0];
450 distance = this->compute_line_seg(fPts[ptIndex], firstPt, distance, ptIndex);
451 if (distance > prevD) {
452 *fPts.append() = firstPt;
453 }
454 }
455
456 SkDEBUGCODE(this->validate();)
457
458 return new SkContourMeasure(std::move(fSegments), std::move(fPts), distance, haveSeenClose);
459}
460
461static void compute_pos_tan(const SkPoint pts[], unsigned segType,
462 SkScalar t, SkPoint* pos, SkVector* tangent) {
463 switch (segType) {
464 case kLine_SegType:
465 if (pos) {
466 pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
467 SkScalarInterp(pts[0].fY, pts[1].fY, t));
468 }
469 if (tangent) {
470 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
471 }
472 break;
473 case kQuad_SegType:
474 SkEvalQuadAt(pts, t, pos, tangent);
475 if (tangent) {
476 tangent->normalize();
477 }
478 break;
479 case kConic_SegType: {
480 SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent);
481 if (tangent) {
482 tangent->normalize();
483 }
484 } break;
485 case kCubic_SegType:
486 SkEvalCubicAt(pts, t, pos, tangent, nullptr);
487 if (tangent) {
488 tangent->normalize();
489 }
490 break;
491 default:
492 SkDEBUGFAIL("unknown segType");
493 }
494}
495
496
497////////////////////////////////////////////////////////////////////////////////
498////////////////////////////////////////////////////////////////////////////////
499
501}
502
504 SkScalar resScale) {
505 this->reset(path, forceClosed, resScale);
506}
507
509
512
513/** Assign a new path, or null to have none.
514*/
515void SkContourMeasureIter::reset(const SkPath& path, bool forceClosed, SkScalar resScale) {
516 if (path.isFinite()) {
517 fImpl = std::make_unique<Impl>(path, forceClosed, resScale);
518 } else {
519 fImpl.reset();
520 }
521}
522
524 if (!fImpl) {
525 return nullptr;
526 }
527 while (fImpl->hasNextSegments()) {
528 auto cm = fImpl->buildSegments();
529 if (cm) {
530 return sk_sp<SkContourMeasure>(cm);
531 }
532 }
533 return nullptr;
534}
535
536///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
537
538SkContourMeasure::SkContourMeasure(SkTDArray<Segment>&& segs, SkTDArray<SkPoint>&& pts, SkScalar length, bool isClosed)
539 : fSegments(std::move(segs))
540 , fPts(std::move(pts))
541 , fLength(length)
542 , fIsClosed(isClosed)
543 {}
544
545template <typename T, typename K>
546int SkTKSearch(const T base[], int count, const K& key) {
547 SkASSERT(count >= 0);
548 if (count <= 0) {
549 return ~0;
550 }
551
552 SkASSERT(base != nullptr); // base may be nullptr if count is zero
553
554 unsigned lo = 0;
555 unsigned hi = count - 1;
556
557 while (lo < hi) {
558 unsigned mid = (hi + lo) >> 1;
559 if (base[mid].fDistance < key) {
560 lo = mid + 1;
561 } else {
562 hi = mid;
563 }
564 }
565
566 if (base[hi].fDistance < key) {
567 hi += 1;
568 hi = ~hi;
569 } else if (key < base[hi].fDistance) {
570 hi = ~hi;
571 }
572 return hi;
573}
574
575const SkContourMeasure::Segment* SkContourMeasure::distanceToSegment( SkScalar distance,
576 SkScalar* t) const {
577 SkDEBUGCODE(SkScalar length = ) this->length();
578 SkASSERT(distance >= 0 && distance <= length);
579
580 const Segment* seg = fSegments.begin();
581 int count = fSegments.size();
582
583 int index = SkTKSearch<Segment, SkScalar>(seg, count, distance);
584 // don't care if we hit an exact match or not, so we xor index if it is negative
585 index ^= (index >> 31);
586 seg = &seg[index];
587
588 // now interpolate t-values with the prev segment (if possible)
589 SkScalar startT = 0, startD = 0;
590 // check if the prev segment is legal, and references the same set of points
591 if (index > 0) {
592 startD = seg[-1].fDistance;
593 if (seg[-1].fPtIndex == seg->fPtIndex) {
594 SkASSERT(seg[-1].fType == seg->fType);
595 startT = seg[-1].getScalarT();
596 }
597 }
598
599 SkASSERT(seg->getScalarT() > startT);
600 SkASSERT(distance >= startD);
601 SkASSERT(seg->fDistance > startD);
602
603 *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD);
604 return seg;
605}
606
608 if (SkIsNaN(distance)) {
609 return false;
610 }
611
612 const SkScalar length = this->length();
613 SkASSERT(length > 0 && !fSegments.empty());
614
615 // pin the distance to a legal range
616 if (distance < 0) {
617 distance = 0;
618 } else if (distance > length) {
620 }
621
622 SkScalar t;
623 const Segment* seg = this->distanceToSegment(distance, &t);
624 if (SkIsNaN(t)) {
625 return false;
626 }
627
628 SkASSERT((unsigned)seg->fPtIndex < (unsigned)fPts.size());
629 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
630 return true;
631}
632
634 SkPoint position;
635 SkVector tangent;
636
637 if (this->getPosTan(distance, &position, &tangent)) {
638 if (matrix) {
640 matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
641 } else {
642 matrix->reset();
643 }
645 matrix->postTranslate(position.fX, position.fY);
646 }
647 }
648 return true;
649 }
650 return false;
651}
652
654 bool startWithMoveTo) const {
655 SkASSERT(dst);
656
657 SkScalar length = this->length(); // ensure we have built our segments
658
659 if (startD < 0) {
660 startD = 0;
661 }
662 if (stopD > length) {
663 stopD = length;
664 }
665 if (!(startD <= stopD)) { // catch NaN values as well
666 return false;
667 }
668 if (fSegments.empty()) {
669 return false;
670 }
671
672 SkPoint p;
673 SkScalar startT, stopT;
674 const Segment* seg = this->distanceToSegment(startD, &startT);
675 if (!SkIsFinite(startT)) {
676 return false;
677 }
678 const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
679 if (!SkIsFinite(stopT)) {
680 return false;
681 }
682 SkASSERT(seg <= stopSeg);
683 if (startWithMoveTo) {
684 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr);
685 dst->moveTo(p);
686 }
687
688 if (seg->fPtIndex == stopSeg->fPtIndex) {
689 SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
690 } else {
691 do {
692 SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
693 seg = SkContourMeasure::Segment::Next(seg);
694 startT = 0;
695 } while (seg->fPtIndex < stopSeg->fPtIndex);
696 SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
697 }
698
699 return true;
700}
SkPoint fPts[2]
SkPath fPath
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
int count
Definition: FontMgrTest.cpp:50
SkPoint pos
std::unique_ptr< SkLatticeIter > fIter
Definition: LatticeOp.cpp:380
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT(cond)
Definition: SkAssert.h:116
static int tspan_big_enough(int tspan)
constexpr int kMaxRecursionDepth
static bool cubic_too_curvy(const SkPoint pts[4], SkScalar tolerance)
void SkContourMeasure_segTo(const SkPoint pts[], unsigned segType, SkScalar startT, SkScalar stopT, SkPath *dst)
int SkTKSearch(const T base[], int count, const K &key)
static constexpr SkScalar tValue2Scalar(int t)
static bool conic_too_curvy(const SkPoint &firstPt, const SkPoint &midTPt, const SkPoint &lastPt, SkScalar tolerance)
static bool cheap_dist_exceeds_limit(const SkPoint &pt, SkScalar x, SkScalar y, SkScalar tolerance)
static bool quad_too_curvy(const SkPoint pts[3], SkScalar tolerance)
static void compute_pos_tan(const SkPoint pts[], unsigned segType, SkScalar t, SkPoint *pos, SkVector *tangent)
#define kMaxTValue
#define CHEAP_DIST_LIMIT
static constexpr bool SkIsNaN(T x)
static bool SkIsFinite(T x, Pack... values)
static constexpr float sk_ieee_float_divide(float numer, float denom)
void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
Definition: SkGeometry.cpp:175
void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7])
Definition: SkGeometry.cpp:575
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
Definition: SkGeometry.cpp:473
void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint *loc, SkVector *tangent, SkVector *curvature)
Definition: SkGeometry.cpp:418
void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5])
Definition: SkGeometry.cpp:193
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint *pt, SkVector *tangent)
Definition: SkGeometry.cpp:132
@ kConic_SegType
@ kCubic_SegType
@ kLine_SegType
@ kQuad_SegType
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kConic
SkPath::RawIter returns 3 points + 1 weight.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
#define SK_Scalar1
Definition: SkScalar.h:18
#define SkScalarHalf(a)
Definition: SkScalar.h:75
static SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t)
Definition: SkScalar.h:131
#define SkScalarAbs(x)
Definition: SkScalar.h:39
static int compute_cubic_segs(const SkPoint pts[4])
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
Impl(const SkPath &path, bool forceClosed, SkScalar resScale)
SkContourMeasure * buildSegments()
void reset(const SkPath &path, bool forceClosed, SkScalar resScale=1)
SkContourMeasureIter & operator=(SkContourMeasureIter &&)
sk_sp< SkContourMeasure > next()
bool getMatrix(SkScalar distance, SkMatrix *matrix, MatrixFlags flags=kGetPosAndTan_MatrixFlag) const
bool getSegment(SkScalar startD, SkScalar stopD, SkPath *dst, bool startWithMoveTo) const
bool getPosTan(SkScalar distance, SkPoint *position, SkVector *tangent) const
SkScalar length() const
SkPath::RangeIter RangeIter
Definition: SkPathPriv.h:164
Definition: SkPath.h:59
T * end()
Definition: SkTDArray.h:152
bool empty() const
Definition: SkTDArray.h:135
void reset()
Definition: SkTDArray.h:171
T * begin()
Definition: SkTDArray.h:150
T * append()
Definition: SkTDArray.h:191
static const int K
Definition: daa.cpp:21
static const char * begin(const StringSlice &s)
Definition: editor.cpp:252
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
float SkScalar
Definition: extension.cpp:12
struct MyStruct s
FlutterSemanticsFlag flags
if(end==-1)
glong glong end
static float max(float r, float g, float b)
Definition: hsl.cpp:49
size_t length
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:287
Definition: ref_ptr.h:256
SkScalar w
#define T
Definition: precompiler.cc:65
SkScalar fW
Definition: SkGeometry.h:337
void evalAt(SkScalar t, SkPoint *pos, SkVector *tangent=nullptr) const
SkPoint fPts[3]
Definition: SkGeometry.h:336
SkPath::RangeIter end()
Definition: SkPathPriv.h:187
float fX
x-axis value
Definition: SkPoint_impl.h:164
bool setNormalize(float x, float y)
Definition: SkPoint.cpp:26
bool isFinite() const
Definition: SkPoint_impl.h:412
void set(float x, float y)
Definition: SkPoint_impl.h:200
static float Distance(const SkPoint &a, const SkPoint &b)
Definition: SkPoint_impl.h:508
float fY
y-axis value
Definition: SkPoint_impl.h:165
bool normalize()
Definition: SkPoint.cpp:22