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:
parent
d6195f956f
commit
fab1ddd3a8
@ -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;
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user