|  | /* | 
|  | * Copyright 2014 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "SkCanvas.h" | 
|  | #include "SkDashPathEffect.h" | 
|  | #include "SkImageInfo.h" | 
|  | #include "SkMatrix.h" | 
|  | #include "SkPaint.h" | 
|  | #include "SkPath.h" | 
|  | #include "SkPathEffect.h" | 
|  | #include "SkPoint.h" | 
|  | #include "SkRect.h" | 
|  | #include "SkRefCnt.h" | 
|  | #include "SkScalar.h" | 
|  | #include "SkStrokeRec.h" | 
|  | #include "SkSurface.h" | 
|  | #include "SkTypes.h" | 
|  | #include "Test.h" | 
|  |  | 
|  | // crbug.com/348821 was rooted in SkDashPathEffect refusing to flatten and unflatten itself when | 
|  | // the effect is nonsense.  Here we test that it fails when passed nonsense parameters. | 
|  |  | 
|  | DEF_TEST(DashPathEffectTest_crbug_348821, r) { | 
|  | SkScalar intervals[] = { 1.76934361e+36f, 2.80259693e-45f };  // Values from bug. | 
|  | const int count = 2; | 
|  | SkScalar phase = SK_ScalarInfinity;  // Used to force a nonsense effect. | 
|  | sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, count, phase)); | 
|  |  | 
|  | REPORTER_ASSERT(r, dash == nullptr); | 
|  | } | 
|  |  | 
|  | // Test out the asPoint culling behavior. | 
|  | DEF_TEST(DashPathEffectTest_asPoints, r) { | 
|  |  | 
|  | const SkScalar intervals[] = { 1.0f, 1.0f }; | 
|  | const int count = 2; | 
|  | sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, count, 0.0f)); | 
|  |  | 
|  | SkRect cull = SkRect::MakeWH(1.0f, 1.0f); | 
|  |  | 
|  | const struct { | 
|  | SkPoint fPts[2]; | 
|  | bool    fExpectedResult; | 
|  | } testCases[] = { | 
|  | { { { -5.0f,  0.5f }, { -4.0f,  0.5f } }, false },   // off to the left | 
|  | { { {  4.0f,  0.5f }, {  5.0f,  0.5f } }, false },   // off to the right | 
|  | { { {  0.5f,  4.0f }, {  0.5f,  5.0f } }, false },   // off the bottom | 
|  | { { {  0.5f, -5.0f }, {  0.5f, -4.0f } }, false },   // off the top | 
|  | { { {  0.5f,  0.2f }, {  0.5f,  0.8f } }, true  },   // entirely inside vertical | 
|  | { { {  0.2f,  0.5f }, {  0.8f,  0.5f } }, true  },   // entirely inside horizontal | 
|  | { { {  0.5f, -5.0f }, {  0.5f,  5.0f } }, true  },   // straddles both sides vertically | 
|  | { { { -5.0f,  0.5f }, {  5.0f,  0.5f } }, true  },   // straddles both sides horizontally | 
|  | { { {  0.5f, -5.0f }, {  0.5f,  0.5f } }, true  },   // straddles top | 
|  | { { {  0.5f,  5.0f }, {  0.5f,  0.5f } }, true  },   // straddles bottom | 
|  | { { { -5.0f,  0.5f }, {  0.5f,  0.5f } }, true  },   // straddles left | 
|  | { { {  5.0f,  0.5f }, {  0.5f,  0.5f } }, true  },   // straddles right | 
|  | { { {  0.5f,  0.5f }, {  0.5f,  0.5f } }, false },   // zero length | 
|  | }; | 
|  |  | 
|  | SkPaint paint; | 
|  | paint.setStyle(SkPaint::kStroke_Style); | 
|  | paint.setStrokeWidth(1.0f); | 
|  | SkStrokeRec rec(paint); | 
|  |  | 
|  | static const int kNumMats = 3; | 
|  | SkMatrix mats[kNumMats]; | 
|  | mats[0].reset(); | 
|  | mats[1].setRotate(90, 0.5f, 0.5f); | 
|  | mats[2].setTranslate(10.0f, 10.0f); | 
|  |  | 
|  | for (int i = 0; i < kNumMats; ++i) { | 
|  | for (int j = 0; j < (int)SK_ARRAY_COUNT(testCases); ++j) { | 
|  | for (int k = 0; k < 2; ++k) {  // exercise alternating endpoints | 
|  | SkPathEffect::PointData results; | 
|  | SkPath src; | 
|  |  | 
|  | src.moveTo(testCases[j].fPts[k]); | 
|  | src.lineTo(testCases[j].fPts[(k+1)%2]); | 
|  |  | 
|  | bool actualResult = dash->asPoints(&results, src, rec, mats[i], &cull); | 
|  | if (i < 2) { | 
|  | REPORTER_ASSERT(r, actualResult == testCases[j].fExpectedResult); | 
|  | } else { | 
|  | // On the third pass all the lines should be outside the translated cull rect | 
|  | REPORTER_ASSERT(r, !actualResult); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DEF_TEST(DashPath_bug4871, r) { | 
|  | SkPath path; | 
|  | path.moveTo(30, 24); | 
|  | path.cubicTo(30.002f, 24, 30, 24, 30, 24); | 
|  | path.close(); | 
|  |  | 
|  | SkScalar intervals[2] = { 1, 1 }; | 
|  | sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, 2, 0)); | 
|  |  | 
|  | SkPaint paint; | 
|  | paint.setStyle(SkPaint::kStroke_Style); | 
|  | paint.setPathEffect(dash); | 
|  |  | 
|  | SkPath fill; | 
|  | paint.getFillPath(path, &fill); | 
|  | } | 
|  |  | 
|  | // Verify that long lines with many dashes don't cause overflows/OOMs. | 
|  | DEF_TEST(DashPathEffectTest_asPoints_limit, r) { | 
|  | sk_sp<SkSurface> surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(256, 256))); | 
|  | SkCanvas* canvas = surface->getCanvas(); | 
|  |  | 
|  | SkPaint p; | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  | // force the bounds to outset by a large amount | 
|  | p.setStrokeWidth(5.0e10f); | 
|  | const SkScalar intervals[] = { 1, 1 }; | 
|  | p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0)); | 
|  | canvas->drawLine(1, 1, 1, 5.0e10f, p); | 
|  | } | 
|  |  | 
|  | // This used to cause SkDashImpl to walk off the end of the intervals array, due to underflow | 
|  | // trying to substract a smal value from a large one in floats. | 
|  | DEF_TEST(DashCrazy_crbug_875494, r) { | 
|  | SkScalar vals[] = { 98, 94, 2888458849.f, 227, 0, 197 }; | 
|  | const int N = SK_ARRAY_COUNT(vals); | 
|  |  | 
|  | SkRect cull = SkRect::MakeXYWH(43,236,57,149); | 
|  | SkPath path; | 
|  | path.addRect(cull); | 
|  |  | 
|  | SkPath path2; | 
|  | SkPaint paint; | 
|  | paint.setStyle(SkPaint::kStroke_Style); | 
|  | paint.setPathEffect(SkDashPathEffect::Make(vals, N, 222)); | 
|  | paint.getFillPath(path, &path2, &cull); | 
|  | } |