only add pathmeasure segment if the accumulated length was actually changed,

and not based on if the local length was > 0. This is necessary since 

    assert(delta > 0);  // true
    prevDistance = distance;
    distance += delta;
    assert(distance > prevDistance);    // not always true

Fixes https://bugs.webkit.org/show_bug.cgi?id=78979



git-svn-id: http://skia.googlecode.com/svn/trunk@3739 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2012-04-20 15:10:32 +00:00
parent d6195f956f
commit fab1ddd3a8
2 changed files with 69 additions and 19 deletions

View File

@ -147,11 +147,16 @@ SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4],
void SkPathMeasure::buildSegments() {
SkPoint pts[4];
int ptIndex = fFirstPtIndex;
SkScalar d, distance = 0;
SkScalar distance = 0;
bool isClosed = fForceClosed;
bool firstMoveTo = ptIndex < 0;
Segment* seg;
/* Note:
* as we accumulate distance, we have to check that the result of +=
* actually made it larger, since a very small delta might be > 0, but
* still have no effect on distance (if distance >>> delta).
*/
fSegments.reset();
bool done = false;
do {
@ -166,32 +171,41 @@ void SkPathMeasure::buildSegments() {
firstMoveTo = false;
break;
case SkPath::kLine_Verb:
d = SkPoint::Distance(pts[0], pts[1]);
case SkPath::kLine_Verb: {
SkScalar d = SkPoint::Distance(pts[0], pts[1]);
SkASSERT(d >= 0);
SkScalar prevD = distance;
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;
if (distance > prevD) {
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:
case SkPath::kQuad_Verb: {
SkScalar prevD = distance;
distance = this->compute_quad_segs(pts, distance, 0,
kMaxTValue, ptIndex);
fPts.append(2, pts + 1);
ptIndex += 2;
break;
if (distance > prevD) {
fPts.append(2, pts + 1);
ptIndex += 2;
}
} break;
case SkPath::kCubic_Verb:
case SkPath::kCubic_Verb: {
SkScalar prevD = distance;
distance = this->compute_cubic_segs(pts, distance, 0,
kMaxTValue, ptIndex);
fPts.append(3, pts + 1);
ptIndex += 3;
break;
if (distance > prevD) {
fPts.append(3, pts + 1);
ptIndex += 3;
}
} break;
case SkPath::kClose_Verb:
isClosed = true;

View File

@ -8,6 +8,40 @@
#include "Test.h"
#include "SkPathMeasure.h"
static void test_small_segment(skiatest::Reporter* reporter) {
#ifdef SK_SCALAR_IS_FLOAT
SkPath path;
const SkPoint pts[] = {
{ 100000, 100000},
// big jump between these points, makes a big segment
{ 1.0005, 0.9999 },
// tiny (non-zero) jump between these points
{ 1, 1 },
};
path.moveTo(pts[0]);
for (size_t i = 1; i < SK_ARRAY_COUNT(pts); ++i) {
path.lineTo(pts[i]);
}
SkPathMeasure meas(path, false);
/* this would assert (before a fix) because we added a segment with
the same length as the prev segment, due to the follow (bad) pattern
d = distance(pts[0], pts[1]);
distance += d;
seg->fDistance = distance;
SkASSERT(d > 0); // TRUE
SkASSERT(seg->fDistance > prevSeg->fDistance); // FALSE
This 2nd assert failes because (distance += d) didn't affect distance
because distance >>> d.
*/
meas.getLength();
#endif
}
static void TestPathMeasure(skiatest::Reporter* reporter) {
SkPath path;
@ -131,6 +165,8 @@ static void TestPathMeasure(skiatest::Reporter* reporter) {
SkFloatToScalar(0.0001f)));
REPORTER_ASSERT(reporter, tangent.fX == -SK_Scalar1);
REPORTER_ASSERT(reporter, tangent.fY == 0);
test_small_segment(reporter);
}
#include "TestClassDef.h"