18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2008 The Android Open Source Project 38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPathMeasure.h" 1023d97760248300b7aec213a36f8b0485857240b5hstern#include "SkPathMeasurePriv.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkGeometry.h" 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTSearch.h" 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15f97aa74fea0133378e64700e30a7c2962212fcb5caryclark#define kMaxTValue 0x3FFFFFFF 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline SkScalar tValue2Scalar(int t) { 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((unsigned)t <= kMaxTValue); 19f97aa74fea0133378e64700e30a7c2962212fcb5caryclark const SkScalar kMaxTReciprocal = 1.0f / kMaxTValue; 20f97aa74fea0133378e64700e30a7c2962212fcb5caryclark return t * kMaxTReciprocal; 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::Segment::getScalarT() const { 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return tValue2Scalar(fTValue); 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) { 288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com unsigned ptIndex = seg->fPtIndex; 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ++seg; 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (seg->fPtIndex == ptIndex); 338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return seg; 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3623d97760248300b7aec213a36f8b0485857240b5hsternvoid SkPathMeasure_segTo(const SkPoint pts[], unsigned segType, 3723d97760248300b7aec213a36f8b0485857240b5hstern SkScalar startT, SkScalar stopT, SkPath* dst) { 3823d97760248300b7aec213a36f8b0485857240b5hstern SkASSERT(startT >= 0 && startT <= SK_Scalar1); 3923d97760248300b7aec213a36f8b0485857240b5hstern SkASSERT(stopT >= 0 && stopT <= SK_Scalar1); 4023d97760248300b7aec213a36f8b0485857240b5hstern SkASSERT(startT <= stopT); 4123d97760248300b7aec213a36f8b0485857240b5hstern 4223d97760248300b7aec213a36f8b0485857240b5hstern if (startT == stopT) { 4323d97760248300b7aec213a36f8b0485857240b5hstern /* if the dash as a zero-length on segment, add a corresponding zero-length line. 4423d97760248300b7aec213a36f8b0485857240b5hstern The stroke code will add end caps to zero length lines as appropriate */ 4523d97760248300b7aec213a36f8b0485857240b5hstern SkPoint lastPt; 4623d97760248300b7aec213a36f8b0485857240b5hstern SkAssertResult(dst->getLastPt(&lastPt)); 4723d97760248300b7aec213a36f8b0485857240b5hstern dst->lineTo(lastPt); 4823d97760248300b7aec213a36f8b0485857240b5hstern return; 4923d97760248300b7aec213a36f8b0485857240b5hstern } 5023d97760248300b7aec213a36f8b0485857240b5hstern 5123d97760248300b7aec213a36f8b0485857240b5hstern SkPoint tmp0[7], tmp1[7]; 5223d97760248300b7aec213a36f8b0485857240b5hstern 5323d97760248300b7aec213a36f8b0485857240b5hstern switch (segType) { 5423d97760248300b7aec213a36f8b0485857240b5hstern case kLine_SegType: 5523d97760248300b7aec213a36f8b0485857240b5hstern if (SK_Scalar1 == stopT) { 5623d97760248300b7aec213a36f8b0485857240b5hstern dst->lineTo(pts[1]); 5723d97760248300b7aec213a36f8b0485857240b5hstern } else { 5823d97760248300b7aec213a36f8b0485857240b5hstern dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT), 5923d97760248300b7aec213a36f8b0485857240b5hstern SkScalarInterp(pts[0].fY, pts[1].fY, stopT)); 6023d97760248300b7aec213a36f8b0485857240b5hstern } 6123d97760248300b7aec213a36f8b0485857240b5hstern break; 6223d97760248300b7aec213a36f8b0485857240b5hstern case kQuad_SegType: 6323d97760248300b7aec213a36f8b0485857240b5hstern if (0 == startT) { 6423d97760248300b7aec213a36f8b0485857240b5hstern if (SK_Scalar1 == stopT) { 6523d97760248300b7aec213a36f8b0485857240b5hstern dst->quadTo(pts[1], pts[2]); 6623d97760248300b7aec213a36f8b0485857240b5hstern } else { 6723d97760248300b7aec213a36f8b0485857240b5hstern SkChopQuadAt(pts, tmp0, stopT); 6823d97760248300b7aec213a36f8b0485857240b5hstern dst->quadTo(tmp0[1], tmp0[2]); 6923d97760248300b7aec213a36f8b0485857240b5hstern } 7023d97760248300b7aec213a36f8b0485857240b5hstern } else { 7123d97760248300b7aec213a36f8b0485857240b5hstern SkChopQuadAt(pts, tmp0, startT); 7223d97760248300b7aec213a36f8b0485857240b5hstern if (SK_Scalar1 == stopT) { 7323d97760248300b7aec213a36f8b0485857240b5hstern dst->quadTo(tmp0[3], tmp0[4]); 7423d97760248300b7aec213a36f8b0485857240b5hstern } else { 7523d97760248300b7aec213a36f8b0485857240b5hstern SkChopQuadAt(&tmp0[2], tmp1, (stopT - startT) / (1 - startT)); 7623d97760248300b7aec213a36f8b0485857240b5hstern dst->quadTo(tmp1[1], tmp1[2]); 7723d97760248300b7aec213a36f8b0485857240b5hstern } 7823d97760248300b7aec213a36f8b0485857240b5hstern } 7923d97760248300b7aec213a36f8b0485857240b5hstern break; 8023d97760248300b7aec213a36f8b0485857240b5hstern case kConic_SegType: { 8123d97760248300b7aec213a36f8b0485857240b5hstern SkConic conic(pts[0], pts[2], pts[3], pts[1].fX); 8223d97760248300b7aec213a36f8b0485857240b5hstern 8323d97760248300b7aec213a36f8b0485857240b5hstern if (0 == startT) { 8423d97760248300b7aec213a36f8b0485857240b5hstern if (SK_Scalar1 == stopT) { 8523d97760248300b7aec213a36f8b0485857240b5hstern dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); 8623d97760248300b7aec213a36f8b0485857240b5hstern } else { 8723d97760248300b7aec213a36f8b0485857240b5hstern SkConic tmp[2]; 88414c4295f951d43068666b6294df15b2fd2ba85ccaryclark if (conic.chopAt(stopT, tmp)) { 89414c4295f951d43068666b6294df15b2fd2ba85ccaryclark dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); 90414c4295f951d43068666b6294df15b2fd2ba85ccaryclark } 9123d97760248300b7aec213a36f8b0485857240b5hstern } 9223d97760248300b7aec213a36f8b0485857240b5hstern } else { 9323d97760248300b7aec213a36f8b0485857240b5hstern if (SK_Scalar1 == stopT) { 9423d97760248300b7aec213a36f8b0485857240b5hstern SkConic tmp1[2]; 95414c4295f951d43068666b6294df15b2fd2ba85ccaryclark if (conic.chopAt(startT, tmp1)) { 96414c4295f951d43068666b6294df15b2fd2ba85ccaryclark dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); 97414c4295f951d43068666b6294df15b2fd2ba85ccaryclark } 9823d97760248300b7aec213a36f8b0485857240b5hstern } else { 9923d97760248300b7aec213a36f8b0485857240b5hstern SkConic tmp; 10023d97760248300b7aec213a36f8b0485857240b5hstern conic.chopAt(startT, stopT, &tmp); 10123d97760248300b7aec213a36f8b0485857240b5hstern dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW); 10223d97760248300b7aec213a36f8b0485857240b5hstern } 10323d97760248300b7aec213a36f8b0485857240b5hstern } 10423d97760248300b7aec213a36f8b0485857240b5hstern } break; 10523d97760248300b7aec213a36f8b0485857240b5hstern case kCubic_SegType: 10623d97760248300b7aec213a36f8b0485857240b5hstern if (0 == startT) { 10723d97760248300b7aec213a36f8b0485857240b5hstern if (SK_Scalar1 == stopT) { 10823d97760248300b7aec213a36f8b0485857240b5hstern dst->cubicTo(pts[1], pts[2], pts[3]); 10923d97760248300b7aec213a36f8b0485857240b5hstern } else { 11023d97760248300b7aec213a36f8b0485857240b5hstern SkChopCubicAt(pts, tmp0, stopT); 11123d97760248300b7aec213a36f8b0485857240b5hstern dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); 11223d97760248300b7aec213a36f8b0485857240b5hstern } 11323d97760248300b7aec213a36f8b0485857240b5hstern } else { 11423d97760248300b7aec213a36f8b0485857240b5hstern SkChopCubicAt(pts, tmp0, startT); 11523d97760248300b7aec213a36f8b0485857240b5hstern if (SK_Scalar1 == stopT) { 11623d97760248300b7aec213a36f8b0485857240b5hstern dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]); 11723d97760248300b7aec213a36f8b0485857240b5hstern } else { 11823d97760248300b7aec213a36f8b0485857240b5hstern SkChopCubicAt(&tmp0[3], tmp1, (stopT - startT) / (1 - startT)); 11923d97760248300b7aec213a36f8b0485857240b5hstern dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]); 12023d97760248300b7aec213a36f8b0485857240b5hstern } 12123d97760248300b7aec213a36f8b0485857240b5hstern } 12223d97760248300b7aec213a36f8b0485857240b5hstern break; 12323d97760248300b7aec213a36f8b0485857240b5hstern default: 1247ca9a74fef3296cdf1385785b5e817e963bb4c35Ben Wagner SK_ABORT("unknown segType"); 12523d97760248300b7aec213a36f8b0485857240b5hstern } 12623d97760248300b7aec213a36f8b0485857240b5hstern} 12723d97760248300b7aec213a36f8b0485857240b5hstern 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int tspan_big_enough(int tspan) { 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((unsigned)tspan <= kMaxTValue); 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return tspan >> 10; 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// can't use tangents, since we need [0..1..................2] to be seen 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// as definitely not a line (it is when drawn, but not parametrically) 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// so we compare midpoints 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define CHEAP_DIST_LIMIT (SK_Scalar1/2) // just made this value up 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1401a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::quad_too_curvy(const SkPoint pts[3]) { 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // diff = (a/4 + b/2 + c/4) - (a/2 + c/2) 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // diff = -a/4 + b/2 - c/4 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar dx = SkScalarHalf(pts[1].fX) - 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX)); 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar dy = SkScalarHalf(pts[1].fY) - 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY)); 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy)); 1491a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark return dist > fTolerance; 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1521a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt, 153b6474dd1a530a543ae799c3822e8bc60180761c0caryclark const SkPoint& lastPt) { 154b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkPoint midEnds = firstPt + lastPt; 155b6474dd1a530a543ae799c3822e8bc60180761c0caryclark midEnds *= 0.5f; 156b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkVector dxy = midTPt - midEnds; 157b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar dist = SkMaxScalar(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY)); 1581a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark return dist > fTolerance; 159b6474dd1a530a543ae799c3822e8bc60180761c0caryclark} 160b6474dd1a530a543ae799c3822e8bc60180761c0caryclark 1611a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::cheap_dist_exceeds_limit(const SkPoint& pt, 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar x, SkScalar y) { 1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY)); 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // just made up the 1/2 1651a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark return dist > fTolerance; 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1681a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkbool SkPathMeasure::cubic_too_curvy(const SkPoint pts[4]) { 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return cheap_dist_exceeds_limit(pts[1], 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3), 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3)) 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com || 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com cheap_dist_exceeds_limit(pts[2], 1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3), 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3)); 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 178b6474dd1a530a543ae799c3822e8bc60180761c0caryclarkstatic SkScalar quad_folded_len(const SkPoint pts[3]) { 179b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar t = SkFindQuadMaxCurvature(pts); 180b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkPoint pt = SkEvalQuadAt(pts, t); 181b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkVector a = pts[2] - pt; 182b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar result = a.length(); 183b6474dd1a530a543ae799c3822e8bc60180761c0caryclark if (0 != t) { 184b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkVector b = pts[0] - pt; 185b6474dd1a530a543ae799c3822e8bc60180761c0caryclark result += b.length(); 186b6474dd1a530a543ae799c3822e8bc60180761c0caryclark } 187b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkASSERT(SkScalarIsFinite(result)); 188b6474dd1a530a543ae799c3822e8bc60180761c0caryclark return result; 189b6474dd1a530a543ae799c3822e8bc60180761c0caryclark} 190b6474dd1a530a543ae799c3822e8bc60180761c0caryclark 19117bc0851d34afe8c89d7455c061a1d419f76af8acaryclark/* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */ 192b6474dd1a530a543ae799c3822e8bc60180761c0caryclark/* This works -- more needs to be done to see if it is performant on all platforms. 193b6474dd1a530a543ae799c3822e8bc60180761c0caryclark To use this to measure parts of quads requires recomputing everything -- perhaps 194b6474dd1a530a543ae799c3822e8bc60180761c0caryclark a chop-like interface can start from a larger measurement and get two new measurements 195b6474dd1a530a543ae799c3822e8bc60180761c0caryclark with one call here. 196b6474dd1a530a543ae799c3822e8bc60180761c0caryclark */ 19717bc0851d34afe8c89d7455c061a1d419f76af8acaryclarkstatic SkScalar compute_quad_len(const SkPoint pts[3]) { 198b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkPoint a,b; 199b6474dd1a530a543ae799c3822e8bc60180761c0caryclark a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; 200b6474dd1a530a543ae799c3822e8bc60180761c0caryclark a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; 201b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); 202b6474dd1a530a543ae799c3822e8bc60180761c0caryclark if (0 == A) { 203b6474dd1a530a543ae799c3822e8bc60180761c0caryclark a = pts[2] - pts[0]; 204b6474dd1a530a543ae799c3822e8bc60180761c0caryclark return a.length(); 205b6474dd1a530a543ae799c3822e8bc60180761c0caryclark } 206b6474dd1a530a543ae799c3822e8bc60180761c0caryclark b.fX = 2 * (pts[1].fX - pts[0].fX); 207b6474dd1a530a543ae799c3822e8bc60180761c0caryclark b.fY = 2 * (pts[1].fY - pts[0].fY); 208b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); 209b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar C = b.fX * b.fX + b.fY * b.fY; 210b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); 211b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar A_2 = SkScalarSqrt(A); 212b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar A_32 = 2 * A * A_2; 213b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar C_2 = 2 * SkScalarSqrt(C); 214b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar BA = B / A_2; 215b6474dd1a530a543ae799c3822e8bc60180761c0caryclark if (0 == BA + C_2) { 216b6474dd1a530a543ae799c3822e8bc60180761c0caryclark return quad_folded_len(pts); 217b6474dd1a530a543ae799c3822e8bc60180761c0caryclark } 218b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2); 219b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar K = 4 * C * A - B * B; 220b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2); 221b6474dd1a530a543ae799c3822e8bc60180761c0caryclark if (L <= 0) { 222b6474dd1a530a543ae799c3822e8bc60180761c0caryclark return quad_folded_len(pts); 223b6474dd1a530a543ae799c3822e8bc60180761c0caryclark } 224b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar M = SkScalarLog(L); 225b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar result = (J + K * M) / (4 * A_32); 226b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkASSERT(SkScalarIsFinite(result)); 227b6474dd1a530a543ae799c3822e8bc60180761c0caryclark return result; 22817bc0851d34afe8c89d7455c061a1d419f76af8acaryclark} 22917bc0851d34afe8c89d7455c061a1d419f76af8acaryclark 2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], 2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar distance, int mint, int maxt, int ptIndex) { 2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) { 2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint tmp[5]; 2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int halft = (mint + maxt) >> 1; 2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkChopQuadAtHalf(pts, tmp); 2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex); 2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex); 2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar d = SkPoint::Distance(pts[0], pts[2]); 241ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com SkScalar prevD = distance; 242ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com distance += d; 243ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com if (distance > prevD) { 2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Segment* seg = fSegments.append(); 2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fDistance = distance; 2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fPtIndex = ptIndex; 2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fType = kQuad_SegType; 2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fTValue = maxt; 2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return distance; 2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 254b6474dd1a530a543ae799c3822e8bc60180761c0caryclarkSkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distance, 255b6474dd1a530a543ae799c3822e8bc60180761c0caryclark int mint, const SkPoint& minPt, 256b6474dd1a530a543ae799c3822e8bc60180761c0caryclark int maxt, const SkPoint& maxPt, int ptIndex) { 257b6474dd1a530a543ae799c3822e8bc60180761c0caryclark int halft = (mint + maxt) >> 1; 258b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkPoint halfPt = conic.evalAt(tValue2Scalar(halft)); 259b6474dd1a530a543ae799c3822e8bc60180761c0caryclark if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt)) { 260b6474dd1a530a543ae799c3822e8bc60180761c0caryclark distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex); 261b6474dd1a530a543ae799c3822e8bc60180761c0caryclark distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt, ptIndex); 262b6474dd1a530a543ae799c3822e8bc60180761c0caryclark } else { 263b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar d = SkPoint::Distance(minPt, maxPt); 264b6474dd1a530a543ae799c3822e8bc60180761c0caryclark SkScalar prevD = distance; 265b6474dd1a530a543ae799c3822e8bc60180761c0caryclark distance += d; 266b6474dd1a530a543ae799c3822e8bc60180761c0caryclark if (distance > prevD) { 267b6474dd1a530a543ae799c3822e8bc60180761c0caryclark Segment* seg = fSegments.append(); 268b6474dd1a530a543ae799c3822e8bc60180761c0caryclark seg->fDistance = distance; 269b6474dd1a530a543ae799c3822e8bc60180761c0caryclark seg->fPtIndex = ptIndex; 270b6474dd1a530a543ae799c3822e8bc60180761c0caryclark seg->fType = kConic_SegType; 271b6474dd1a530a543ae799c3822e8bc60180761c0caryclark seg->fTValue = maxt; 272b6474dd1a530a543ae799c3822e8bc60180761c0caryclark } 273b6474dd1a530a543ae799c3822e8bc60180761c0caryclark } 274b6474dd1a530a543ae799c3822e8bc60180761c0caryclark return distance; 275b6474dd1a530a543ae799c3822e8bc60180761c0caryclark} 276220f926d9d4b38a9018c922c095847bbd261f583reed 2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], 2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar distance, int mint, int maxt, int ptIndex) { 2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) { 2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint tmp[7]; 2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int halft = (mint + maxt) >> 1; 2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkChopCubicAtHalf(pts, tmp); 2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex); 2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex); 2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar d = SkPoint::Distance(pts[0], pts[3]); 288ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com SkScalar prevD = distance; 289ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com distance += d; 290ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com if (distance > prevD) { 2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Segment* seg = fSegments.append(); 2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fDistance = distance; 2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fPtIndex = ptIndex; 2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fType = kCubic_SegType; 2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fTValue = maxt; 2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return distance; 2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPathMeasure::buildSegments() { 3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pts[4]; 3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int ptIndex = fFirstPtIndex; 304fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com SkScalar distance = 0; 3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool isClosed = fForceClosed; 3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool firstMoveTo = ptIndex < 0; 3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Segment* seg; 3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 309fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com /* Note: 310fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com * as we accumulate distance, we have to check that the result of += 311fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com * actually made it larger, since a very small delta might be > 0, but 312fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com * still have no effect on distance (if distance >>> delta). 313ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com * 314ded44149856373072a8c6d2b2eacb213a1273a6ereed@google.com * We do this check below, and in compute_quad_segs and compute_cubic_segs 315fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com */ 3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSegments.reset(); 317a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org bool done = false; 318a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org do { 3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (fIter.next(pts)) { 3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkPath::kMove_Verb: 321a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org ptIndex += 1; 322a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org fPts.append(1, pts); 3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!firstMoveTo) { 324a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org done = true; 325a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org break; 3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 327a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org firstMoveTo = false; 328a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org break; 3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 330fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com case SkPath::kLine_Verb: { 331fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com SkScalar d = SkPoint::Distance(pts[0], pts[1]); 3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(d >= 0); 333fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com SkScalar prevD = distance; 334a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org distance += d; 335fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com if (distance > prevD) { 336fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com seg = fSegments.append(); 337fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com seg->fDistance = distance; 338fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com seg->fPtIndex = ptIndex; 339fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com seg->fType = kLine_SegType; 340fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com seg->fTValue = kMaxTValue; 341fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com fPts.append(1, pts + 1); 342fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com ptIndex++; 343fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com } 344fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com } break; 3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 346fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com case SkPath::kQuad_Verb: { 347fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com SkScalar prevD = distance; 34817bc0851d34afe8c89d7455c061a1d419f76af8acaryclark if (false) { 34917bc0851d34afe8c89d7455c061a1d419f76af8acaryclark SkScalar length = compute_quad_len(pts); 35017bc0851d34afe8c89d7455c061a1d419f76af8acaryclark if (length) { 35117bc0851d34afe8c89d7455c061a1d419f76af8acaryclark distance += length; 35217bc0851d34afe8c89d7455c061a1d419f76af8acaryclark Segment* seg = fSegments.append(); 35317bc0851d34afe8c89d7455c061a1d419f76af8acaryclark seg->fDistance = distance; 35417bc0851d34afe8c89d7455c061a1d419f76af8acaryclark seg->fPtIndex = ptIndex; 35517bc0851d34afe8c89d7455c061a1d419f76af8acaryclark seg->fType = kQuad_SegType; 35617bc0851d34afe8c89d7455c061a1d419f76af8acaryclark seg->fTValue = kMaxTValue; 35717bc0851d34afe8c89d7455c061a1d419f76af8acaryclark } 35817bc0851d34afe8c89d7455c061a1d419f76af8acaryclark } else { 35917bc0851d34afe8c89d7455c061a1d419f76af8acaryclark distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex); 36017bc0851d34afe8c89d7455c061a1d419f76af8acaryclark } 361fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com if (distance > prevD) { 362fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com fPts.append(2, pts + 1); 363fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com ptIndex += 2; 364fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com } 365fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com } break; 3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 367220f926d9d4b38a9018c922c095847bbd261f583reed case SkPath::kConic_Verb: { 368220f926d9d4b38a9018c922c095847bbd261f583reed const SkConic conic(pts, fIter.conicWeight()); 369220f926d9d4b38a9018c922c095847bbd261f583reed SkScalar prevD = distance; 370b6474dd1a530a543ae799c3822e8bc60180761c0caryclark distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0], 371b6474dd1a530a543ae799c3822e8bc60180761c0caryclark kMaxTValue, conic.fPts[2], ptIndex); 372220f926d9d4b38a9018c922c095847bbd261f583reed if (distance > prevD) { 373220f926d9d4b38a9018c922c095847bbd261f583reed // we store the conic weight in our next point, followed by the last 2 pts 374220f926d9d4b38a9018c922c095847bbd261f583reed // thus to reconstitue a conic, you'd need to say 375220f926d9d4b38a9018c922c095847bbd261f583reed // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX) 376220f926d9d4b38a9018c922c095847bbd261f583reed fPts.append()->set(conic.fW, 0); 377220f926d9d4b38a9018c922c095847bbd261f583reed fPts.append(2, pts + 1); 378220f926d9d4b38a9018c922c095847bbd261f583reed ptIndex += 3; 379220f926d9d4b38a9018c922c095847bbd261f583reed } 380220f926d9d4b38a9018c922c095847bbd261f583reed } break; 381220f926d9d4b38a9018c922c095847bbd261f583reed 382fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com case SkPath::kCubic_Verb: { 383fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com SkScalar prevD = distance; 384220f926d9d4b38a9018c922c095847bbd261f583reed distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex); 385fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com if (distance > prevD) { 386fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com fPts.append(3, pts + 1); 387fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com ptIndex += 3; 388fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com } 389fab1ddd3a8893db58b2ce0afd28ecc73412ee871reed@google.com } break; 3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkPath::kClose_Verb: 3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com isClosed = true; 3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 394fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkPath::kDone_Verb: 396a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org done = true; 397a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org break; 3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 399a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org } while (!done); 400a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org 4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLength = distance; 4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fIsClosed = isClosed; 403a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org fFirstPtIndex = ptIndex; 4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* seg = fSegments.begin(); 4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* stop = fSegments.end(); 4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com unsigned ptIndex = 0; 4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar distance = 0; 411d1d628120af11c022e88265e9bdd27eb7d5d1eb8caryclark // limit the loop to a reasonable number; pathological cases can run for minutes 412d1d628120af11c022e88265e9bdd27eb7d5d1eb8caryclark int maxChecks = 10000000; // set to INT_MAX to defeat the check 4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while (seg < stop) { 4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(seg->fDistance > distance); 4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(seg->fPtIndex >= ptIndex); 4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(seg->fTValue > 0); 4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* s = seg; 419d1d628120af11c022e88265e9bdd27eb7d5d1eb8caryclark while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex && --maxChecks > 0) { 4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(s[0].fType == s[1].fType); 4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(s[0].fTValue < s[1].fTValue); 4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com s += 1; 4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com distance = seg->fDistance; 4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ptIndex = seg->fPtIndex; 4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg += 1; 4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // SkDebugf("\n"); 4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 43423d97760248300b7aec213a36f8b0485857240b5hsternstatic void compute_pos_tan(const SkPoint pts[], unsigned segType, 4355b94153a7b039a9269a8aabbe8f0da0e878e3978reed@google.com SkScalar t, SkPoint* pos, SkVector* tangent) { 4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (segType) { 4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kLine_SegType: 4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (pos) { 439a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t), 4405b94153a7b039a9269a8aabbe8f0da0e878e3978reed@google.com SkScalarInterp(pts[0].fY, pts[1].fY, t)); 4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (tangent) { 443a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY); 4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kQuad_SegType: 4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkEvalQuadAt(pts, t, pos, tangent); 4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (tangent) { 4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tangent->normalize(); 4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 452220f926d9d4b38a9018c922c095847bbd261f583reed case kConic_SegType: { 453220f926d9d4b38a9018c922c095847bbd261f583reed SkConic(pts[0], pts[2], pts[3], pts[1].fX).evalAt(t, pos, tangent); 454220f926d9d4b38a9018c922c095847bbd261f583reed if (tangent) { 455220f926d9d4b38a9018c922c095847bbd261f583reed tangent->normalize(); 456220f926d9d4b38a9018c922c095847bbd261f583reed } 457220f926d9d4b38a9018c922c095847bbd261f583reed } break; 4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCubic_SegType: 45996fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkEvalCubicAt(pts, t, pos, tangent, nullptr); 4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (tangent) { 4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tangent->normalize(); 4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 4650c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("unknown segType"); 4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////// 4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////// 4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPathMeasure::SkPathMeasure() { 47496fcdcc219d2a0d3579719b84b28bede76efba64halcanary fPath = nullptr; 4751a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark fTolerance = CHEAP_DIST_LIMIT; 4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLength = -1; // signal we need to compute it 4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fForceClosed = false; 4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFirstPtIndex = -1; 4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4811a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkSkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale) { 4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPath = &path; 4831a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark fTolerance = CHEAP_DIST_LIMIT * SkScalarInvert(resScale); 4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLength = -1; // signal we need to compute it 4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fForceClosed = forceClosed; 4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFirstPtIndex = -1; 4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fIter.setPath(path, forceClosed); 4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPathMeasure::~SkPathMeasure() {} 4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** Assign a new path, or null to have none. 4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPathMeasure::setPath(const SkPath* path, bool forceClosed) { 4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPath = path; 4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLength = -1; // signal we need to compute it 4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fForceClosed = forceClosed; 4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fFirstPtIndex = -1; 5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (path) { 5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fIter.setPath(*path, forceClosed); 5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fSegments.reset(); 505a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org fPts.reset(); 5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkPathMeasure::getLength() { 50996fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (fPath == nullptr) { 5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fLength < 0) { 5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->buildSegments(); 5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 515ae68a399cdf3d94aff28e497d5360bc288f2131dCary Clark if (SkScalarIsNaN(fLength)) { 516ae68a399cdf3d94aff28e497d5360bc288f2131dCary Clark fLength = 0; 517ae68a399cdf3d94aff28e497d5360bc288f2131dCary Clark } 5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(fLength >= 0); 5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return fLength; 5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 52283e22e407e48acc4e23774edb2241c6a111e1db9reedtemplate <typename T, typename K> 52383e22e407e48acc4e23774edb2241c6a111e1db9reedint SkTKSearch(const T base[], int count, const K& key) { 52483e22e407e48acc4e23774edb2241c6a111e1db9reed SkASSERT(count >= 0); 52583e22e407e48acc4e23774edb2241c6a111e1db9reed if (count <= 0) { 52683e22e407e48acc4e23774edb2241c6a111e1db9reed return ~0; 52783e22e407e48acc4e23774edb2241c6a111e1db9reed } 5289d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary 52996fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(base != nullptr); // base may be nullptr if count is zero 5309d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary 53183e22e407e48acc4e23774edb2241c6a111e1db9reed int lo = 0; 53283e22e407e48acc4e23774edb2241c6a111e1db9reed int hi = count - 1; 5339d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary 53483e22e407e48acc4e23774edb2241c6a111e1db9reed while (lo < hi) { 53583e22e407e48acc4e23774edb2241c6a111e1db9reed int mid = (hi + lo) >> 1; 53683e22e407e48acc4e23774edb2241c6a111e1db9reed if (base[mid].fDistance < key) { 53783e22e407e48acc4e23774edb2241c6a111e1db9reed lo = mid + 1; 53883e22e407e48acc4e23774edb2241c6a111e1db9reed } else { 53983e22e407e48acc4e23774edb2241c6a111e1db9reed hi = mid; 54083e22e407e48acc4e23774edb2241c6a111e1db9reed } 54183e22e407e48acc4e23774edb2241c6a111e1db9reed } 5429d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary 54383e22e407e48acc4e23774edb2241c6a111e1db9reed if (base[hi].fDistance < key) { 54483e22e407e48acc4e23774edb2241c6a111e1db9reed hi += 1; 54583e22e407e48acc4e23774edb2241c6a111e1db9reed hi = ~hi; 54683e22e407e48acc4e23774edb2241c6a111e1db9reed } else if (key < base[hi].fDistance) { 54783e22e407e48acc4e23774edb2241c6a111e1db9reed hi = ~hi; 54883e22e407e48acc4e23774edb2241c6a111e1db9reed } 54983e22e407e48acc4e23774edb2241c6a111e1db9reed return hi; 55083e22e407e48acc4e23774edb2241c6a111e1db9reed} 55183e22e407e48acc4e23774edb2241c6a111e1db9reed 5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkPathMeasure::Segment* SkPathMeasure::distanceToSegment( 5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar distance, SkScalar* t) { 5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(SkScalar length = ) this->getLength(); 5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(distance >= 0 && distance <= length); 5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* seg = fSegments.begin(); 5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count = fSegments.count(); 5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 56083e22e407e48acc4e23774edb2241c6a111e1db9reed int index = SkTKSearch<Segment, SkScalar>(seg, count, distance); 5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // don't care if we hit an exact match or not, so we xor index if it is negative 5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com index ^= (index >> 31); 5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg = &seg[index]; 5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now interpolate t-values with the prev segment (if possible) 5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar startT = 0, startD = 0; 5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // check if the prev segment is legal, and references the same set of points 5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (index > 0) { 5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com startD = seg[-1].fDistance; 5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (seg[-1].fPtIndex == seg->fPtIndex) { 5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(seg[-1].fType == seg->fType); 5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com startT = seg[-1].getScalarT(); 5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(seg->getScalarT() > startT); 5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(distance >= startD); 5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(seg->fDistance > startD); 5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 580a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed *t = startT + (seg->getScalarT() - startT) * (distance - startD) / (seg->fDistance - startD); 5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return seg; 5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 584a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reedbool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent) { 58596fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == fPath) { 5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 5878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar length = this->getLength(); // call this to force computing it 5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count = fSegments.count(); 5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (count == 0 || length == 0) { 593a6d04d90e2f0a35698a7380cef8d622a8ee0b33fschenney@chromium.org return false; 5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // pin the distance to a legal range 5978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (distance < 0) { 5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com distance = 0; 5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else if (distance > length) { 6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com distance = length; 6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 602fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 6038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar t; 6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* seg = this->distanceToSegment(distance, &t); 6058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6065b94153a7b039a9269a8aabbe8f0da0e878e3978reed@google.com compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent); 6078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 6088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix, 6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com MatrixFlags flags) { 61296fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == fPath) { 613dfef456f183713da8c05fe5f3d252736a7776c8cdjsollen@google.com return false; 614dfef456f183713da8c05fe5f3d252736a7776c8cdjsollen@google.com } 615dfef456f183713da8c05fe5f3d252736a7776c8cdjsollen@google.com 6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint position; 6178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkVector tangent; 6188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (this->getPosTan(distance, &position, &tangent)) { 6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (matrix) { 6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (flags & kGetTangent_MatrixFlag) { 6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix->setSinCos(tangent.fY, tangent.fX, 0, 0); 6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix->reset(); 6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (flags & kGetPosition_MatrixFlag) { 6278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix->postTranslate(position.fX, position.fY); 6288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 6338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, 6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool startWithMoveTo) { 6378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(dst); 6388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar length = this->getLength(); // ensure we have built our segments 6408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (startD < 0) { 6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com startD = 0; 6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (stopD > length) { 6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com stopD = length; 6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6475cb00a95734143ca068960ead1ae94d0440c61dacaryclark if (startD > stopD) { 6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 650703348f5fac69dbedf22cda2ce264d2c9683bcf3caryclark if (!fSegments.count()) { 651703348f5fac69dbedf22cda2ce264d2c9683bcf3caryclark return false; 652703348f5fac69dbedf22cda2ce264d2c9683bcf3caryclark } 6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint p; 6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar startT, stopT; 6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* seg = this->distanceToSegment(startD, &startT); 6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* stopSeg = this->distanceToSegment(stopD, &stopT); 6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(seg <= stopSeg); 6598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (startWithMoveTo) { 66196fcdcc219d2a0d3579719b84b28bede76efba64halcanary compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, nullptr); 6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->moveTo(p); 6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (seg->fPtIndex == stopSeg->fPtIndex) { 66623d97760248300b7aec213a36f8b0485857240b5hstern SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst); 6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 66923d97760248300b7aec213a36f8b0485857240b5hstern SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst); 6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg = SkPathMeasure::NextSegment(seg); 6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com startT = 0; 6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (seg->fPtIndex < stopSeg->fPtIndex); 67323d97760248300b7aec213a36f8b0485857240b5hstern SkPathMeasure_segTo(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst); 6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::isClosed() { 6794727ba84944fbb1e674257d938e2d0a5f2b79a56Mike Reed (void)this->getLength(); // make sure we measure the current contour 6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return fIsClosed; 6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** Move to the next contour in the path. Return true if one exists, or false if 6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com we're done with the path. 6858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPathMeasure::nextContour() { 6874727ba84944fbb1e674257d938e2d0a5f2b79a56Mike Reed (void)this->getLength(); // make sure we measure the current contour 6884727ba84944fbb1e674257d938e2d0a5f2b79a56Mike Reed fLength = -1; // now signal that we should build the next set of segments 6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return this->getLength() > 0; 6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPathMeasure::dump() { 6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count()); 6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < fSegments.count(); i++) { 7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const Segment* seg = &fSegments[i]; 7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", 7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), 7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com seg->fType); 7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 709