gfx/skia/trunk/src/core/SkPathMeasure.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2008 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include "SkPathMeasure.h"
michael@0 11 #include "SkGeometry.h"
michael@0 12 #include "SkPath.h"
michael@0 13 #include "SkTSearch.h"
michael@0 14
michael@0 15 // these must be 0,1,2 since they are in our 2-bit field
michael@0 16 enum {
michael@0 17 kLine_SegType,
michael@0 18 kQuad_SegType,
michael@0 19 kCubic_SegType
michael@0 20 };
michael@0 21
michael@0 22 #define kMaxTValue 32767
michael@0 23
michael@0 24 static inline SkScalar tValue2Scalar(int t) {
michael@0 25 SkASSERT((unsigned)t <= kMaxTValue);
michael@0 26 return t * 3.05185e-5f; // t / 32767
michael@0 27 }
michael@0 28
michael@0 29 SkScalar SkPathMeasure::Segment::getScalarT() const {
michael@0 30 return tValue2Scalar(fTValue);
michael@0 31 }
michael@0 32
michael@0 33 const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg) {
michael@0 34 unsigned ptIndex = seg->fPtIndex;
michael@0 35
michael@0 36 do {
michael@0 37 ++seg;
michael@0 38 } while (seg->fPtIndex == ptIndex);
michael@0 39 return seg;
michael@0 40 }
michael@0 41
michael@0 42 ///////////////////////////////////////////////////////////////////////////////
michael@0 43
michael@0 44 static inline int tspan_big_enough(int tspan) {
michael@0 45 SkASSERT((unsigned)tspan <= kMaxTValue);
michael@0 46 return tspan >> 10;
michael@0 47 }
michael@0 48
michael@0 49 // can't use tangents, since we need [0..1..................2] to be seen
michael@0 50 // as definitely not a line (it is when drawn, but not parametrically)
michael@0 51 // so we compare midpoints
michael@0 52 #define CHEAP_DIST_LIMIT (SK_Scalar1/2) // just made this value up
michael@0 53
michael@0 54 static bool quad_too_curvy(const SkPoint pts[3]) {
michael@0 55 // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
michael@0 56 // diff = -a/4 + b/2 - c/4
michael@0 57 SkScalar dx = SkScalarHalf(pts[1].fX) -
michael@0 58 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
michael@0 59 SkScalar dy = SkScalarHalf(pts[1].fY) -
michael@0 60 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
michael@0 61
michael@0 62 SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
michael@0 63 return dist > CHEAP_DIST_LIMIT;
michael@0 64 }
michael@0 65
michael@0 66 static bool cheap_dist_exceeds_limit(const SkPoint& pt,
michael@0 67 SkScalar x, SkScalar y) {
michael@0 68 SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
michael@0 69 // just made up the 1/2
michael@0 70 return dist > CHEAP_DIST_LIMIT;
michael@0 71 }
michael@0 72
michael@0 73 static bool cubic_too_curvy(const SkPoint pts[4]) {
michael@0 74 return cheap_dist_exceeds_limit(pts[1],
michael@0 75 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
michael@0 76 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3))
michael@0 77 ||
michael@0 78 cheap_dist_exceeds_limit(pts[2],
michael@0 79 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
michael@0 80 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3));
michael@0 81 }
michael@0 82
michael@0 83 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3],
michael@0 84 SkScalar distance, int mint, int maxt, int ptIndex) {
michael@0 85 if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) {
michael@0 86 SkPoint tmp[5];
michael@0 87 int halft = (mint + maxt) >> 1;
michael@0 88
michael@0 89 SkChopQuadAtHalf(pts, tmp);
michael@0 90 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
michael@0 91 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
michael@0 92 } else {
michael@0 93 SkScalar d = SkPoint::Distance(pts[0], pts[2]);
michael@0 94 SkScalar prevD = distance;
michael@0 95 distance += d;
michael@0 96 if (distance > prevD) {
michael@0 97 Segment* seg = fSegments.append();
michael@0 98 seg->fDistance = distance;
michael@0 99 seg->fPtIndex = ptIndex;
michael@0 100 seg->fType = kQuad_SegType;
michael@0 101 seg->fTValue = maxt;
michael@0 102 }
michael@0 103 }
michael@0 104 return distance;
michael@0 105 }
michael@0 106
michael@0 107 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
michael@0 108 SkScalar distance, int mint, int maxt, int ptIndex) {
michael@0 109 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) {
michael@0 110 SkPoint tmp[7];
michael@0 111 int halft = (mint + maxt) >> 1;
michael@0 112
michael@0 113 SkChopCubicAtHalf(pts, tmp);
michael@0 114 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
michael@0 115 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
michael@0 116 } else {
michael@0 117 SkScalar d = SkPoint::Distance(pts[0], pts[3]);
michael@0 118 SkScalar prevD = distance;
michael@0 119 distance += d;
michael@0 120 if (distance > prevD) {
michael@0 121 Segment* seg = fSegments.append();
michael@0 122 seg->fDistance = distance;
michael@0 123 seg->fPtIndex = ptIndex;
michael@0 124 seg->fType = kCubic_SegType;
michael@0 125 seg->fTValue = maxt;
michael@0 126 }
michael@0 127 }
michael@0 128 return distance;
michael@0 129 }
michael@0 130
michael@0 131 void SkPathMeasure::buildSegments() {
michael@0 132 SkPoint pts[4];
michael@0 133 int ptIndex = fFirstPtIndex;
michael@0 134 SkScalar distance = 0;
michael@0 135 bool isClosed = fForceClosed;
michael@0 136 bool firstMoveTo = ptIndex < 0;
michael@0 137 Segment* seg;
michael@0 138
michael@0 139 /* Note:
michael@0 140 * as we accumulate distance, we have to check that the result of +=
michael@0 141 * actually made it larger, since a very small delta might be > 0, but
michael@0 142 * still have no effect on distance (if distance >>> delta).
michael@0 143 *
michael@0 144 * We do this check below, and in compute_quad_segs and compute_cubic_segs
michael@0 145 */
michael@0 146 fSegments.reset();
michael@0 147 bool done = false;
michael@0 148 do {
michael@0 149 switch (fIter.next(pts)) {
michael@0 150 case SkPath::kConic_Verb:
michael@0 151 SkASSERT(0);
michael@0 152 break;
michael@0 153 case SkPath::kMove_Verb:
michael@0 154 ptIndex += 1;
michael@0 155 fPts.append(1, pts);
michael@0 156 if (!firstMoveTo) {
michael@0 157 done = true;
michael@0 158 break;
michael@0 159 }
michael@0 160 firstMoveTo = false;
michael@0 161 break;
michael@0 162
michael@0 163 case SkPath::kLine_Verb: {
michael@0 164 SkScalar d = SkPoint::Distance(pts[0], pts[1]);
michael@0 165 SkASSERT(d >= 0);
michael@0 166 SkScalar prevD = distance;
michael@0 167 distance += d;
michael@0 168 if (distance > prevD) {
michael@0 169 seg = fSegments.append();
michael@0 170 seg->fDistance = distance;
michael@0 171 seg->fPtIndex = ptIndex;
michael@0 172 seg->fType = kLine_SegType;
michael@0 173 seg->fTValue = kMaxTValue;
michael@0 174 fPts.append(1, pts + 1);
michael@0 175 ptIndex++;
michael@0 176 }
michael@0 177 } break;
michael@0 178
michael@0 179 case SkPath::kQuad_Verb: {
michael@0 180 SkScalar prevD = distance;
michael@0 181 distance = this->compute_quad_segs(pts, distance, 0,
michael@0 182 kMaxTValue, ptIndex);
michael@0 183 if (distance > prevD) {
michael@0 184 fPts.append(2, pts + 1);
michael@0 185 ptIndex += 2;
michael@0 186 }
michael@0 187 } break;
michael@0 188
michael@0 189 case SkPath::kCubic_Verb: {
michael@0 190 SkScalar prevD = distance;
michael@0 191 distance = this->compute_cubic_segs(pts, distance, 0,
michael@0 192 kMaxTValue, ptIndex);
michael@0 193 if (distance > prevD) {
michael@0 194 fPts.append(3, pts + 1);
michael@0 195 ptIndex += 3;
michael@0 196 }
michael@0 197 } break;
michael@0 198
michael@0 199 case SkPath::kClose_Verb:
michael@0 200 isClosed = true;
michael@0 201 break;
michael@0 202
michael@0 203 case SkPath::kDone_Verb:
michael@0 204 done = true;
michael@0 205 break;
michael@0 206 }
michael@0 207 } while (!done);
michael@0 208
michael@0 209 fLength = distance;
michael@0 210 fIsClosed = isClosed;
michael@0 211 fFirstPtIndex = ptIndex;
michael@0 212
michael@0 213 #ifdef SK_DEBUG
michael@0 214 {
michael@0 215 const Segment* seg = fSegments.begin();
michael@0 216 const Segment* stop = fSegments.end();
michael@0 217 unsigned ptIndex = 0;
michael@0 218 SkScalar distance = 0;
michael@0 219
michael@0 220 while (seg < stop) {
michael@0 221 SkASSERT(seg->fDistance > distance);
michael@0 222 SkASSERT(seg->fPtIndex >= ptIndex);
michael@0 223 SkASSERT(seg->fTValue > 0);
michael@0 224
michael@0 225 const Segment* s = seg;
michael@0 226 while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex) {
michael@0 227 SkASSERT(s[0].fType == s[1].fType);
michael@0 228 SkASSERT(s[0].fTValue < s[1].fTValue);
michael@0 229 s += 1;
michael@0 230 }
michael@0 231
michael@0 232 distance = seg->fDistance;
michael@0 233 ptIndex = seg->fPtIndex;
michael@0 234 seg += 1;
michael@0 235 }
michael@0 236 // SkDebugf("\n");
michael@0 237 }
michael@0 238 #endif
michael@0 239 }
michael@0 240
michael@0 241 static void compute_pos_tan(const SkPoint pts[], int segType,
michael@0 242 SkScalar t, SkPoint* pos, SkVector* tangent) {
michael@0 243 switch (segType) {
michael@0 244 case kLine_SegType:
michael@0 245 if (pos) {
michael@0 246 pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
michael@0 247 SkScalarInterp(pts[0].fY, pts[1].fY, t));
michael@0 248 }
michael@0 249 if (tangent) {
michael@0 250 tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
michael@0 251 }
michael@0 252 break;
michael@0 253 case kQuad_SegType:
michael@0 254 SkEvalQuadAt(pts, t, pos, tangent);
michael@0 255 if (tangent) {
michael@0 256 tangent->normalize();
michael@0 257 }
michael@0 258 break;
michael@0 259 case kCubic_SegType:
michael@0 260 SkEvalCubicAt(pts, t, pos, tangent, NULL);
michael@0 261 if (tangent) {
michael@0 262 tangent->normalize();
michael@0 263 }
michael@0 264 break;
michael@0 265 default:
michael@0 266 SkDEBUGFAIL("unknown segType");
michael@0 267 }
michael@0 268 }
michael@0 269
michael@0 270 static void seg_to(const SkPoint pts[], int segType,
michael@0 271 SkScalar startT, SkScalar stopT, SkPath* dst) {
michael@0 272 SkASSERT(startT >= 0 && startT <= SK_Scalar1);
michael@0 273 SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
michael@0 274 SkASSERT(startT <= stopT);
michael@0 275
michael@0 276 if (startT == stopT) {
michael@0 277 return; // should we report this, to undo a moveTo?
michael@0 278 }
michael@0 279
michael@0 280 SkPoint tmp0[7], tmp1[7];
michael@0 281
michael@0 282 switch (segType) {
michael@0 283 case kLine_SegType:
michael@0 284 if (SK_Scalar1 == stopT) {
michael@0 285 dst->lineTo(pts[1]);
michael@0 286 } else {
michael@0 287 dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
michael@0 288 SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
michael@0 289 }
michael@0 290 break;
michael@0 291 case kQuad_SegType:
michael@0 292 if (0 == startT) {
michael@0 293 if (SK_Scalar1 == stopT) {
michael@0 294 dst->quadTo(pts[1], pts[2]);
michael@0 295 } else {
michael@0 296 SkChopQuadAt(pts, tmp0, stopT);
michael@0 297 dst->quadTo(tmp0[1], tmp0[2]);
michael@0 298 }
michael@0 299 } else {
michael@0 300 SkChopQuadAt(pts, tmp0, startT);
michael@0 301 if (SK_Scalar1 == stopT) {
michael@0 302 dst->quadTo(tmp0[3], tmp0[4]);
michael@0 303 } else {
michael@0 304 SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT,
michael@0 305 SK_Scalar1 - startT));
michael@0 306 dst->quadTo(tmp1[1], tmp1[2]);
michael@0 307 }
michael@0 308 }
michael@0 309 break;
michael@0 310 case kCubic_SegType:
michael@0 311 if (0 == startT) {
michael@0 312 if (SK_Scalar1 == stopT) {
michael@0 313 dst->cubicTo(pts[1], pts[2], pts[3]);
michael@0 314 } else {
michael@0 315 SkChopCubicAt(pts, tmp0, stopT);
michael@0 316 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
michael@0 317 }
michael@0 318 } else {
michael@0 319 SkChopCubicAt(pts, tmp0, startT);
michael@0 320 if (SK_Scalar1 == stopT) {
michael@0 321 dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
michael@0 322 } else {
michael@0 323 SkChopCubicAt(&tmp0[3], tmp1, SkScalarDiv(stopT - startT,
michael@0 324 SK_Scalar1 - startT));
michael@0 325 dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
michael@0 326 }
michael@0 327 }
michael@0 328 break;
michael@0 329 default:
michael@0 330 SkDEBUGFAIL("unknown segType");
michael@0 331 sk_throw();
michael@0 332 }
michael@0 333 }
michael@0 334
michael@0 335 ////////////////////////////////////////////////////////////////////////////////
michael@0 336 ////////////////////////////////////////////////////////////////////////////////
michael@0 337
michael@0 338 SkPathMeasure::SkPathMeasure() {
michael@0 339 fPath = NULL;
michael@0 340 fLength = -1; // signal we need to compute it
michael@0 341 fForceClosed = false;
michael@0 342 fFirstPtIndex = -1;
michael@0 343 }
michael@0 344
michael@0 345 SkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed) {
michael@0 346 fPath = &path;
michael@0 347 fLength = -1; // signal we need to compute it
michael@0 348 fForceClosed = forceClosed;
michael@0 349 fFirstPtIndex = -1;
michael@0 350
michael@0 351 fIter.setPath(path, forceClosed);
michael@0 352 }
michael@0 353
michael@0 354 SkPathMeasure::~SkPathMeasure() {}
michael@0 355
michael@0 356 /** Assign a new path, or null to have none.
michael@0 357 */
michael@0 358 void SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
michael@0 359 fPath = path;
michael@0 360 fLength = -1; // signal we need to compute it
michael@0 361 fForceClosed = forceClosed;
michael@0 362 fFirstPtIndex = -1;
michael@0 363
michael@0 364 if (path) {
michael@0 365 fIter.setPath(*path, forceClosed);
michael@0 366 }
michael@0 367 fSegments.reset();
michael@0 368 fPts.reset();
michael@0 369 }
michael@0 370
michael@0 371 SkScalar SkPathMeasure::getLength() {
michael@0 372 if (fPath == NULL) {
michael@0 373 return 0;
michael@0 374 }
michael@0 375 if (fLength < 0) {
michael@0 376 this->buildSegments();
michael@0 377 }
michael@0 378 SkASSERT(fLength >= 0);
michael@0 379 return fLength;
michael@0 380 }
michael@0 381
michael@0 382 const SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(
michael@0 383 SkScalar distance, SkScalar* t) {
michael@0 384 SkDEBUGCODE(SkScalar length = ) this->getLength();
michael@0 385 SkASSERT(distance >= 0 && distance <= length);
michael@0 386
michael@0 387 const Segment* seg = fSegments.begin();
michael@0 388 int count = fSegments.count();
michael@0 389
michael@0 390 int index = SkTSearch<SkScalar>(&seg->fDistance, count, distance, sizeof(Segment));
michael@0 391 // don't care if we hit an exact match or not, so we xor index if it is negative
michael@0 392 index ^= (index >> 31);
michael@0 393 seg = &seg[index];
michael@0 394
michael@0 395 // now interpolate t-values with the prev segment (if possible)
michael@0 396 SkScalar startT = 0, startD = 0;
michael@0 397 // check if the prev segment is legal, and references the same set of points
michael@0 398 if (index > 0) {
michael@0 399 startD = seg[-1].fDistance;
michael@0 400 if (seg[-1].fPtIndex == seg->fPtIndex) {
michael@0 401 SkASSERT(seg[-1].fType == seg->fType);
michael@0 402 startT = seg[-1].getScalarT();
michael@0 403 }
michael@0 404 }
michael@0 405
michael@0 406 SkASSERT(seg->getScalarT() > startT);
michael@0 407 SkASSERT(distance >= startD);
michael@0 408 SkASSERT(seg->fDistance > startD);
michael@0 409
michael@0 410 *t = startT + SkScalarMulDiv(seg->getScalarT() - startT,
michael@0 411 distance - startD,
michael@0 412 seg->fDistance - startD);
michael@0 413 return seg;
michael@0 414 }
michael@0 415
michael@0 416 bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
michael@0 417 SkVector* tangent) {
michael@0 418 if (NULL == fPath) {
michael@0 419 return false;
michael@0 420 }
michael@0 421
michael@0 422 SkScalar length = this->getLength(); // call this to force computing it
michael@0 423 int count = fSegments.count();
michael@0 424
michael@0 425 if (count == 0 || length == 0) {
michael@0 426 return false;
michael@0 427 }
michael@0 428
michael@0 429 // pin the distance to a legal range
michael@0 430 if (distance < 0) {
michael@0 431 distance = 0;
michael@0 432 } else if (distance > length) {
michael@0 433 distance = length;
michael@0 434 }
michael@0 435
michael@0 436 SkScalar t;
michael@0 437 const Segment* seg = this->distanceToSegment(distance, &t);
michael@0 438
michael@0 439 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, t, pos, tangent);
michael@0 440 return true;
michael@0 441 }
michael@0 442
michael@0 443 bool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix,
michael@0 444 MatrixFlags flags) {
michael@0 445 if (NULL == fPath) {
michael@0 446 return false;
michael@0 447 }
michael@0 448
michael@0 449 SkPoint position;
michael@0 450 SkVector tangent;
michael@0 451
michael@0 452 if (this->getPosTan(distance, &position, &tangent)) {
michael@0 453 if (matrix) {
michael@0 454 if (flags & kGetTangent_MatrixFlag) {
michael@0 455 matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
michael@0 456 } else {
michael@0 457 matrix->reset();
michael@0 458 }
michael@0 459 if (flags & kGetPosition_MatrixFlag) {
michael@0 460 matrix->postTranslate(position.fX, position.fY);
michael@0 461 }
michael@0 462 }
michael@0 463 return true;
michael@0 464 }
michael@0 465 return false;
michael@0 466 }
michael@0 467
michael@0 468 bool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
michael@0 469 bool startWithMoveTo) {
michael@0 470 SkASSERT(dst);
michael@0 471
michael@0 472 SkScalar length = this->getLength(); // ensure we have built our segments
michael@0 473
michael@0 474 if (startD < 0) {
michael@0 475 startD = 0;
michael@0 476 }
michael@0 477 if (stopD > length) {
michael@0 478 stopD = length;
michael@0 479 }
michael@0 480 if (startD >= stopD) {
michael@0 481 return false;
michael@0 482 }
michael@0 483
michael@0 484 SkPoint p;
michael@0 485 SkScalar startT, stopT;
michael@0 486 const Segment* seg = this->distanceToSegment(startD, &startT);
michael@0 487 const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
michael@0 488 SkASSERT(seg <= stopSeg);
michael@0 489
michael@0 490 if (startWithMoveTo) {
michael@0 491 compute_pos_tan(&fPts[seg->fPtIndex], seg->fType, startT, &p, NULL);
michael@0 492 dst->moveTo(p);
michael@0 493 }
michael@0 494
michael@0 495 if (seg->fPtIndex == stopSeg->fPtIndex) {
michael@0 496 seg_to(&fPts[seg->fPtIndex], seg->fType, startT, stopT, dst);
michael@0 497 } else {
michael@0 498 do {
michael@0 499 seg_to(&fPts[seg->fPtIndex], seg->fType, startT, SK_Scalar1, dst);
michael@0 500 seg = SkPathMeasure::NextSegment(seg);
michael@0 501 startT = 0;
michael@0 502 } while (seg->fPtIndex < stopSeg->fPtIndex);
michael@0 503 seg_to(&fPts[seg->fPtIndex], seg->fType, 0, stopT, dst);
michael@0 504 }
michael@0 505 return true;
michael@0 506 }
michael@0 507
michael@0 508 bool SkPathMeasure::isClosed() {
michael@0 509 (void)this->getLength();
michael@0 510 return fIsClosed;
michael@0 511 }
michael@0 512
michael@0 513 /** Move to the next contour in the path. Return true if one exists, or false if
michael@0 514 we're done with the path.
michael@0 515 */
michael@0 516 bool SkPathMeasure::nextContour() {
michael@0 517 fLength = -1;
michael@0 518 return this->getLength() > 0;
michael@0 519 }
michael@0 520
michael@0 521 ///////////////////////////////////////////////////////////////////////////////
michael@0 522 ///////////////////////////////////////////////////////////////////////////////
michael@0 523
michael@0 524 #ifdef SK_DEBUG
michael@0 525
michael@0 526 void SkPathMeasure::dump() {
michael@0 527 SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
michael@0 528
michael@0 529 for (int i = 0; i < fSegments.count(); i++) {
michael@0 530 const Segment* seg = &fSegments[i];
michael@0 531 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
michael@0 532 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(),
michael@0 533 seg->fType);
michael@0 534 }
michael@0 535 }
michael@0 536
michael@0 537 #endif

mercurial