aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/effects/SkDashPathEffect.cpp24
-rw-r--r--tests/DrawPathTest.cpp23
2 files changed, 39 insertions, 8 deletions
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp
index e6f6afaf07..c1bb705818 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -16,14 +16,21 @@ static inline int is_even(int x) {
}
static SkScalar FindFirstInterval(const SkScalar intervals[], SkScalar phase,
- int32_t* index) {
- int i;
-
- for (i = 0; phase > intervals[i]; i++) {
- phase -= intervals[i];
+ int32_t* index, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (phase > intervals[i]) {
+ phase -= intervals[i];
+ } else {
+ *index = i;
+ return intervals[i] - phase;
+ }
}
- *index = i;
- return intervals[i] - phase;
+ // If we get here, phase "appears" to be larger than our length. This
+ // shouldn't happen with perfect precision, but we can accumulate errors
+ // during the initial length computation (rounding can make our sum be too
+ // big or too small. In that event, we just have to eat the error here.
+ *index = 0;
+ return intervals[0];
}
SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
@@ -67,7 +74,8 @@ SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
}
SkASSERT(phase >= 0 && phase < len);
- fInitialDashLength = FindFirstInterval(intervals, phase, &fInitialDashIndex);
+ fInitialDashLength = FindFirstInterval(intervals, phase,
+ &fInitialDashIndex, count);
SkASSERT(fInitialDashLength >= 0);
SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount);
diff --git a/tests/DrawPathTest.cpp b/tests/DrawPathTest.cpp
index 947bf88029..f421ee87b6 100644
--- a/tests/DrawPathTest.cpp
+++ b/tests/DrawPathTest.cpp
@@ -137,6 +137,28 @@ static void test_bug533(skiatest::Reporter* reporter) {
#endif
}
+static void test_crbug_140642(skiatest::Reporter* reporter) {
+ /*
+ * We used to see this construct, and due to rounding as we accumulated
+ * our length, the loop where we apply the phase would run off the end of
+ * the array, since it relied on just -= each interval value, which did not
+ * behave as "expected". Now the code explicitly checks for walking off the
+ * end of that array.
+
+ * A different (better) fix might be to rewrite dashing to do all of its
+ * length/phase/measure math using double, but this may need to be
+ * coordinated with SkPathMeasure, to be consistent between the two.
+
+ <path stroke="mintcream" stroke-dasharray="27734 35660 2157846850 247"
+ stroke-dashoffset="-248.135982067">
+ */
+
+#ifdef SK_SCALAR_IS_FLOAT
+ const SkScalar vals[] = { 27734, 35660, 2157846850.0f, 247 };
+ SkDashPathEffect dontAssert(vals, 4, -248.135982067f);
+#endif
+}
+
static void test_crbug_124652(skiatest::Reporter* reporter) {
#ifdef SK_SCALAR_IS_FLOAT
/*
@@ -185,6 +207,7 @@ static void TestDrawPath(skiatest::Reporter* reporter) {
test_bug533(reporter);
test_bigcubic(reporter);
test_crbug_124652(reporter);
+ test_crbug_140642(reporter);
test_inversepathwithclip(reporter);
// test_crbug131181(reporter);
}