aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar schenney@chromium.org <schenney@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-01-18 18:02:10 +0000
committerGravatar schenney@chromium.org <schenney@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-01-18 18:02:10 +0000
commita6d04d90e2f0a35698a7380cef8d622a8ee0b33f (patch)
treec153962950ff83ca8fe049359667a251138b7c4b
parent8351aabbfe82a76a698fa2bde00d33c1174518cd (diff)
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
-rw-r--r--include/core/SkPath.h2
-rw-r--r--src/core/SkPathMeasure.cpp99
-rw-r--r--tests/PathMeasureTest.cpp2
3 files changed, 40 insertions, 63 deletions
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index ec79a49248..2774bea01a 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -753,7 +753,6 @@ private:
void computeBounds() const;
friend class Iter;
- void cons_moveto();
friend class SkPathStroker;
/* Append the first contour of path, ignoring path's initial point. If no
@@ -776,7 +775,6 @@ private:
//
inline void injectMoveToIfNeeded();
- friend const SkPoint* sk_get_path_points(const SkPath&, int index);
friend class SkAutoPathBoundsUpdate;
};
diff --git a/src/core/SkPathMeasure.cpp b/src/core/SkPathMeasure.cpp
index 3158925349..04d19c2ac5 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 @@ void SkPathMeasure::buildSegments() {
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 @@ void SkPathMeasure::buildSegments() {
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 @@ DONE:
#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 compute_pos_tan(const SkPath& path, int firstPtIndex, int ptIndex,
}
}
-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 @@ static void seg_to(const SkPath& src, int firstPtIndex, int ptIndex,
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 @@ void SkPathMeasure::setPath(const SkPath* path, bool forceClosed) {
fIter.setPath(*path, forceClosed);
}
fSegments.reset();
+ fPts.reset();
}
SkScalar SkPathMeasure::getLength() {
@@ -431,7 +418,6 @@ bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
SkVector* tangent) {
SkASSERT(fPath);
if (fPath == NULL) {
- EMPTY:
return false;
}
@@ -439,7 +425,7 @@ bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
int count = fSegments.count();
if (count == 0 || length == 0) {
- goto EMPTY;
+ return false;
}
// pin the distance to a legal range
@@ -452,8 +438,7 @@ bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos,
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 @@ bool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst,
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;
}
diff --git a/tests/PathMeasureTest.cpp b/tests/PathMeasureTest.cpp
index 6cc64fe394..2ff9f3a057 100644
--- a/tests/PathMeasureTest.cpp
+++ b/tests/PathMeasureTest.cpp
@@ -44,7 +44,6 @@ static void TestPathMeasure(skiatest::Reporter* reporter) {
#endif
}
-#if 0
// Test the behavior following a close not followed by a move.
path.reset();
path.lineTo(SK_Scalar1, 0);
@@ -129,7 +128,6 @@ static void TestPathMeasure(skiatest::Reporter* reporter) {
SkScalarNearlyEqual(position.fY, SK_Scalar1 * 2.0f, SK_Scalar1 * 0.0001));
REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1);
REPORTER_ASSERT(reporter, tangent.fY == 0);
-#endif
}
#include "TestClassDef.h"