23#define kMaxTValue 0x3FFFFFFF
29 return t * kMaxTReciprocal;
32static_assert(0.0f ==
tValue2Scalar( 0),
"Lower limit should be exact.");
35SkScalar SkContourMeasure::Segment::getScalarT()
const {
45 if (startT == stopT) {
46 if (!dst->isEmpty()) {
70 dst->quadTo(pts[1], pts[2]);
73 dst->quadTo(tmp0[1], tmp0[2]);
78 dst->quadTo(tmp0[3], tmp0[4]);
80 SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT));
81 dst->quadTo(tmp1[1], tmp1[2]);
86 SkConic conic(pts[0], pts[2], pts[3], pts[1].fX);
90 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW);
93 if (conic.chopAt(stopT, tmp)) {
94 dst->conicTo(tmp[0].
fPts[1], tmp[0].
fPts[2], tmp[0].fW);
100 if (conic.chopAt(startT, tmp)) {
101 dst->conicTo(tmp[1].
fPts[1], tmp[1].
fPts[2], tmp[1].fW);
105 conic.chopAt(startT, stopT, &tmp);
106 dst->conicTo(tmp.
fPts[1], tmp.
fPts[2], tmp.
fW);
113 dst->cubicTo(pts[1], pts[2], pts[3]);
116 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
121 dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
123 SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT));
124 dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
143#define CHEAP_DIST_LIMIT (SK_Scalar1/2)
154 return dist > tolerance;
159 SkPoint midEnds = firstPt + lastPt;
163 return dist > tolerance;
170 return dist > tolerance;
193 , fForceClosed(forceClosed) {}
211 int mint,
int maxt,
unsigned ptIndex,
int recursionDepth = 0);
213 int mint,
const SkPoint& minPt,
214 int maxt,
const SkPoint& maxPt,
215 unsigned ptIndex,
int recursionDepth = 0);
217 int mint,
int maxt,
unsigned ptIndex,
int recursionDepth = 0);
221 int mint,
int maxt,
unsigned ptIndex,
222 int recursionDepth) {
226 int halft = (mint + maxt) >> 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);
236 if (distance > prevD) {
238 SkContourMeasure::Segment* seg = fSegments.
append();
240 seg->fPtIndex = ptIndex;
249 int mint,
const SkPoint& minPt,
250 int maxt,
const SkPoint& maxPt,
251 unsigned ptIndex,
int recursionDepth) {
252 int halft = (mint + maxt) >> 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);
269 if (distance > prevD) {
271 SkContourMeasure::Segment* seg = fSegments.
append();
273 seg->fPtIndex = ptIndex;
282 int mint,
int maxt,
unsigned ptIndex,
283 int recursionDepth) {
288 int halft = (mint + maxt) >> 1;
293 ptIndex, recursionDepth);
295 ptIndex, recursionDepth);
300 if (distance > prevD) {
302 SkContourMeasure::Segment* seg = fSegments.
append();
304 seg->fPtIndex = ptIndex;
318 if (distance > prevD) {
320 SkContourMeasure::Segment* seg = fSegments.
append();
322 seg->fPtIndex = ptIndex;
330void SkContourMeasureIter::Impl::validate()
const {
331 const SkContourMeasure::Segment* seg = fSegments.
begin();
332 const SkContourMeasure::Segment* stop = fSegments.
end();
333 unsigned ptIndex = 0;
336 int maxChecks = 10000000;
338 SkASSERT(seg->fDistance > distance);
342 const SkContourMeasure::Segment*
s = seg;
343 while (
s < stop - 1 &&
s[0].fPtIndex ==
s[1].fPtIndex && --maxChecks > 0) {
350 ptIndex = seg->fPtIndex;
359 bool haveSeenClose = fForceClosed;
360 bool haveSeenMoveTo =
false;
375 auto [verb, pts,
w] = *
fIter;
384 haveSeenMoveTo =
true;
390 distance = this->compute_line_seg(pts[0], pts[1], distance, ptIndex);
391 if (distance > prevD) {
392 fPts.append(1, pts + 1);
400 distance = this->compute_quad_segs(pts, distance, 0,
kMaxTValue, ptIndex);
401 if (distance > prevD) {
402 fPts.append(2, pts + 1);
411 distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0],
413 if (distance > prevD) {
417 fPts.append()->
set(conic.fW, 0);
418 fPts.append(2, pts + 1);
427 if (distance > prevD) {
428 fPts.append(3, pts + 1);
434 haveSeenClose =
true;
443 if (fSegments.
empty()) {
450 distance = this->compute_line_seg(
fPts[ptIndex], firstPt, distance, ptIndex);
451 if (distance > prevD) {
452 *
fPts.append() = firstPt;
470 tangent->
setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
505 this->
reset(path, forceClosed, resScale);
516 if (path.isFinite()) {
517 fImpl = std::make_unique<Impl>(path, forceClosed, resScale);
527 while (fImpl->hasNextSegments()) {
528 auto cm = fImpl->buildSegments();
539 : fSegments(
std::move(segs))
542 , fIsClosed(isClosed)
545template <
typename T,
typename K>
555 unsigned hi =
count - 1;
558 unsigned mid = (hi + lo) >> 1;
559 if (
base[mid].fDistance <
key) {
566 if (
base[hi].fDistance <
key) {
569 }
else if (
key <
base[hi].fDistance) {
575const SkContourMeasure::Segment* SkContourMeasure::distanceToSegment(
SkScalar distance,
580 const Segment* seg = fSegments.
begin();
581 int count = fSegments.size();
585 index ^= (index >> 31);
592 startD = seg[-1].fDistance;
593 if (seg[-1].fPtIndex == seg->fPtIndex) {
594 SkASSERT(seg[-1].fType == seg->fType);
595 startT = seg[-1].getScalarT();
599 SkASSERT(seg->getScalarT() > startT);
603 *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD);
618 }
else if (distance >
length) {
623 const Segment* seg = this->distanceToSegment(distance, &t);
628 SkASSERT((
unsigned)seg->fPtIndex < (
unsigned)
fPts.size());
637 if (this->
getPosTan(distance, &position, &tangent)) {
640 matrix->setSinCos(tangent.
fY, tangent.
fX, 0, 0);
645 matrix->postTranslate(position.
fX, position.
fY);
654 bool startWithMoveTo)
const {
665 if (!(startD <= stopD)) {
668 if (fSegments.
empty()) {
674 const Segment* seg = this->distanceToSegment(startD, &startT);
678 const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
683 if (startWithMoveTo) {
688 if (seg->fPtIndex == stopSeg->fPtIndex) {
693 seg = SkContourMeasure::Segment::Next(seg);
695 }
while (seg->fPtIndex < stopSeg->fPtIndex);
std::unique_ptr< SkLatticeIter > fIter
#define SkAssertResult(cond)
#define SkDEBUGFAIL(message)
#define SK_ABORT(message,...)
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)
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)
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)
@ 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.
static SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t)
static int compute_cubic_segs(const SkPoint pts[4])
Impl(const SkPath &path, bool forceClosed, SkScalar resScale)
SkContourMeasure * buildSegments()
bool hasNextSegments() const
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
@ kGetPosition_MatrixFlag
SkPath::RangeIter RangeIter
static const char * begin(const StringSlice &s)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
FlutterSemanticsFlag flags
void evalAt(SkScalar t, SkPoint *pos, SkVector *tangent=nullptr) const
bool setNormalize(float x, float y)
void set(float x, float y)
static float Distance(const SkPoint &a, const SkPoint &b)