Fixing the behavior of SkPathMeasure to reflect changes in SkPath::Iter.
This implementation modifies SkPath::Iter extensively to avoid copying
the points when used to measure path length.

BUG=446
TEST=tests/PathMeasureTest.cpp
Review URL: https://codereview.appspot.com/5533074

git-svn-id: http://skia.googlecode.com/svn/trunk@3062 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkPathMeasure.cpp b/src/core/SkPathMeasure.cpp
index 3158925..04d19c2 100644
--- a/src/core/SkPathMeasure.cpp
+++ b/src/core/SkPathMeasure.cpp
@@ -15,7 +15,6 @@
 // these must be 0,1,2 since they are in our 2-bit field
 enum {
     kLine_SegType,
-    kCloseLine_SegType,
     kQuad_SegType,
     kCubic_SegType
 };
@@ -154,40 +153,43 @@
     Segment*        seg;
 
     fSegments.reset();
-    for (;;) {
+    bool done = false;
+    do {
         switch (fIter.next(pts)) {
             case SkPath::kMove_Verb:
+                ptIndex += 1;
+                fPts.append(1, pts);
                 if (!firstMoveTo) {
-                    goto DONE;
+                    done = true;
+                    break;
                 }
-            ptIndex += 1;
-            firstMoveTo = false;
-            break;
+                firstMoveTo = false;
+                break;
 
             case SkPath::kLine_Verb:
                 d = SkPoint::Distance(pts[0], pts[1]);
                 SkASSERT(d >= 0);
-                if (!SkScalarNearlyZero(d)) {
-                    distance += d;
-                    seg = fSegments.append();
-                    seg->fDistance = distance;
-                    seg->fPtIndex = ptIndex;
-                    seg->fType = fIter.isCloseLine() ?
-                                    kCloseLine_SegType : kLine_SegType;
-                    seg->fTValue = kMaxTValue;
-                }
-                ptIndex += !fIter.isCloseLine();
+                distance += d;
+                seg = fSegments.append();
+                seg->fDistance = distance;
+                seg->fPtIndex = ptIndex;
+                seg->fType = kLine_SegType;
+                seg->fTValue = kMaxTValue;
+                fPts.append(1, pts + 1);
+                ptIndex++;
                 break;
 
             case SkPath::kQuad_Verb:
                 distance = this->compute_quad_segs(pts, distance, 0,
                                                    kMaxTValue, ptIndex);
+                fPts.append(2, pts + 1);
                 ptIndex += 2;
                 break;
 
             case SkPath::kCubic_Verb:
                 distance = this->compute_cubic_segs(pts, distance, 0,
                                                     kMaxTValue, ptIndex);
+                fPts.append(3, pts + 1);
                 ptIndex += 3;
                 break;
 
@@ -196,13 +198,14 @@
                 break;
                 
             case SkPath::kDone_Verb:
-                goto DONE;
+                done = true;
+                break;
         }
-    }
-DONE:
+    } while (!done);
+
     fLength = distance;
     fIsClosed = isClosed;
-    fFirstPtIndex = ptIndex + 1;
+    fFirstPtIndex = ptIndex;
 
 #ifdef SK_DEBUG
     {
@@ -232,31 +235,20 @@
 #endif
 }
 
-// marked as a friend in SkPath.h
-const SkPoint* sk_get_path_points(const SkPath& path, int index) {
-    return &path.fPts[index];
-}
-
-static void compute_pos_tan(const SkPath& path, int firstPtIndex, int ptIndex,
+static void compute_pos_tan(const SkTDArray<SkPoint>& segmentPts, int ptIndex,
                     int segType, SkScalar t, SkPoint* pos, SkVector* tangent) {
-    const SkPoint*  pts = sk_get_path_points(path, ptIndex);
+    const SkPoint*  pts = &segmentPts[ptIndex];
 
     switch (segType) {
         case kLine_SegType:
-        case kCloseLine_SegType: {
-            const SkPoint* endp = (segType == kLine_SegType) ?
-                                    &pts[1] :
-                                    sk_get_path_points(path, firstPtIndex);
-
             if (pos) {
-                pos->set(SkScalarInterp(pts[0].fX, endp->fX, t),
-                        SkScalarInterp(pts[0].fY, endp->fY, t));
+                pos->set(SkScalarInterp(pts[0].fX, pts[1].fX, t),
+                        SkScalarInterp(pts[0].fY, pts[1].fY, t));
             }
             if (tangent) {
-                tangent->setNormalize(endp->fX - pts[0].fX, endp->fY - pts[0].fY);
+                tangent->setNormalize(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY);
             }
             break;
-        }
         case kQuad_SegType:
             SkEvalQuadAt(pts, t, pos, tangent);
             if (tangent) {
@@ -274,7 +266,7 @@
     }
 }
 
-static void seg_to(const SkPath& src, int firstPtIndex, int ptIndex,
+static void seg_to(const SkTDArray<SkPoint>& segmentPts, int ptIndex,
                    int segType, SkScalar startT, SkScalar stopT, SkPath* dst) {
     SkASSERT(startT >= 0 && startT <= SK_Scalar1);
     SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
@@ -284,24 +276,18 @@
         return;
     }
 
-    const SkPoint*  pts = sk_get_path_points(src, ptIndex);
+    const SkPoint*  pts = &segmentPts[ptIndex];
     SkPoint         tmp0[7], tmp1[7];
 
     switch (segType) {
         case kLine_SegType:
-        case kCloseLine_SegType: {
-            const SkPoint* endp = (segType == kLine_SegType) ?
-                                    &pts[1] :
-                                    sk_get_path_points(src, firstPtIndex);
-
             if (stopT == kMaxTValue) {
-                dst->lineTo(*endp);
+                dst->lineTo(pts[1]);
             } else {
-                dst->lineTo(SkScalarInterp(pts[0].fX, endp->fX, stopT),
-                            SkScalarInterp(pts[0].fY, endp->fY, stopT));
+                dst->lineTo(SkScalarInterp(pts[0].fX, pts[1].fX, stopT),
+                            SkScalarInterp(pts[0].fY, pts[1].fY, stopT));
             }
             break;
-        }
         case kQuad_SegType:
             if (startT == 0) {
                 if (stopT == SK_Scalar1) {
@@ -379,6 +365,7 @@
         fIter.setPath(*path, forceClosed);
     }
     fSegments.reset();
+    fPts.reset();
 }
 
 SkScalar SkPathMeasure::getLength() {
@@ -431,7 +418,6 @@
                               SkVector* tangent) {
     SkASSERT(fPath);
     if (fPath == NULL) {
-    EMPTY:
         return false;
     }
 
@@ -439,7 +425,7 @@
     int         count = fSegments.count();
 
     if (count == 0 || length == 0) {
-        goto EMPTY;
+        return false;
     }
 
     // pin the distance to a legal range
@@ -452,8 +438,7 @@
     SkScalar        t;
     const Segment*  seg = this->distanceToSegment(distance, &t);
 
-    compute_pos_tan(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
-                    t, pos, tangent);
+    compute_pos_tan(fPts, seg->fPtIndex, seg->fType, t, pos, tangent);
     return true;
 }
 
@@ -501,23 +486,19 @@
     SkASSERT(seg <= stopSeg);
 
     if (startWithMoveTo) {
-        compute_pos_tan(*fPath, fSegments[0].fPtIndex, seg->fPtIndex,
-                        seg->fType, startT, &p, NULL);
+        compute_pos_tan(fPts, seg->fPtIndex, seg->fType, startT, &p, NULL);
         dst->moveTo(p);
     }
 
     if (seg->fPtIndex == stopSeg->fPtIndex) {
-        seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
-               startT, stopT, dst);
+        seg_to(fPts, seg->fPtIndex, seg->fType, startT, stopT, dst);
     } else {
         do {
-            seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
-                   startT, SK_Scalar1, dst);
+            seg_to(fPts, seg->fPtIndex, seg->fType, startT, SK_Scalar1, dst);
             seg = SkPathMeasure::NextSegment(seg);
             startT = 0;
         } while (seg->fPtIndex < stopSeg->fPtIndex);
-        seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType,
-               0, stopT, dst);
+        seg_to(fPts, seg->fPtIndex, seg->fType, 0, stopT, dst);
     }
     return true;
 }