1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "Test.h"
9 
10 #include "SkDashPathEffect.h"
11 #include "SkWriteBuffer.h"
12 #include "SkStrokeRec.h"
13 
14 // crbug.com/348821 was rooted in SkDashPathEffect refusing to flatten and unflatten itself when
15 // fInitialDashLength < 0 (a signal the effect is nonsense).  Here we test that it flattens.
16 
DEF_TEST(DashPathEffectTest_crbug_348821,r)17 DEF_TEST(DashPathEffectTest_crbug_348821, r) {
18     SkScalar intervals[] = { 1.76934361e+36f, 2.80259693e-45f };  // Values from bug.
19     const int count = 2;
20     SkScalar phase = SK_ScalarInfinity;  // Used to force the bad fInitialDashLength = -1 path.
21     SkAutoTUnref<SkPathEffect> dash(SkDashPathEffect::Create(intervals, count, phase));
22 
23     // nullptr -> refuses to work with flattening framework.
24     REPORTER_ASSERT(r, dash->getFactory() != nullptr);
25 
26     SkWriteBuffer buffer;
27     buffer.writeFlattenable(dash);
28     REPORTER_ASSERT(r, buffer.bytesWritten() > 12);  // We'd write 12 if broken, >=40 if not.
29 }
30 
31 // Test out the asPoint culling behavior.
DEF_TEST(DashPathEffectTest_asPoints,r)32 DEF_TEST(DashPathEffectTest_asPoints, r) {
33 
34     const SkScalar intervals[] = { 1.0f, 1.0f };
35     const int count = 2;
36     SkAutoTUnref<SkPathEffect> dash(SkDashPathEffect::Create(intervals, count, 0.0f));
37 
38     SkRect cull = SkRect::MakeWH(1.0f, 1.0f);
39 
40     const struct {
41         SkPoint fPts[2];
42         bool    fExpectedResult;
43     } testCases[] = {
44         { { { -5.0f,  0.5f }, { -4.0f,  0.5f } }, false },   // off to the left
45         { { {  4.0f,  0.5f }, {  5.0f,  0.5f } }, false },   // off to the right
46         { { {  0.5f,  4.0f }, {  0.5f,  5.0f } }, false },   // off the bottom
47         { { {  0.5f, -5.0f }, {  0.5f, -4.0f } }, false },   // off the top
48         { { {  0.5f,  0.2f }, {  0.5f,  0.8f } }, true  },   // entirely inside vertical
49         { { {  0.2f,  0.5f }, {  0.8f,  0.5f } }, true  },   // entirely inside horizontal
50         { { {  0.5f, -5.0f }, {  0.5f,  5.0f } }, true  },   // straddles both sides vertically
51         { { { -5.0f,  0.5f }, {  5.0f,  0.5f } }, true  },   // straddles both sides horizontally
52         { { {  0.5f, -5.0f }, {  0.5f,  0.5f } }, true  },   // straddles top
53         { { {  0.5f,  5.0f }, {  0.5f,  0.5f } }, true  },   // straddles bottom
54         { { { -5.0f,  0.5f }, {  0.5f,  0.5f } }, true  },   // straddles left
55         { { {  5.0f,  0.5f }, {  0.5f,  0.5f } }, true  },   // straddles right
56         { { {  0.5f,  0.5f }, {  0.5f,  0.5f } }, false },   // zero length
57     };
58 
59     SkPaint paint;
60     paint.setStyle(SkPaint::kStroke_Style);
61     paint.setStrokeWidth(1.0f);
62     SkStrokeRec rec(paint);
63 
64     static const int kNumMats = 3;
65     SkMatrix mats[kNumMats];
66     mats[0].reset();
67     mats[1].setRotate(90, 0.5f, 0.5f);
68     mats[2].setTranslate(10.0f, 10.0f);
69 
70     for (int i = 0; i < kNumMats; ++i) {
71         for (int j = 0; j < (int)SK_ARRAY_COUNT(testCases); ++j) {
72             for (int k = 0; k < 2; ++k) {  // exercise alternating endpoints
73                 SkPathEffect::PointData results;
74                 SkPath src;
75 
76                 src.moveTo(testCases[j].fPts[k]);
77                 src.lineTo(testCases[j].fPts[(k+1)%2]);
78 
79                 bool actualResult = dash->asPoints(&results, src, rec, mats[i], &cull);
80                 if (i < 2) {
81                     REPORTER_ASSERT(r, actualResult == testCases[j].fExpectedResult);
82                 } else {
83                     // On the third pass all the lines should be outside the translated cull rect
84                     REPORTER_ASSERT(r, !actualResult);
85                 }
86             }
87         }
88     }
89 }
90 
DEF_TEST(DashPath_bug4871,r)91 DEF_TEST(DashPath_bug4871, r) {
92     SkPath path;
93     path.moveTo(30, 24);
94     path.cubicTo(30.002f, 24, 30, 24, 30, 24);
95     path.close();
96 
97     SkScalar intervals[2] = { 1, 1 };
98     SkAutoTUnref<SkPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0));
99 
100     SkPaint paint;
101     paint.setStyle(SkPaint::kStroke_Style);
102     paint.setPathEffect(dash);
103 
104     SkPath fill;
105     paint.getFillPath(path, &fill);
106 }
107