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