1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkContourMeasure.h" 9cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 10cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 11cb93a386Sopenharmony_ci#include "src/core/SkPathMeasurePriv.h" 12cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 13cb93a386Sopenharmony_ci#include "src/core/SkTSearch.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci#define kMaxTValue 0x3FFFFFFF 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ciconstexpr static inline SkScalar tValue2Scalar(int t) { 18cb93a386Sopenharmony_ci SkASSERT((unsigned)t <= kMaxTValue); 19cb93a386Sopenharmony_ci // 1/kMaxTValue can't be represented as a float, but it's close and the limits work fine. 20cb93a386Sopenharmony_ci const SkScalar kMaxTReciprocal = 1.0f / (SkScalar)kMaxTValue; 21cb93a386Sopenharmony_ci return t * kMaxTReciprocal; 22cb93a386Sopenharmony_ci} 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_cistatic_assert(0.0f == tValue2Scalar( 0), "Lower limit should be exact."); 25cb93a386Sopenharmony_cistatic_assert(1.0f == tValue2Scalar(kMaxTValue), "Upper limit should be exact."); 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ciSkScalar SkContourMeasure::Segment::getScalarT() const { 28cb93a386Sopenharmony_ci return tValue2Scalar(fTValue); 29cb93a386Sopenharmony_ci} 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_civoid SkContourMeasure_segTo(const SkPoint pts[], unsigned segType, 32cb93a386Sopenharmony_ci SkScalar startT, SkScalar stopT, SkPath* dst) { 33cb93a386Sopenharmony_ci SkASSERT(startT >= 0 && startT <= SK_Scalar1); 34cb93a386Sopenharmony_ci SkASSERT(stopT >= 0 && stopT <= SK_Scalar1); 35cb93a386Sopenharmony_ci SkASSERT(startT <= stopT); 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci if (startT == stopT) { 38cb93a386Sopenharmony_ci if (!dst->isEmpty()) { 39cb93a386Sopenharmony_ci /* if the dash as a zero-length on segment, add a corresponding zero-length line. 40cb93a386Sopenharmony_ci The stroke code will add end caps to zero length lines as appropriate */ 41cb93a386Sopenharmony_ci SkPoint lastPt; 42cb93a386Sopenharmony_ci SkAssertResult(dst->getLastPt(&lastPt)); 43cb93a386Sopenharmony_ci dst->lineTo(lastPt); 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci return; 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci SkPoint tmp0[7], tmp1[7]; 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci switch (segType) { 51cb93a386Sopenharmony_ci case kLine_SegType: 52cb93a386Sopenharmony_ci if (SK_Scalar1 == stopT) { 53cb93a386Sopenharmony_ci dst->lineTo(pts[1]); 54cb93a386Sopenharmony_ci } else { 55cb93a386Sopenharmony_ci dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT), 56cb93a386Sopenharmony_ci SkScalarInterp(pts[0].fY, pts[1].fY, stopT)); 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci break; 59cb93a386Sopenharmony_ci case kQuad_SegType: 60cb93a386Sopenharmony_ci if (0 == startT) { 61cb93a386Sopenharmony_ci if (SK_Scalar1 == stopT) { 62cb93a386Sopenharmony_ci dst->quadTo(pts[1], pts[2]); 63cb93a386Sopenharmony_ci } else { 64cb93a386Sopenharmony_ci SkChopQuadAt(pts, tmp0, stopT); 65cb93a386Sopenharmony_ci dst->quadTo(tmp0[1], tmp0[2]); 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci } else { 68cb93a386Sopenharmony_ci SkChopQuadAt(pts, tmp0, startT); 69cb93a386Sopenharmony_ci if (SK_Scalar1 == stopT) { 70cb93a386Sopenharmony_ci dst->quadTo(tmp0[3], tmp0[4]); 71cb93a386Sopenharmony_ci } else { 72cb93a386Sopenharmony_ci SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT)); 73cb93a386Sopenharmony_ci dst->quadTo(tmp1[1], tmp1[2]); 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci break; 77cb93a386Sopenharmony_ci case kConic_SegType: { 78cb93a386Sopenharmony_ci SkConic conic(pts[0], pts[2], pts[3], pts[1].fX); 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci if (0 == startT) { 81cb93a386Sopenharmony_ci if (SK_Scalar1 == stopT) { 82cb93a386Sopenharmony_ci dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); 83cb93a386Sopenharmony_ci } else { 84cb93a386Sopenharmony_ci SkConic tmp[2]; 85cb93a386Sopenharmony_ci if (conic.chopAt(stopT, tmp)) { 86cb93a386Sopenharmony_ci dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci } else { 90cb93a386Sopenharmony_ci if (SK_Scalar1 == stopT) { 91cb93a386Sopenharmony_ci SkConic tmp[2]; 92cb93a386Sopenharmony_ci if (conic.chopAt(startT, tmp)) { 93cb93a386Sopenharmony_ci dst->conicTo(tmp[1].fPts[1], tmp[1].fPts[2], tmp[1].fW); 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci } else { 96cb93a386Sopenharmony_ci SkConic tmp; 97cb93a386Sopenharmony_ci conic.chopAt(startT, stopT, &tmp); 98cb93a386Sopenharmony_ci dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW); 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci } break; 102cb93a386Sopenharmony_ci case kCubic_SegType: 103cb93a386Sopenharmony_ci if (0 == startT) { 104cb93a386Sopenharmony_ci if (SK_Scalar1 == stopT) { 105cb93a386Sopenharmony_ci dst->cubicTo(pts[1], pts[2], pts[3]); 106cb93a386Sopenharmony_ci } else { 107cb93a386Sopenharmony_ci SkChopCubicAt(pts, tmp0, stopT); 108cb93a386Sopenharmony_ci dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci } else { 111cb93a386Sopenharmony_ci SkChopCubicAt(pts, tmp0, startT); 112cb93a386Sopenharmony_ci if (SK_Scalar1 == stopT) { 113cb93a386Sopenharmony_ci dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]); 114cb93a386Sopenharmony_ci } else { 115cb93a386Sopenharmony_ci SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT)); 116cb93a386Sopenharmony_ci dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]); 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci break; 120cb93a386Sopenharmony_ci default: 121cb93a386Sopenharmony_ci SK_ABORT("unknown segType"); 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci} 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_cistatic inline int tspan_big_enough(int tspan) { 128cb93a386Sopenharmony_ci SkASSERT((unsigned)tspan <= kMaxTValue); 129cb93a386Sopenharmony_ci return tspan >> 10; 130cb93a386Sopenharmony_ci} 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci// can't use tangents, since we need [0..1..................2] to be seen 133cb93a386Sopenharmony_ci// as definitely not a line (it is when drawn, but not parametrically) 134cb93a386Sopenharmony_ci// so we compare midpoints 135cb93a386Sopenharmony_ci#define CHEAP_DIST_LIMIT (SK_Scalar1/2) // just made this value up 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_cistatic bool quad_too_curvy(const SkPoint pts[3], SkScalar tolerance) { 138cb93a386Sopenharmony_ci // diff = (a/4 + b/2 + c/4) - (a/2 + c/2) 139cb93a386Sopenharmony_ci // diff = -a/4 + b/2 - c/4 140cb93a386Sopenharmony_ci SkScalar dx = SkScalarHalf(pts[1].fX) - 141cb93a386Sopenharmony_ci SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX)); 142cb93a386Sopenharmony_ci SkScalar dy = SkScalarHalf(pts[1].fY) - 143cb93a386Sopenharmony_ci SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY)); 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci SkScalar dist = std::max(SkScalarAbs(dx), SkScalarAbs(dy)); 146cb93a386Sopenharmony_ci return dist > tolerance; 147cb93a386Sopenharmony_ci} 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_cistatic bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt, 150cb93a386Sopenharmony_ci const SkPoint& lastPt, SkScalar tolerance) { 151cb93a386Sopenharmony_ci SkPoint midEnds = firstPt + lastPt; 152cb93a386Sopenharmony_ci midEnds *= 0.5f; 153cb93a386Sopenharmony_ci SkVector dxy = midTPt - midEnds; 154cb93a386Sopenharmony_ci SkScalar dist = std::max(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY)); 155cb93a386Sopenharmony_ci return dist > tolerance; 156cb93a386Sopenharmony_ci} 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_cistatic bool cheap_dist_exceeds_limit(const SkPoint& pt, SkScalar x, SkScalar y, 159cb93a386Sopenharmony_ci SkScalar tolerance) { 160cb93a386Sopenharmony_ci SkScalar dist = std::max(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY)); 161cb93a386Sopenharmony_ci // just made up the 1/2 162cb93a386Sopenharmony_ci return dist > tolerance; 163cb93a386Sopenharmony_ci} 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_cistatic bool cubic_too_curvy(const SkPoint pts[4], SkScalar tolerance) { 166cb93a386Sopenharmony_ci return cheap_dist_exceeds_limit(pts[1], 167cb93a386Sopenharmony_ci SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3), 168cb93a386Sopenharmony_ci SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3), tolerance) 169cb93a386Sopenharmony_ci || 170cb93a386Sopenharmony_ci cheap_dist_exceeds_limit(pts[2], 171cb93a386Sopenharmony_ci SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3), 172cb93a386Sopenharmony_ci SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3), tolerance); 173cb93a386Sopenharmony_ci} 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ciclass SkContourMeasureIter::Impl { 176cb93a386Sopenharmony_cipublic: 177cb93a386Sopenharmony_ci Impl(const SkPath& path, bool forceClosed, SkScalar resScale) 178cb93a386Sopenharmony_ci : fPath(path) 179cb93a386Sopenharmony_ci , fIter(SkPathPriv::Iterate(fPath).begin()) 180cb93a386Sopenharmony_ci , fTolerance(CHEAP_DIST_LIMIT * SkScalarInvert(resScale)) 181cb93a386Sopenharmony_ci , fForceClosed(forceClosed) {} 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci bool hasNextSegments() const { return fIter != SkPathPriv::Iterate(fPath).end(); } 184cb93a386Sopenharmony_ci SkContourMeasure* buildSegments(); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ciprivate: 187cb93a386Sopenharmony_ci SkPath fPath; 188cb93a386Sopenharmony_ci SkPathPriv::RangeIter fIter; 189cb93a386Sopenharmony_ci SkScalar fTolerance; 190cb93a386Sopenharmony_ci bool fForceClosed; 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci // temporary 193cb93a386Sopenharmony_ci SkTDArray<SkContourMeasure::Segment> fSegments; 194cb93a386Sopenharmony_ci SkTDArray<SkPoint> fPts; // Points used to define the segments 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci SkDEBUGCODE(void validate() const;) 197cb93a386Sopenharmony_ci SkScalar compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance, unsigned ptIndex); 198cb93a386Sopenharmony_ci SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance, 199cb93a386Sopenharmony_ci int mint, int maxt, unsigned ptIndex); 200cb93a386Sopenharmony_ci SkScalar compute_conic_segs(const SkConic& conic, SkScalar distance, 201cb93a386Sopenharmony_ci int mint, const SkPoint& minPt, 202cb93a386Sopenharmony_ci int maxt, const SkPoint& maxPt, 203cb93a386Sopenharmony_ci unsigned ptIndex); 204cb93a386Sopenharmony_ci SkScalar compute_cubic_segs(const SkPoint pts[4], SkScalar distance, 205cb93a386Sopenharmony_ci int mint, int maxt, unsigned ptIndex); 206cb93a386Sopenharmony_ci}; 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_quad_segs(const SkPoint pts[3], SkScalar distance, 209cb93a386Sopenharmony_ci int mint, int maxt, unsigned ptIndex) { 210cb93a386Sopenharmony_ci if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts, fTolerance)) { 211cb93a386Sopenharmony_ci SkPoint tmp[5]; 212cb93a386Sopenharmony_ci int halft = (mint + maxt) >> 1; 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci SkChopQuadAtHalf(pts, tmp); 215cb93a386Sopenharmony_ci distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex); 216cb93a386Sopenharmony_ci distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex); 217cb93a386Sopenharmony_ci } else { 218cb93a386Sopenharmony_ci SkScalar d = SkPoint::Distance(pts[0], pts[2]); 219cb93a386Sopenharmony_ci SkScalar prevD = distance; 220cb93a386Sopenharmony_ci distance += d; 221cb93a386Sopenharmony_ci if (distance > prevD) { 222cb93a386Sopenharmony_ci SkASSERT(ptIndex < (unsigned)fPts.count()); 223cb93a386Sopenharmony_ci SkContourMeasure::Segment* seg = fSegments.append(); 224cb93a386Sopenharmony_ci seg->fDistance = distance; 225cb93a386Sopenharmony_ci seg->fPtIndex = ptIndex; 226cb93a386Sopenharmony_ci seg->fType = kQuad_SegType; 227cb93a386Sopenharmony_ci seg->fTValue = maxt; 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci } 230cb93a386Sopenharmony_ci return distance; 231cb93a386Sopenharmony_ci} 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_conic_segs(const SkConic& conic, SkScalar distance, 234cb93a386Sopenharmony_ci int mint, const SkPoint& minPt, 235cb93a386Sopenharmony_ci int maxt, const SkPoint& maxPt, 236cb93a386Sopenharmony_ci unsigned ptIndex) { 237cb93a386Sopenharmony_ci int halft = (mint + maxt) >> 1; 238cb93a386Sopenharmony_ci SkPoint halfPt = conic.evalAt(tValue2Scalar(halft)); 239cb93a386Sopenharmony_ci if (!halfPt.isFinite()) { 240cb93a386Sopenharmony_ci return distance; 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt, fTolerance)) { 243cb93a386Sopenharmony_ci distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex); 244cb93a386Sopenharmony_ci distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt, ptIndex); 245cb93a386Sopenharmony_ci } else { 246cb93a386Sopenharmony_ci SkScalar d = SkPoint::Distance(minPt, maxPt); 247cb93a386Sopenharmony_ci SkScalar prevD = distance; 248cb93a386Sopenharmony_ci distance += d; 249cb93a386Sopenharmony_ci if (distance > prevD) { 250cb93a386Sopenharmony_ci SkASSERT(ptIndex < (unsigned)fPts.count()); 251cb93a386Sopenharmony_ci SkContourMeasure::Segment* seg = fSegments.append(); 252cb93a386Sopenharmony_ci seg->fDistance = distance; 253cb93a386Sopenharmony_ci seg->fPtIndex = ptIndex; 254cb93a386Sopenharmony_ci seg->fType = kConic_SegType; 255cb93a386Sopenharmony_ci seg->fTValue = maxt; 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci return distance; 259cb93a386Sopenharmony_ci} 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_cubic_segs(const SkPoint pts[4], SkScalar distance, 262cb93a386Sopenharmony_ci int mint, int maxt, unsigned ptIndex) { 263cb93a386Sopenharmony_ci if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts, fTolerance)) { 264cb93a386Sopenharmony_ci SkPoint tmp[7]; 265cb93a386Sopenharmony_ci int halft = (mint + maxt) >> 1; 266cb93a386Sopenharmony_ci 267cb93a386Sopenharmony_ci SkChopCubicAtHalf(pts, tmp); 268cb93a386Sopenharmony_ci distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex); 269cb93a386Sopenharmony_ci distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex); 270cb93a386Sopenharmony_ci } else { 271cb93a386Sopenharmony_ci SkScalar d = SkPoint::Distance(pts[0], pts[3]); 272cb93a386Sopenharmony_ci SkScalar prevD = distance; 273cb93a386Sopenharmony_ci distance += d; 274cb93a386Sopenharmony_ci if (distance > prevD) { 275cb93a386Sopenharmony_ci SkASSERT(ptIndex < (unsigned)fPts.count()); 276cb93a386Sopenharmony_ci SkContourMeasure::Segment* seg = fSegments.append(); 277cb93a386Sopenharmony_ci seg->fDistance = distance; 278cb93a386Sopenharmony_ci seg->fPtIndex = ptIndex; 279cb93a386Sopenharmony_ci seg->fType = kCubic_SegType; 280cb93a386Sopenharmony_ci seg->fTValue = maxt; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci return distance; 284cb93a386Sopenharmony_ci} 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ciSkScalar SkContourMeasureIter::Impl::compute_line_seg(SkPoint p0, SkPoint p1, SkScalar distance, 287cb93a386Sopenharmony_ci unsigned ptIndex) { 288cb93a386Sopenharmony_ci SkScalar d = SkPoint::Distance(p0, p1); 289cb93a386Sopenharmony_ci SkASSERT(d >= 0); 290cb93a386Sopenharmony_ci SkScalar prevD = distance; 291cb93a386Sopenharmony_ci distance += d; 292cb93a386Sopenharmony_ci if (distance > prevD) { 293cb93a386Sopenharmony_ci SkASSERT((unsigned)ptIndex < (unsigned)fPts.count()); 294cb93a386Sopenharmony_ci SkContourMeasure::Segment* seg = fSegments.append(); 295cb93a386Sopenharmony_ci seg->fDistance = distance; 296cb93a386Sopenharmony_ci seg->fPtIndex = ptIndex; 297cb93a386Sopenharmony_ci seg->fType = kLine_SegType; 298cb93a386Sopenharmony_ci seg->fTValue = kMaxTValue; 299cb93a386Sopenharmony_ci } 300cb93a386Sopenharmony_ci return distance; 301cb93a386Sopenharmony_ci} 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci#ifdef SK_DEBUG 304cb93a386Sopenharmony_civoid SkContourMeasureIter::Impl::validate() const { 305cb93a386Sopenharmony_ci const SkContourMeasure::Segment* seg = fSegments.begin(); 306cb93a386Sopenharmony_ci const SkContourMeasure::Segment* stop = fSegments.end(); 307cb93a386Sopenharmony_ci unsigned ptIndex = 0; 308cb93a386Sopenharmony_ci SkScalar distance = 0; 309cb93a386Sopenharmony_ci // limit the loop to a reasonable number; pathological cases can run for minutes 310cb93a386Sopenharmony_ci int maxChecks = 10000000; // set to INT_MAX to defeat the check 311cb93a386Sopenharmony_ci while (seg < stop) { 312cb93a386Sopenharmony_ci SkASSERT(seg->fDistance > distance); 313cb93a386Sopenharmony_ci SkASSERT(seg->fPtIndex >= ptIndex); 314cb93a386Sopenharmony_ci SkASSERT(seg->fTValue > 0); 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci const SkContourMeasure::Segment* s = seg; 317cb93a386Sopenharmony_ci while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) { 318cb93a386Sopenharmony_ci SkASSERT(s[0].fType == s[1].fType); 319cb93a386Sopenharmony_ci SkASSERT(s[0].fTValue < s[1].fTValue); 320cb93a386Sopenharmony_ci s += 1; 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci distance = seg->fDistance; 324cb93a386Sopenharmony_ci ptIndex = seg->fPtIndex; 325cb93a386Sopenharmony_ci seg += 1; 326cb93a386Sopenharmony_ci } 327cb93a386Sopenharmony_ci} 328cb93a386Sopenharmony_ci#endif 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ciSkContourMeasure* SkContourMeasureIter::Impl::buildSegments() { 331cb93a386Sopenharmony_ci int ptIndex = -1; 332cb93a386Sopenharmony_ci SkScalar distance = 0; 333cb93a386Sopenharmony_ci bool haveSeenClose = fForceClosed; 334cb93a386Sopenharmony_ci bool haveSeenMoveTo = false; 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci /* Note: 337cb93a386Sopenharmony_ci * as we accumulate distance, we have to check that the result of += 338cb93a386Sopenharmony_ci * actually made it larger, since a very small delta might be > 0, but 339cb93a386Sopenharmony_ci * still have no effect on distance (if distance >>> delta). 340cb93a386Sopenharmony_ci * 341cb93a386Sopenharmony_ci * We do this check below, and in compute_quad_segs and compute_cubic_segs 342cb93a386Sopenharmony_ci */ 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci fSegments.reset(); 345cb93a386Sopenharmony_ci fPts.reset(); 346cb93a386Sopenharmony_ci 347cb93a386Sopenharmony_ci auto end = SkPathPriv::Iterate(fPath).end(); 348cb93a386Sopenharmony_ci for (; fIter != end; ++fIter) { 349cb93a386Sopenharmony_ci auto [verb, pts, w] = *fIter; 350cb93a386Sopenharmony_ci if (haveSeenMoveTo && verb == SkPathVerb::kMove) { 351cb93a386Sopenharmony_ci break; 352cb93a386Sopenharmony_ci } 353cb93a386Sopenharmony_ci switch (verb) { 354cb93a386Sopenharmony_ci case SkPathVerb::kMove: 355cb93a386Sopenharmony_ci ptIndex += 1; 356cb93a386Sopenharmony_ci fPts.append(1, pts); 357cb93a386Sopenharmony_ci SkASSERT(!haveSeenMoveTo); 358cb93a386Sopenharmony_ci haveSeenMoveTo = true; 359cb93a386Sopenharmony_ci break; 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci case SkPathVerb::kLine: { 362cb93a386Sopenharmony_ci SkASSERT(haveSeenMoveTo); 363cb93a386Sopenharmony_ci SkScalar prevD = distance; 364cb93a386Sopenharmony_ci distance = this->compute_line_seg(pts[0], pts[1], distance, ptIndex); 365cb93a386Sopenharmony_ci if (distance > prevD) { 366cb93a386Sopenharmony_ci fPts.append(1, pts + 1); 367cb93a386Sopenharmony_ci ptIndex++; 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci } break; 370cb93a386Sopenharmony_ci 371cb93a386Sopenharmony_ci case SkPathVerb::kQuad: { 372cb93a386Sopenharmony_ci SkASSERT(haveSeenMoveTo); 373cb93a386Sopenharmony_ci SkScalar prevD = distance; 374cb93a386Sopenharmony_ci distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex); 375cb93a386Sopenharmony_ci if (distance > prevD) { 376cb93a386Sopenharmony_ci fPts.append(2, pts + 1); 377cb93a386Sopenharmony_ci ptIndex += 2; 378cb93a386Sopenharmony_ci } 379cb93a386Sopenharmony_ci } break; 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_ci case SkPathVerb::kConic: { 382cb93a386Sopenharmony_ci SkASSERT(haveSeenMoveTo); 383cb93a386Sopenharmony_ci const SkConic conic(pts, *w); 384cb93a386Sopenharmony_ci SkScalar prevD = distance; 385cb93a386Sopenharmony_ci distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0], 386cb93a386Sopenharmony_ci kMaxTValue, conic.fPts[2], ptIndex); 387cb93a386Sopenharmony_ci if (distance > prevD) { 388cb93a386Sopenharmony_ci // we store the conic weight in our next point, followed by the last 2 pts 389cb93a386Sopenharmony_ci // thus to reconstitue a conic, you'd need to say 390cb93a386Sopenharmony_ci // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX) 391cb93a386Sopenharmony_ci fPts.append()->set(conic.fW, 0); 392cb93a386Sopenharmony_ci fPts.append(2, pts + 1); 393cb93a386Sopenharmony_ci ptIndex += 3; 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci } break; 396cb93a386Sopenharmony_ci 397cb93a386Sopenharmony_ci case SkPathVerb::kCubic: { 398cb93a386Sopenharmony_ci SkASSERT(haveSeenMoveTo); 399cb93a386Sopenharmony_ci SkScalar prevD = distance; 400cb93a386Sopenharmony_ci distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex); 401cb93a386Sopenharmony_ci if (distance > prevD) { 402cb93a386Sopenharmony_ci fPts.append(3, pts + 1); 403cb93a386Sopenharmony_ci ptIndex += 3; 404cb93a386Sopenharmony_ci } 405cb93a386Sopenharmony_ci } break; 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci case SkPathVerb::kClose: 408cb93a386Sopenharmony_ci haveSeenClose = true; 409cb93a386Sopenharmony_ci break; 410cb93a386Sopenharmony_ci } 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_ci } 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci if (!SkScalarIsFinite(distance)) { 415cb93a386Sopenharmony_ci return nullptr; 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci if (fSegments.count() == 0) { 418cb93a386Sopenharmony_ci return nullptr; 419cb93a386Sopenharmony_ci } 420cb93a386Sopenharmony_ci 421cb93a386Sopenharmony_ci if (haveSeenClose) { 422cb93a386Sopenharmony_ci SkScalar prevD = distance; 423cb93a386Sopenharmony_ci SkPoint firstPt = fPts[0]; 424cb93a386Sopenharmony_ci distance = this->compute_line_seg(fPts[ptIndex], firstPt, distance, ptIndex); 425cb93a386Sopenharmony_ci if (distance > prevD) { 426cb93a386Sopenharmony_ci *fPts.append() = firstPt; 427cb93a386Sopenharmony_ci } 428cb93a386Sopenharmony_ci } 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci return new SkContourMeasure(std::move(fSegments), std::move(fPts), distance, haveSeenClose); 433cb93a386Sopenharmony_ci} 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_cistatic void compute_pos_tan(const SkPoint pts[], unsigned segType, 436cb93a386Sopenharmony_ci SkScalar t, SkPoint* pos, SkVector* tangent) { 437cb93a386Sopenharmony_ci switch (segType) { 438cb93a386Sopenharmony_ci case kLine_SegType: 439cb93a386Sopenharmony_ci if (pos) { 440cb93a386Sopenharmony_ci pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t), 441cb93a386Sopenharmony_ci SkScalarInterp(pts[0].fY, pts[1].fY, t)); 442cb93a386Sopenharmony_ci } 443cb93a386Sopenharmony_ci if (tangent) { 444cb93a386Sopenharmony_ci tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY); 445cb93a386Sopenharmony_ci } 446cb93a386Sopenharmony_ci break; 447cb93a386Sopenharmony_ci case kQuad_SegType: 448cb93a386Sopenharmony_ci SkEvalQuadAt(pts, t, pos, tangent); 449cb93a386Sopenharmony_ci if (tangent) { 450cb93a386Sopenharmony_ci tangent->normalize(); 451cb93a386Sopenharmony_ci } 452cb93a386Sopenharmony_ci break; 453cb93a386Sopenharmony_ci case kConic_SegType: { 454cb93a386Sopenharmony_ci SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent); 455cb93a386Sopenharmony_ci if (tangent) { 456cb93a386Sopenharmony_ci tangent->normalize(); 457cb93a386Sopenharmony_ci } 458cb93a386Sopenharmony_ci } break; 459cb93a386Sopenharmony_ci case kCubic_SegType: 460cb93a386Sopenharmony_ci SkEvalCubicAt(pts, t, pos, tangent, nullptr); 461cb93a386Sopenharmony_ci if (tangent) { 462cb93a386Sopenharmony_ci tangent->normalize(); 463cb93a386Sopenharmony_ci } 464cb93a386Sopenharmony_ci break; 465cb93a386Sopenharmony_ci default: 466cb93a386Sopenharmony_ci SkDEBUGFAIL("unknown segType"); 467cb93a386Sopenharmony_ci } 468cb93a386Sopenharmony_ci} 469cb93a386Sopenharmony_ci 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 472cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 473cb93a386Sopenharmony_ci 474cb93a386Sopenharmony_ciSkContourMeasureIter::SkContourMeasureIter() { 475cb93a386Sopenharmony_ci} 476cb93a386Sopenharmony_ci 477cb93a386Sopenharmony_ciSkContourMeasureIter::SkContourMeasureIter(const SkPath& path, bool forceClosed, 478cb93a386Sopenharmony_ci SkScalar resScale) { 479cb93a386Sopenharmony_ci this->reset(path, forceClosed, resScale); 480cb93a386Sopenharmony_ci} 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ciSkContourMeasureIter::~SkContourMeasureIter() {} 483cb93a386Sopenharmony_ci 484cb93a386Sopenharmony_ci/** Assign a new path, or null to have none. 485cb93a386Sopenharmony_ci*/ 486cb93a386Sopenharmony_civoid SkContourMeasureIter::reset(const SkPath& path, bool forceClosed, SkScalar resScale) { 487cb93a386Sopenharmony_ci if (path.isFinite()) { 488cb93a386Sopenharmony_ci fImpl = std::make_unique<Impl>(path, forceClosed, resScale); 489cb93a386Sopenharmony_ci } else { 490cb93a386Sopenharmony_ci fImpl.reset(); 491cb93a386Sopenharmony_ci } 492cb93a386Sopenharmony_ci} 493cb93a386Sopenharmony_ci 494cb93a386Sopenharmony_cisk_sp<SkContourMeasure> SkContourMeasureIter::next() { 495cb93a386Sopenharmony_ci if (!fImpl) { 496cb93a386Sopenharmony_ci return nullptr; 497cb93a386Sopenharmony_ci } 498cb93a386Sopenharmony_ci while (fImpl->hasNextSegments()) { 499cb93a386Sopenharmony_ci auto cm = fImpl->buildSegments(); 500cb93a386Sopenharmony_ci if (cm) { 501cb93a386Sopenharmony_ci return sk_sp<SkContourMeasure>(cm); 502cb93a386Sopenharmony_ci } 503cb93a386Sopenharmony_ci } 504cb93a386Sopenharmony_ci return nullptr; 505cb93a386Sopenharmony_ci} 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 508cb93a386Sopenharmony_ci 509cb93a386Sopenharmony_ciSkContourMeasure::SkContourMeasure(SkTDArray<Segment>&& segs, SkTDArray<SkPoint>&& pts, SkScalar length, bool isClosed) 510cb93a386Sopenharmony_ci : fSegments(std::move(segs)) 511cb93a386Sopenharmony_ci , fPts(std::move(pts)) 512cb93a386Sopenharmony_ci , fLength(length) 513cb93a386Sopenharmony_ci , fIsClosed(isClosed) 514cb93a386Sopenharmony_ci {} 515cb93a386Sopenharmony_ci 516cb93a386Sopenharmony_citemplate <typename T, typename K> 517cb93a386Sopenharmony_ciint SkTKSearch(const T base[], int count, const K& key) { 518cb93a386Sopenharmony_ci SkASSERT(count >= 0); 519cb93a386Sopenharmony_ci if (count <= 0) { 520cb93a386Sopenharmony_ci return ~0; 521cb93a386Sopenharmony_ci } 522cb93a386Sopenharmony_ci 523cb93a386Sopenharmony_ci SkASSERT(base != nullptr); // base may be nullptr if count is zero 524cb93a386Sopenharmony_ci 525cb93a386Sopenharmony_ci unsigned lo = 0; 526cb93a386Sopenharmony_ci unsigned hi = count - 1; 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci while (lo < hi) { 529cb93a386Sopenharmony_ci unsigned mid = (hi + lo) >> 1; 530cb93a386Sopenharmony_ci if (base[mid].fDistance < key) { 531cb93a386Sopenharmony_ci lo = mid + 1; 532cb93a386Sopenharmony_ci } else { 533cb93a386Sopenharmony_ci hi = mid; 534cb93a386Sopenharmony_ci } 535cb93a386Sopenharmony_ci } 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_ci if (base[hi].fDistance < key) { 538cb93a386Sopenharmony_ci hi += 1; 539cb93a386Sopenharmony_ci hi = ~hi; 540cb93a386Sopenharmony_ci } else if (key < base[hi].fDistance) { 541cb93a386Sopenharmony_ci hi = ~hi; 542cb93a386Sopenharmony_ci } 543cb93a386Sopenharmony_ci return hi; 544cb93a386Sopenharmony_ci} 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ciconst SkContourMeasure::Segment* SkContourMeasure::distanceToSegment( SkScalar distance, 547cb93a386Sopenharmony_ci SkScalar* t) const { 548cb93a386Sopenharmony_ci SkDEBUGCODE(SkScalar length = ) this->length(); 549cb93a386Sopenharmony_ci SkASSERT(distance >= 0 && distance <= length); 550cb93a386Sopenharmony_ci 551cb93a386Sopenharmony_ci const Segment* seg = fSegments.begin(); 552cb93a386Sopenharmony_ci int count = fSegments.count(); 553cb93a386Sopenharmony_ci 554cb93a386Sopenharmony_ci int index = SkTKSearch<Segment, SkScalar>(seg, count, distance); 555cb93a386Sopenharmony_ci // don't care if we hit an exact match or not, so we xor index if it is negative 556cb93a386Sopenharmony_ci index ^= (index >> 31); 557cb93a386Sopenharmony_ci seg = &seg[index]; 558cb93a386Sopenharmony_ci 559cb93a386Sopenharmony_ci // now interpolate t-values with the prev segment (if possible) 560cb93a386Sopenharmony_ci SkScalar startT = 0, startD = 0; 561cb93a386Sopenharmony_ci // check if the prev segment is legal, and references the same set of points 562cb93a386Sopenharmony_ci if (index > 0) { 563cb93a386Sopenharmony_ci startD = seg[-1].fDistance; 564cb93a386Sopenharmony_ci if (seg[-1].fPtIndex == seg->fPtIndex) { 565cb93a386Sopenharmony_ci SkASSERT(seg[-1].fType == seg->fType); 566cb93a386Sopenharmony_ci startT = seg[-1].getScalarT(); 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci } 569cb93a386Sopenharmony_ci 570cb93a386Sopenharmony_ci SkASSERT(seg->getScalarT() > startT); 571cb93a386Sopenharmony_ci SkASSERT(distance >= startD); 572cb93a386Sopenharmony_ci SkASSERT(seg->fDistance > startD); 573cb93a386Sopenharmony_ci 574cb93a386Sopenharmony_ci *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD); 575cb93a386Sopenharmony_ci return seg; 576cb93a386Sopenharmony_ci} 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_cibool SkContourMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) const { 579cb93a386Sopenharmony_ci if (SkScalarIsNaN(distance)) { 580cb93a386Sopenharmony_ci return false; 581cb93a386Sopenharmony_ci } 582cb93a386Sopenharmony_ci 583cb93a386Sopenharmony_ci const SkScalar length = this->length(); 584cb93a386Sopenharmony_ci SkASSERT(length > 0 && fSegments.count() > 0); 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci // pin the distance to a legal range 587cb93a386Sopenharmony_ci if (distance < 0) { 588cb93a386Sopenharmony_ci distance = 0; 589cb93a386Sopenharmony_ci } else if (distance > length) { 590cb93a386Sopenharmony_ci distance = length; 591cb93a386Sopenharmony_ci } 592cb93a386Sopenharmony_ci 593cb93a386Sopenharmony_ci SkScalar t; 594cb93a386Sopenharmony_ci const Segment* seg = this->distanceToSegment(distance, &t); 595cb93a386Sopenharmony_ci if (SkScalarIsNaN(t)) { 596cb93a386Sopenharmony_ci return false; 597cb93a386Sopenharmony_ci } 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_ci SkASSERT((unsigned)seg->fPtIndex < (unsigned)fPts.count()); 600cb93a386Sopenharmony_ci compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent); 601cb93a386Sopenharmony_ci return true; 602cb93a386Sopenharmony_ci} 603cb93a386Sopenharmony_ci 604cb93a386Sopenharmony_cibool SkContourMeasure::getMatrix(SkScalar distance, SkMatrix* matrix, MatrixFlags flags) const { 605cb93a386Sopenharmony_ci SkPoint position; 606cb93a386Sopenharmony_ci SkVector tangent; 607cb93a386Sopenharmony_ci 608cb93a386Sopenharmony_ci if (this->getPosTan(distance, &position, &tangent)) { 609cb93a386Sopenharmony_ci if (matrix) { 610cb93a386Sopenharmony_ci if (flags & kGetTangent_MatrixFlag) { 611cb93a386Sopenharmony_ci matrix->setSinCos(tangent.fY, tangent.fX, 0, 0); 612cb93a386Sopenharmony_ci } else { 613cb93a386Sopenharmony_ci matrix->reset(); 614cb93a386Sopenharmony_ci } 615cb93a386Sopenharmony_ci if (flags & kGetPosition_MatrixFlag) { 616cb93a386Sopenharmony_ci matrix->postTranslate(position.fX, position.fY); 617cb93a386Sopenharmony_ci } 618cb93a386Sopenharmony_ci } 619cb93a386Sopenharmony_ci return true; 620cb93a386Sopenharmony_ci } 621cb93a386Sopenharmony_ci return false; 622cb93a386Sopenharmony_ci} 623cb93a386Sopenharmony_ci 624cb93a386Sopenharmony_cibool SkContourMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, 625cb93a386Sopenharmony_ci bool startWithMoveTo) const { 626cb93a386Sopenharmony_ci SkASSERT(dst); 627cb93a386Sopenharmony_ci 628cb93a386Sopenharmony_ci SkScalar length = this->length(); // ensure we have built our segments 629cb93a386Sopenharmony_ci 630cb93a386Sopenharmony_ci if (startD < 0) { 631cb93a386Sopenharmony_ci startD = 0; 632cb93a386Sopenharmony_ci } 633cb93a386Sopenharmony_ci if (stopD > length) { 634cb93a386Sopenharmony_ci stopD = length; 635cb93a386Sopenharmony_ci } 636cb93a386Sopenharmony_ci if (!(startD <= stopD)) { // catch NaN values as well 637cb93a386Sopenharmony_ci return false; 638cb93a386Sopenharmony_ci } 639cb93a386Sopenharmony_ci if (!fSegments.count()) { 640cb93a386Sopenharmony_ci return false; 641cb93a386Sopenharmony_ci } 642cb93a386Sopenharmony_ci 643cb93a386Sopenharmony_ci SkPoint p; 644cb93a386Sopenharmony_ci SkScalar startT, stopT; 645cb93a386Sopenharmony_ci const Segment* seg = this->distanceToSegment(startD, &startT); 646cb93a386Sopenharmony_ci if (!SkScalarIsFinite(startT)) { 647cb93a386Sopenharmony_ci return false; 648cb93a386Sopenharmony_ci } 649cb93a386Sopenharmony_ci const Segment* stopSeg = this->distanceToSegment(stopD, &stopT); 650cb93a386Sopenharmony_ci if (!SkScalarIsFinite(stopT)) { 651cb93a386Sopenharmony_ci return false; 652cb93a386Sopenharmony_ci } 653cb93a386Sopenharmony_ci SkASSERT(seg <= stopSeg); 654cb93a386Sopenharmony_ci if (startWithMoveTo) { 655cb93a386Sopenharmony_ci compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr); 656cb93a386Sopenharmony_ci dst->moveTo(p); 657cb93a386Sopenharmony_ci } 658cb93a386Sopenharmony_ci 659cb93a386Sopenharmony_ci if (seg->fPtIndex == stopSeg->fPtIndex) { 660cb93a386Sopenharmony_ci SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst); 661cb93a386Sopenharmony_ci } else { 662cb93a386Sopenharmony_ci do { 663cb93a386Sopenharmony_ci SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst); 664cb93a386Sopenharmony_ci seg = SkContourMeasure::Segment::Next(seg); 665cb93a386Sopenharmony_ci startT = 0; 666cb93a386Sopenharmony_ci } while (seg->fPtIndex < stopSeg->fPtIndex); 667cb93a386Sopenharmony_ci SkContourMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst); 668cb93a386Sopenharmony_ci } 669cb93a386Sopenharmony_ci 670cb93a386Sopenharmony_ci return true; 671cb93a386Sopenharmony_ci} 672