Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
153 SkScalar dist = std::max(SkScalarAbs(dx), SkScalarAbs(dy));
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
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
607bool SkContourMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) const {
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) {
619 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
m reset()
int count
SkPoint pos
std::unique_ptr< SkLatticeIter > fIter
#define SkAssertResult(cond)
Definition SkAssert.h:123
#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
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static bool SkIsFinite(T x, Pack... values)
static bool SkIsNaN(T x)
static constexpr float sk_ieee_float_divide(float numer, float denom)
void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7])
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint *loc, SkVector *tangent, SkVector *curvature)
void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5])
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint *pt, SkVector *tangent)
@ 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])
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
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
glong glong end
size_t length
double y
double x
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
Definition ref_ptr.h:256
SkScalar w
#define T
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
bool setNormalize(float x, float y)
Definition SkPoint.cpp:26
bool isFinite() const
void set(float x, float y)
static float Distance(const SkPoint &a, const SkPoint &b)
float fY
y-axis value
bool normalize()
Definition SkPoint.cpp:22