1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkFloatBits.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCubicClipper.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker // Currently the supersampler blitter uses int16_t for its index into an array
26*c8dee2aaSAndroid Build Coastguard Worker // the width of the clip. Test that we don't crash/assert if we try to draw
27*c8dee2aaSAndroid Build Coastguard Worker // with a device/clip that is larger.
test_giantClip()28*c8dee2aaSAndroid Build Coastguard Worker static void test_giantClip() {
29*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bm;
30*c8dee2aaSAndroid Build Coastguard Worker bm.allocN32Pixels(64919, 1);
31*c8dee2aaSAndroid Build Coastguard Worker SkCanvas canvas(bm);
32*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(SK_ColorTRANSPARENT);
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
35*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
36*c8dee2aaSAndroid Build Coastguard Worker canvas.drawPath(SkPath::Polygon({{0,0}, {1,0}, {33,1}}, false), paint);
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker
PrintCurve(const char * name,const SkPoint crv[4])39*c8dee2aaSAndroid Build Coastguard Worker static void PrintCurve(const char *name, const SkPoint crv[4]) {
40*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n",
41*c8dee2aaSAndroid Build Coastguard Worker name,
42*c8dee2aaSAndroid Build Coastguard Worker (float)crv[0].fX, (float)crv[0].fY,
43*c8dee2aaSAndroid Build Coastguard Worker (float)crv[1].fX, (float)crv[1].fY,
44*c8dee2aaSAndroid Build Coastguard Worker (float)crv[2].fX, (float)crv[2].fY,
45*c8dee2aaSAndroid Build Coastguard Worker (float)crv[3].fX, (float)crv[3].fY);
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard Worker
CurvesAreEqual(const SkPoint c0[4],const SkPoint c1[4],float tol)50*c8dee2aaSAndroid Build Coastguard Worker static bool CurvesAreEqual(const SkPoint c0[4],
51*c8dee2aaSAndroid Build Coastguard Worker const SkPoint c1[4],
52*c8dee2aaSAndroid Build Coastguard Worker float tol) {
53*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; i++) {
54*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarAbs(c0[i].fX - c1[i].fX) > tol ||
55*c8dee2aaSAndroid Build Coastguard Worker SkScalarAbs(c0[i].fY - c1[i].fY) > tol
56*c8dee2aaSAndroid Build Coastguard Worker ) {
57*c8dee2aaSAndroid Build Coastguard Worker PrintCurve("c0", c0);
58*c8dee2aaSAndroid Build Coastguard Worker PrintCurve("c1", c1);
59*c8dee2aaSAndroid Build Coastguard Worker return false;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker }
62*c8dee2aaSAndroid Build Coastguard Worker return true;
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker
SetCurve(float x0,float y0,float x1,float y1,float x2,float y2,float x3,float y3,SkPoint crv[4])66*c8dee2aaSAndroid Build Coastguard Worker static SkPoint* SetCurve(float x0, float y0,
67*c8dee2aaSAndroid Build Coastguard Worker float x1, float y1,
68*c8dee2aaSAndroid Build Coastguard Worker float x2, float y2,
69*c8dee2aaSAndroid Build Coastguard Worker float x3, float y3,
70*c8dee2aaSAndroid Build Coastguard Worker SkPoint crv[4]) {
71*c8dee2aaSAndroid Build Coastguard Worker crv[0].fX = x0; crv[0].fY = y0;
72*c8dee2aaSAndroid Build Coastguard Worker crv[1].fX = x1; crv[1].fY = y1;
73*c8dee2aaSAndroid Build Coastguard Worker crv[2].fX = x2; crv[2].fY = y2;
74*c8dee2aaSAndroid Build Coastguard Worker crv[3].fX = x3; crv[3].fY = y3;
75*c8dee2aaSAndroid Build Coastguard Worker return crv;
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(ClipCubic,reporter)79*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(ClipCubic, reporter) {
80*c8dee2aaSAndroid Build Coastguard Worker static SkPoint crv[4] = {
81*c8dee2aaSAndroid Build Coastguard Worker { SkIntToScalar(0), SkIntToScalar(0) },
82*c8dee2aaSAndroid Build Coastguard Worker { SkIntToScalar(2), SkIntToScalar(3) },
83*c8dee2aaSAndroid Build Coastguard Worker { SkIntToScalar(1), SkIntToScalar(10) },
84*c8dee2aaSAndroid Build Coastguard Worker { SkIntToScalar(4), SkIntToScalar(12) }
85*c8dee2aaSAndroid Build Coastguard Worker };
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Worker SkCubicClipper clipper;
88*c8dee2aaSAndroid Build Coastguard Worker SkPoint clipped[4], shouldbe[4];
89*c8dee2aaSAndroid Build Coastguard Worker SkIRect clipRect;
90*c8dee2aaSAndroid Build Coastguard Worker bool success;
91*c8dee2aaSAndroid Build Coastguard Worker const float tol = 1e-4f;
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker // Test no clip, with plenty of room.
94*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, -2, 6, 14);
95*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
96*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
97*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == true);
98*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
99*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
100*c8dee2aaSAndroid Build Coastguard Worker
101*c8dee2aaSAndroid Build Coastguard Worker // Test no clip, touching first point.
102*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, 0, 6, 14);
103*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
104*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
105*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == true);
106*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
107*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
108*c8dee2aaSAndroid Build Coastguard Worker
109*c8dee2aaSAndroid Build Coastguard Worker // Test no clip, touching last point.
110*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, -2, 6, 12);
111*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
112*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
113*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == true);
114*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
115*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker // Test all clip.
118*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, 14, 6, 20);
119*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
120*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
121*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == false);
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker // Test clip at 1.
124*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, 1, 6, 14);
125*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
126*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
127*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == true);
128*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
129*c8dee2aaSAndroid Build Coastguard Worker 0.5126125216f, 1,
130*c8dee2aaSAndroid Build Coastguard Worker 1.841195941f, 4.337081432f,
131*c8dee2aaSAndroid Build Coastguard Worker 1.297019958f, 10.19801331f,
132*c8dee2aaSAndroid Build Coastguard Worker 4, 12,
133*c8dee2aaSAndroid Build Coastguard Worker shouldbe), tol));
134*c8dee2aaSAndroid Build Coastguard Worker
135*c8dee2aaSAndroid Build Coastguard Worker // Test clip at 2.
136*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, 2, 6, 14);
137*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
138*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
139*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == true);
140*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
141*c8dee2aaSAndroid Build Coastguard Worker 00.8412352204f, 2,
142*c8dee2aaSAndroid Build Coastguard Worker 1.767683744f, 5.400758266f,
143*c8dee2aaSAndroid Build Coastguard Worker 1.55052948f, 10.36701965f,
144*c8dee2aaSAndroid Build Coastguard Worker 4, 12,
145*c8dee2aaSAndroid Build Coastguard Worker shouldbe), tol));
146*c8dee2aaSAndroid Build Coastguard Worker
147*c8dee2aaSAndroid Build Coastguard Worker // Test clip at 11.
148*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, -2, 6, 11);
149*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
150*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
151*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == true);
152*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
153*c8dee2aaSAndroid Build Coastguard Worker 0, 0,
154*c8dee2aaSAndroid Build Coastguard Worker 1.742904663f, 2.614356995f,
155*c8dee2aaSAndroid Build Coastguard Worker 1.207521796f, 8.266430855f,
156*c8dee2aaSAndroid Build Coastguard Worker 3.026495695f, 11,
157*c8dee2aaSAndroid Build Coastguard Worker shouldbe), tol));
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker // Test clip at 10.
160*c8dee2aaSAndroid Build Coastguard Worker clipRect.setLTRB(-2, -2, 6, 10);
161*c8dee2aaSAndroid Build Coastguard Worker clipper.setClip(clipRect);
162*c8dee2aaSAndroid Build Coastguard Worker success = clipper.clipCubic(crv, clipped);
163*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, success == true);
164*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
165*c8dee2aaSAndroid Build Coastguard Worker 0, 0,
166*c8dee2aaSAndroid Build Coastguard Worker 1.551193237f, 2.326789856f,
167*c8dee2aaSAndroid Build Coastguard Worker 1.297736168f, 7.059780121f,
168*c8dee2aaSAndroid Build Coastguard Worker 2.505550385f, 10,
169*c8dee2aaSAndroid Build Coastguard Worker shouldbe), tol));
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker test_giantClip();
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(test_fuzz_crbug_698714,reporter)174*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(test_fuzz_crbug_698714, reporter) {
175*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(500, 500)));
176*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* canvas = surface->getCanvas();
177*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
178*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
179*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
180*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0,0
181*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0x43434343), SkBits2Float(0x43430143)); //195.263f, 195.005f
182*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0x43434343), SkBits2Float(0x43434343)); //195.263f, 195.263f
183*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0xb5434343), SkBits2Float(0x434300be)); //-7.2741e-07f, 195.003f
184*c8dee2aaSAndroid Build Coastguard Worker // 195.263f, 195.263f, -1.16387e-05f, 3.58641e-38f, 3.85088e-29f,1.86082e-39f
185*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(SkBits2Float(0x43434343), SkBits2Float(0x43434341),
186*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0xb74343bd), SkBits2Float(0x01434343),
187*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x10434343), SkBits2Float(0x00144332));
188*c8dee2aaSAndroid Build Coastguard Worker // 4.11823e-38f, 195.263f, 195.263f, 195.263f, -7.2741e-07f, 195.263f
189*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(SkBits2Float(0x016037c0), SkBits2Float(0x43434343),
190*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x43434343), SkBits2Float(0x43434343),
191*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0xb5434343), SkBits2Float(0x43434343));
192*c8dee2aaSAndroid Build Coastguard Worker // 195.263f, 195.263f, -1.16387e-05f, 3.58641e-38f, 195.263f, -2
193*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(SkBits2Float(0x43434344), SkBits2Float(0x43434341),
194*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0xb74343bd), SkBits2Float(0x01434343),
195*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x43434343), SkBits2Float(0xc0000014));
196*c8dee2aaSAndroid Build Coastguard Worker // -5.87228e+06f, 3.7773e-07f, 3.60231e-13f, -6.64511e+06f,2.77692e-15f, 2.48803e-15f
197*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(SkBits2Float(0xcab33535), SkBits2Float(0x34cacaca),
198*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x2acacaca), SkBits2Float(0xcacacae3),
199*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x27481927), SkBits2Float(0x27334805));
200*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0xb5434343), SkBits2Float(0x43434343)); //-7.2741e-07f, 195.263f
201*c8dee2aaSAndroid Build Coastguard Worker // 195.263f, 195.263f, -1.16387e-05f, 195.212f, 195.263f, -2
202*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(SkBits2Float(0x43434343), SkBits2Float(0x43434341),
203*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0xb74343b9), SkBits2Float(0x43433643),
204*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x43434343), SkBits2Float(0xc0000014));
205*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0xc7004343), SkBits2Float(0x27480527)); //-32835.3f, 2.77584e-15f
206*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0,0
207*c8dee2aaSAndroid Build Coastguard Worker path.close();
208*c8dee2aaSAndroid Build Coastguard Worker canvas->clipRect({0, 0, 65, 202});
209*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path, paint);
210*c8dee2aaSAndroid Build Coastguard Worker }
211*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(cubic_scan_error_crbug_844457_and_845489,reporter)212*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(cubic_scan_error_crbug_844457_and_845489, reporter) {
213*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
214*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* canvas = surface->getCanvas();
215*c8dee2aaSAndroid Build Coastguard Worker SkPaint p;
216*c8dee2aaSAndroid Build Coastguard Worker
217*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
218*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(-30/64.0, -31/64.0);
219*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(-31/64.0, -31/64,-31/64.0, -31/64,-31/64.0, 100);
220*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(100, 100);
221*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path, p);
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker // May need to define SK_RASTERIZE_EVEN_ROUNDING to trigger the need for this test
224*c8dee2aaSAndroid Build Coastguard Worker path.reset();
225*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(-30/64.0f, -31/64.0f + 1/256.0f);
226*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(-31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f,
227*c8dee2aaSAndroid Build Coastguard Worker -31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f,
228*c8dee2aaSAndroid Build Coastguard Worker -31/64.0f + 1/256.0f, 100);
229*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(100, 100);
230*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path, p);
231*c8dee2aaSAndroid Build Coastguard Worker }
232