blob: d09bf92c5c3733e0dafd0e8a6ef78f35b6c08466 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkPathMeasure.h"
11#include "SkGeometry.h"
12#include "SkPath.h"
13#include "SkTSearch.h"
14
15// these must be 0,1,2 since they are in our 2-bit field
16enum {
17 kLine_SegType,
reed@android.com8a1c16f2008-12-17 15:59:43 +000018 kQuad_SegType,
19 kCubic_SegType
20};
21
22#define kMaxTValue 32767
23
24static inline SkScalar tValue2Scalar(int t) {
25 SkASSERT((unsigned)t <= kMaxTValue);
26
27#ifdef SK_SCALAR_IS_FLOAT
28 return t * 3.05185e-5f; // t / 32767
29#else
30 return (t + (t >> 14)) << 1;
31#endif
32}
33
34SkScalar SkPathMeasure::Segment::getScalarT() const {
35 return tValue2Scalar(fTValue);
36}
37
38const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) {
39 unsigned ptIndex = seg->fPtIndex;
40
41 do {
42 ++seg;
43 } while (seg->fPtIndex == ptIndex);
44 return seg;
45}
46
47///////////////////////////////////////////////////////////////////////////////
48
49static inline int tspan_big_enough(int tspan) {
50 SkASSERT((unsigned)tspan <= kMaxTValue);
51 return tspan >> 10;
52}
53
54#if 0
55static inline bool tangents_too_curvy(const SkVector& tan0, SkVector& tan1) {
56 static const SkScalar kFlatEnoughTangentDotProd = SK_Scalar1 * 99 / 100;
57
58 SkASSERT(kFlatEnoughTangentDotProd > 0 &&
59 kFlatEnoughTangentDotProd < SK_Scalar1);
60
61 return SkPoint::DotProduct(tan0, tan1) < kFlatEnoughTangentDotProd;
62}
63#endif
64
65// can't use tangents, since we need [0..1..................2] to be seen
66// as definitely not a line (it is when drawn, but not parametrically)
67// so we compare midpoints
68#define CHEAP_DIST_LIMIT (SK_Scalar1/2) // just made this value up
69
70static bool quad_too_curvy(const SkPoint pts[3]) {
71 // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
72 // diff = -a/4 + b/2 - c/4
73 SkScalar dx = SkScalarHalf(pts[1].fX) -
74 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
75 SkScalar dy = SkScalarHalf(pts[1].fY) -
76 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
77
78 SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
79 return dist > CHEAP_DIST_LIMIT;
80}
81
82static bool cheap_dist_exceeds_limit(const SkPoint& pt,
83 SkScalar x, SkScalar y) {
84 SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
85 // just made up the 1/2
86 return dist > CHEAP_DIST_LIMIT;
87}
88
89static bool cubic_too_curvy(const SkPoint pts[4]) {
90 return cheap_dist_exceeds_limit(pts[1],
91 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
92 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
93 ||
94 cheap_dist_exceeds_limit(pts[2],
95 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
96 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
97}
98
99SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
100 SkScalar distance, int mint, int maxt, int ptIndex) {
101 if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
102 SkPoint tmp[5];
103 int halft = (mint + maxt) >> 1;
104
105 SkChopQuadAtHalf(pts, tmp);
106 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
107 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
108 } else {
109 SkScalar d = SkPoint::Distance(pts[0], pts[2]);
110 SkASSERT(d >= 0);
reed@google.comded44142012-04-27 20:22:07 +0000111 if (SkScalarNearlyZero(d)) {
112 d = 0;
113 }
114 SkScalar prevD = distance;
115 distance += d;
116 if (distance > prevD) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 Segment* seg = fSegments.append();
118 seg->fDistance = distance;
119 seg->fPtIndex = ptIndex;
120 seg->fType = kQuad_SegType;
121 seg->fTValue = maxt;
122 }
123 }
124 return distance;
125}
126
127SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
128 SkScalar distance, int mint, int maxt, int ptIndex) {
129 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
130 SkPoint tmp[7];
131 int halft = (mint + maxt) >> 1;
132
133 SkChopCubicAtHalf(pts, tmp);
134 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
135 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
136 } else {
137 SkScalar d = SkPoint::Distance(pts[0], pts[3]);
138 SkASSERT(d >= 0);
reed@google.comded44142012-04-27 20:22:07 +0000139 if (SkScalarNearlyZero(d)) {
140 d = 0;
141 }
142 SkScalar prevD = distance;
143 distance += d;
144 if (distance > prevD) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 Segment* seg = fSegments.append();
146 seg->fDistance = distance;
147 seg->fPtIndex = ptIndex;
148 seg->fType = kCubic_SegType;
149 seg->fTValue = maxt;
150 }
151 }
152 return distance;
153}
154
155void SkPathMeasure::buildSegments() {
156 SkPoint pts[4];
157 int ptIndex = fFirstPtIndex;
reed@google.comfab1ddd2012-04-20 15:10:32 +0000158 SkScalar distance = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 bool isClosed = fForceClosed;
160 bool firstMoveTo = ptIndex < 0;
161 Segment* seg;
162
reed@google.comfab1ddd2012-04-20 15:10:32 +0000163 /* Note:
164 * as we accumulate distance, we have to check that the result of +=
165 * actually made it larger, since a very small delta might be > 0, but
166 * still have no effect on distance (if distance >>> delta).
reed@google.comded44142012-04-27 20:22:07 +0000167 *
168 * We do this check below, and in compute_quad_segs and compute_cubic_segs
reed@google.comfab1ddd2012-04-20 15:10:32 +0000169 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 fSegments.reset();
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000171 bool done = false;
172 do {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 switch (fIter.next(pts)) {
174 case SkPath::kMove_Verb:
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000175 ptIndex += 1;
176 fPts.append(1, pts);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 if (!firstMoveTo) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000178 done = true;
179 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 }
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000181 firstMoveTo = false;
182 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183
reed@google.comfab1ddd2012-04-20 15:10:32 +0000184 case SkPath::kLine_Verb: {
185 SkScalar d = SkPoint::Distance(pts[0], pts[1]);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 SkASSERT(d >= 0);
reed@google.comfab1ddd2012-04-20 15:10:32 +0000187 SkScalar prevD = distance;
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000188 distance += d;
reed@google.comfab1ddd2012-04-20 15:10:32 +0000189 if (distance > prevD) {
190 seg = fSegments.append();
191 seg->fDistance = distance;
192 seg->fPtIndex = ptIndex;
193 seg->fType = kLine_SegType;
194 seg->fTValue = kMaxTValue;
195 fPts.append(1, pts + 1);
196 ptIndex++;
197 }
198 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199
reed@google.comfab1ddd2012-04-20 15:10:32 +0000200 case SkPath::kQuad_Verb: {
201 SkScalar prevD = distance;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 distance = this->compute_quad_segs(pts, distance, 0,
203 kMaxTValue, ptIndex);
reed@google.comfab1ddd2012-04-20 15:10:32 +0000204 if (distance > prevD) {
205 fPts.append(2, pts + 1);
206 ptIndex += 2;
207 }
208 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209
reed@google.comfab1ddd2012-04-20 15:10:32 +0000210 case SkPath::kCubic_Verb: {
211 SkScalar prevD = distance;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 distance = this->compute_cubic_segs(pts, distance, 0,
213 kMaxTValue, ptIndex);
reed@google.comfab1ddd2012-04-20 15:10:32 +0000214 if (distance > prevD) {
215 fPts.append(3, pts + 1);
216 ptIndex += 3;
217 }
218 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219
220 case SkPath::kClose_Verb:
221 isClosed = true;
222 break;
223
224 case SkPath::kDone_Verb:
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000225 done = true;
226 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 }
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000228 } while (!done);
229
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 fLength = distance;
231 fIsClosed = isClosed;
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000232 fFirstPtIndex = ptIndex;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233
234#ifdef SK_DEBUG
235 {
236 const Segment* seg = fSegments.begin();
237 const Segment* stop = fSegments.end();
238 unsigned ptIndex = 0;
239 SkScalar distance = 0;
240
241 while (seg < stop) {
242 SkASSERT(seg->fDistance > distance);
243 SkASSERT(seg->fPtIndex >= ptIndex);
244 SkASSERT(seg->fTValue > 0);
245
246 const Segment* s = seg;
247 while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex) {
248 SkASSERT(s[0].fType == s[1].fType);
249 SkASSERT(s[0].fTValue < s[1].fTValue);
250 s += 1;
251 }
252
253 distance = seg->fDistance;
254 ptIndex = seg->fPtIndex;
255 seg += 1;
256 }
257 // SkDebugf("\n");
258 }
259#endif
260}
261
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000262static void compute_pos_tan(const SkTDArray<SkPoint>& segmentPts, int ptIndex,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 int segType, SkScalar t, SkPoint* pos, SkVector* tangent) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000264 const SkPoint* pts = &segmentPts[ptIndex];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265
266 switch (segType) {
267 case kLine_SegType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 if (pos) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000269 pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
270 SkScalarInterp(pts[0].fY, pts[1].fY, t));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 }
272 if (tangent) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000273 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 }
275 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 case kQuad_SegType:
277 SkEvalQuadAt(pts, t, pos, tangent);
278 if (tangent) {
279 tangent->normalize();
280 }
281 break;
282 case kCubic_SegType:
283 SkEvalCubicAt(pts, t, pos, tangent, NULL);
284 if (tangent) {
285 tangent->normalize();
286 }
287 break;
288 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000289 SkDEBUGFAIL("unknown segType");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 }
291}
292
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000293static void seg_to(const SkTDArray<SkPoint>& segmentPts, int ptIndex,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 int segType, SkScalar startT, SkScalar stopT, SkPath* dst) {
295 SkASSERT(startT >= 0 && startT <= SK_Scalar1);
296 SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
297 SkASSERT(startT <= stopT);
298
299 if (SkScalarNearlyZero(stopT - startT)) {
300 return;
301 }
302
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000303 const SkPoint* pts = &segmentPts[ptIndex];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 SkPoint tmp0[7], tmp1[7];
305
306 switch (segType) {
307 case kLine_SegType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308 if (stopT == kMaxTValue) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000309 dst->lineTo(pts[1]);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 } else {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000311 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
312 SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 }
314 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315 case kQuad_SegType:
316 if (startT == 0) {
317 if (stopT == SK_Scalar1) {
318 dst->quadTo(pts[1], pts[2]);
319 } else {
320 SkChopQuadAt(pts, tmp0, stopT);
321 dst->quadTo(tmp0[1], tmp0[2]);
322 }
323 } else {
324 SkChopQuadAt(pts, tmp0, startT);
325 if (stopT == SK_Scalar1) {
326 dst->quadTo(tmp0[3], tmp0[4]);
327 } else {
328 SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT,
329 SK_Scalar1 - startT));
330 dst->quadTo(tmp1[1], tmp1[2]);
331 }
332 }
333 break;
334 case kCubic_SegType:
335 if (startT == 0) {
336 if (stopT == SK_Scalar1) {
337 dst->cubicTo(pts[1], pts[2], pts[3]);
338 } else {
339 SkChopCubicAt(pts, tmp0, stopT);
340 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
341 }
342 } else {
343 SkChopCubicAt(pts, tmp0, startT);
344 if (stopT == SK_Scalar1) {
345 dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
346 } else {
347 SkChopCubicAt(&tmp0[3], tmp1, SkScalarDiv(stopT - startT,
348 SK_Scalar1 - startT));
349 dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
350 }
351 }
352 break;
353 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000354 SkDEBUGFAIL("unknown segType");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 sk_throw();
356 }
357}
358
359////////////////////////////////////////////////////////////////////////////////
360////////////////////////////////////////////////////////////////////////////////
361
362SkPathMeasure::SkPathMeasure() {
363 fPath = NULL;
364 fLength = -1; // signal we need to compute it
365 fForceClosed = false;
366 fFirstPtIndex = -1;
367}
368
369SkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed) {
370 fPath = &path;
371 fLength = -1; // signal we need to compute it
372 fForceClosed = forceClosed;
373 fFirstPtIndex = -1;
374
375 fIter.setPath(path, forceClosed);
376}
377
378SkPathMeasure::~SkPathMeasure() {}
379
380/** Assign a new path, or null to have none.
381*/
382void SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
383 fPath = path;
384 fLength = -1; // signal we need to compute it
385 fForceClosed = forceClosed;
386 fFirstPtIndex = -1;
387
388 if (path) {
389 fIter.setPath(*path, forceClosed);
390 }
391 fSegments.reset();
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000392 fPts.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393}
394
395SkScalar SkPathMeasure::getLength() {
396 if (fPath == NULL) {
397 return 0;
398 }
399 if (fLength < 0) {
400 this->buildSegments();
401 }
402 SkASSERT(fLength >= 0);
403 return fLength;
404}
405
406const SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(
407 SkScalar distance, SkScalar* t) {
408 SkDEBUGCODE(SkScalar length = ) this->getLength();
409 SkASSERT(distance >= 0 && distance <= length);
410
411 const Segment* seg = fSegments.begin();
412 int count = fSegments.count();
413
414 int index = SkTSearch<SkScalar>(&seg->fDistance, count, distance,
415 sizeof(Segment));
416 // don't care if we hit an exact match or not, so we xor index if it is negative
417 index ^= (index >> 31);
418 seg = &seg[index];
419
420 // now interpolate t-values with the prev segment (if possible)
421 SkScalar startT = 0, startD = 0;
422 // check if the prev segment is legal, and references the same set of points
423 if (index > 0) {
424 startD = seg[-1].fDistance;
425 if (seg[-1].fPtIndex == seg->fPtIndex) {
426 SkASSERT(seg[-1].fType == seg->fType);
427 startT = seg[-1].getScalarT();
428 }
429 }
430
431 SkASSERT(seg->getScalarT() > startT);
432 SkASSERT(distance >= startD);
433 SkASSERT(seg->fDistance > startD);
434
435 *t = startT + SkScalarMulDiv(seg->getScalarT() - startT,
436 distance - startD,
437 seg->fDistance - startD);
438 return seg;
439}
440
441bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
442 SkVector* tangent) {
443 SkASSERT(fPath);
444 if (fPath == NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445 return false;
446 }
447
448 SkScalar length = this->getLength(); // call this to force computing it
449 int count = fSegments.count();
450
451 if (count == 0 || length == 0) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000452 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453 }
454
455 // pin the distance to a legal range
456 if (distance < 0) {
457 distance = 0;
458 } else if (distance > length) {
459 distance = length;
460 }
461
462 SkScalar t;
463 const Segment* seg = this->distanceToSegment(distance, &t);
464
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000465 compute_pos_tan(fPts, seg->fPtIndex, seg->fType, t, pos, tangent);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466 return true;
467}
468
469bool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix,
470 MatrixFlags flags) {
471 SkPoint position;
472 SkVector tangent;
473
474 if (this->getPosTan(distance, &position, &tangent)) {
475 if (matrix) {
476 if (flags & kGetTangent_MatrixFlag) {
477 matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
478 } else {
479 matrix->reset();
480 }
481 if (flags & kGetPosition_MatrixFlag) {
482 matrix->postTranslate(position.fX, position.fY);
483 }
484 }
485 return true;
486 }
487 return false;
488}
489
490bool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
491 bool startWithMoveTo) {
492 SkASSERT(dst);
493
494 SkScalar length = this->getLength(); // ensure we have built our segments
495
496 if (startD < 0) {
497 startD = 0;
498 }
499 if (stopD > length) {
500 stopD = length;
501 }
502 if (startD >= stopD) {
503 return false;
504 }
505
506 SkPoint p;
507 SkScalar startT, stopT;
508 const Segment* seg = this->distanceToSegment(startD, &startT);
509 const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
510 SkASSERT(seg <= stopSeg);
511
512 if (startWithMoveTo) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000513 compute_pos_tan(fPts, seg->fPtIndex, seg->fType, startT, &p, NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 dst->moveTo(p);
515 }
516
517 if (seg->fPtIndex == stopSeg->fPtIndex) {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000518 seg_to(fPts, seg->fPtIndex, seg->fType, startT, stopT, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519 } else {
520 do {
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000521 seg_to(fPts, seg->fPtIndex, seg->fType, startT, SK_Scalar1, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000522 seg = SkPathMeasure::NextSegment(seg);
523 startT = 0;
524 } while (seg->fPtIndex < stopSeg->fPtIndex);
schenney@chromium.orga6d04d92012-01-18 18:02:10 +0000525 seg_to(fPts, seg->fPtIndex, seg->fType, 0, stopT, dst);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 }
527 return true;
528}
529
530bool SkPathMeasure::isClosed() {
531 (void)this->getLength();
532 return fIsClosed;
533}
534
535/** Move to the next contour in the path. Return true if one exists, or false if
536 we're done with the path.
537*/
538bool SkPathMeasure::nextContour() {
539 fLength = -1;
540 return this->getLength() > 0;
541}
542
543///////////////////////////////////////////////////////////////////////////////
544///////////////////////////////////////////////////////////////////////////////
545
546#ifdef SK_DEBUG
547
548void SkPathMeasure::dump() {
549 SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
550
551 for (int i = 0; i < fSegments.count(); i++) {
552 const Segment* seg = &fSegments[i];
553 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
554 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
555 seg->fType);
556 }
557}
558
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559#endif