1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2013 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 #include "tests/Test.h"
8*c8dee2aaSAndroid Build Coastguard Worker
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/SkMatrix.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkDashPathEffect.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkSurfaceGanesh.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "tests/CtsEnforcement.h"
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker struct GrContextOptions;
33*c8dee2aaSAndroid Build Coastguard Worker
test_drawPathEmpty(skiatest::Reporter *,SkCanvas * canvas)34*c8dee2aaSAndroid Build Coastguard Worker static void test_drawPathEmpty(skiatest::Reporter*, SkCanvas* canvas) {
35*c8dee2aaSAndroid Build Coastguard Worker // Filling an empty path should not crash.
36*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
37*c8dee2aaSAndroid Build Coastguard Worker SkRect emptyRect = SkRect::MakeEmpty();
38*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(emptyRect, paint);
39*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(SkPath(), paint);
40*c8dee2aaSAndroid Build Coastguard Worker canvas->drawOval(emptyRect, paint);
41*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(emptyRect, paint);
42*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker // Stroking an empty path should not crash.
45*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
46*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
47*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorGRAY);
48*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(SkIntToScalar(20));
49*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeJoin(SkPaint::kRound_Join);
50*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(emptyRect, paint);
51*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(SkPath(), paint);
52*c8dee2aaSAndroid Build Coastguard Worker canvas->drawOval(emptyRect, paint);
53*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(emptyRect, paint);
54*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker
fill_and_stroke(SkCanvas * canvas,const SkPath & p1,const SkPath & p2,sk_sp<SkPathEffect> effect)57*c8dee2aaSAndroid Build Coastguard Worker static void fill_and_stroke(SkCanvas* canvas, const SkPath& p1, const SkPath& p2,
58*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkPathEffect> effect) {
59*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
60*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
61*c8dee2aaSAndroid Build Coastguard Worker paint.setPathEffect(effect);
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(p1, paint);
64*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(p2, paint);
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
67*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(p1, paint);
68*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(p2, paint);
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker
test_drawSameRectOvals(skiatest::Reporter *,SkCanvas * canvas)71*c8dee2aaSAndroid Build Coastguard Worker static void test_drawSameRectOvals(skiatest::Reporter*, SkCanvas* canvas) {
72*c8dee2aaSAndroid Build Coastguard Worker // Drawing ovals with similar bounds but different points order should not crash.
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard Worker SkPath oval1, oval2;
75*c8dee2aaSAndroid Build Coastguard Worker const SkRect rect = SkRect::MakeWH(100, 50);
76*c8dee2aaSAndroid Build Coastguard Worker oval1.addOval(rect, SkPathDirection::kCW);
77*c8dee2aaSAndroid Build Coastguard Worker oval2.addOval(rect, SkPathDirection::kCCW);
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker fill_and_stroke(canvas, oval1, oval2, nullptr);
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker const SkScalar intervals[] = { 1, 1 };
82*c8dee2aaSAndroid Build Coastguard Worker fill_and_stroke(canvas, oval1, oval2, SkDashPathEffect::Make(intervals, 2, 0));
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker
DEF_GANESH_TEST_FOR_GL_CONTEXT(GpuDrawPath,reporter,ctxInfo,CtsEnforcement::kNever)85*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_GL_CONTEXT(GpuDrawPath, reporter, ctxInfo, CtsEnforcement::kNever) {
86*c8dee2aaSAndroid Build Coastguard Worker for (auto& test_func : { &test_drawPathEmpty, &test_drawSameRectOvals }) {
87*c8dee2aaSAndroid Build Coastguard Worker for (auto& sampleCount : {1, 4, 16}) {
88*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeN32Premul(255, 255);
89*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::RenderTarget(
90*c8dee2aaSAndroid Build Coastguard Worker ctxInfo.directContext(), skgpu::Budgeted::kNo, info, sampleCount, nullptr));
91*c8dee2aaSAndroid Build Coastguard Worker if (!surface) {
92*c8dee2aaSAndroid Build Coastguard Worker continue;
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker test_func(reporter, surface->getCanvas());
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(GrDrawCollapsedPath,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)99*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_ALL_CONTEXTS(GrDrawCollapsedPath,
100*c8dee2aaSAndroid Build Coastguard Worker reporter,
101*c8dee2aaSAndroid Build Coastguard Worker ctxInfo,
102*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_T) {
103*c8dee2aaSAndroid Build Coastguard Worker // From https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=37330, it's possible for a convex
104*c8dee2aaSAndroid Build Coastguard Worker // path to be accepted by AAConvexPathRenderer, then be transformed to something without a
105*c8dee2aaSAndroid Build Coastguard Worker // computable first direction by a perspective matrix.
106*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
107*c8dee2aaSAndroid Build Coastguard Worker auto dContext = ctxInfo.directContext();
108*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info));
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
111*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
114*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(0, 0);
115*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(50, 0);
116*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(0, 50);
117*c8dee2aaSAndroid Build Coastguard Worker path.close();
118*c8dee2aaSAndroid Build Coastguard Worker
119*c8dee2aaSAndroid Build Coastguard Worker SkMatrix m;
120*c8dee2aaSAndroid Build Coastguard Worker m.setAll( 0.966006875f , -0.125156224f , 72.0899811f,
121*c8dee2aaSAndroid Build Coastguard Worker -0.00885376986f , -0.112347461f , 64.7121124f,
122*c8dee2aaSAndroid Build Coastguard Worker -8.94321693e-06f, -0.00173384184f, 0.998692870f);
123*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->setMatrix(m);
124*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->drawPath(path, paint);
125*c8dee2aaSAndroid Build Coastguard Worker dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
126*c8dee2aaSAndroid Build Coastguard Worker }
127*c8dee2aaSAndroid Build Coastguard Worker
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(PathTest_CrBug1232834,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)128*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_ALL_CONTEXTS(PathTest_CrBug1232834,
129*c8dee2aaSAndroid Build Coastguard Worker reporter,
130*c8dee2aaSAndroid Build Coastguard Worker ctxInfo,
131*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kApiLevel_T) {
132*c8dee2aaSAndroid Build Coastguard Worker // AAHairlinePathRenderer chops this path to quads that include infinities (and then NaNs).
133*c8dee2aaSAndroid Build Coastguard Worker // It used to trigger asserts, now the degenerate quad segments should cause it to be rejected.
134*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
135*c8dee2aaSAndroid Build Coastguard Worker auto dContext = ctxInfo.directContext();
136*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info));
137*c8dee2aaSAndroid Build Coastguard Worker
138*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
139*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
140*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
141*c8dee2aaSAndroid Build Coastguard Worker
142*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
143*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(9.0072E15f, 60);
144*c8dee2aaSAndroid Build Coastguard Worker path.cubicTo(0, 3.40282e+38f, 0, 3.40282e+38f, 0, 0);
145*c8dee2aaSAndroid Build Coastguard Worker
146*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->drawPath(path, paint);
147*c8dee2aaSAndroid Build Coastguard Worker dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(StrokeCircle_Bug356182429,reporter,ctxInfo,CtsEnforcement::kNextRelease)150*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(StrokeCircle_Bug356182429,
151*c8dee2aaSAndroid Build Coastguard Worker reporter,
152*c8dee2aaSAndroid Build Coastguard Worker ctxInfo,
153*c8dee2aaSAndroid Build Coastguard Worker CtsEnforcement::kNextRelease) {
154*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
155*c8dee2aaSAndroid Build Coastguard Worker auto dContext = ctxInfo.directContext();
156*c8dee2aaSAndroid Build Coastguard Worker auto surface(SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, info));
157*c8dee2aaSAndroid Build Coastguard Worker
158*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
159*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
160*c8dee2aaSAndroid Build Coastguard Worker paint.setStyle(SkPaint::kStroke_Style);
161*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeCap(SkPaint::kRound_Cap);
162*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(15.4375f);
163*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeMiter(2.85207834E9f);
164*c8dee2aaSAndroid Build Coastguard Worker
165*c8dee2aaSAndroid Build Coastguard Worker // This draw ends up in the CircleOp, and asserted because round caps are requested,
166*c8dee2aaSAndroid Build Coastguard Worker // but the stroke is ultimately excluded (due to the negative inner stroke radius).
167*c8dee2aaSAndroid Build Coastguard Worker // Along the way, several other bad things happen (but they don't appear relevant to the bug):
168*c8dee2aaSAndroid Build Coastguard Worker // - MakeArcOp asserts that sweepAngle is non-zero (and it is). After converting degrees to
169*c8dee2aaSAndroid Build Coastguard Worker // radians, it flushes to zero, so the sweep angle stored in the ArcParams is zero.
170*c8dee2aaSAndroid Build Coastguard Worker // - The radius of the "circle" is tiny, but it *also* flushes to zero when we call
171*c8dee2aaSAndroid Build Coastguard Worker // `viewMatrix.mapRadius()`, despite the view matrix being identity. This is a result of
172*c8dee2aaSAndroid Build Coastguard Worker // the implementation of mapRadius (computing geometric mean of the lengths of two vectors).
173*c8dee2aaSAndroid Build Coastguard Worker SkRect oval = SkRect::MakeLTRB(0, 0, 1.83670992E-40f, 1.21223864E-38f);
174*c8dee2aaSAndroid Build Coastguard Worker surface->getCanvas()->drawArc(oval, 8.17909887E-41f, 2.24207754E-44f, false, paint);
175*c8dee2aaSAndroid Build Coastguard Worker dContext->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
176*c8dee2aaSAndroid Build Coastguard Worker }
177