xref: /aosp_15_r20/external/skia/gm/nonclosedpaths.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathBuilder.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker // This GM tests a grab-bag of non-closed paths. All these paths look like
20*c8dee2aaSAndroid Build Coastguard Worker // closed rects, but they don't call path.close(). Depending on the stroke
21*c8dee2aaSAndroid Build Coastguard Worker // settings these slightly different paths give widely different results.
22*c8dee2aaSAndroid Build Coastguard Worker class NonClosedPathsGM: public GM {
23*c8dee2aaSAndroid Build Coastguard Worker public:
NonClosedPathsGM()24*c8dee2aaSAndroid Build Coastguard Worker     NonClosedPathsGM() {}
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker     enum ClosureType {
27*c8dee2aaSAndroid Build Coastguard Worker         TotallyNonClosed,  // The last point doesn't coincide with the first one in the contour.
28*c8dee2aaSAndroid Build Coastguard Worker                            // The path looks not closed at all.
29*c8dee2aaSAndroid Build Coastguard Worker 
30*c8dee2aaSAndroid Build Coastguard Worker         FakeCloseCorner,   // The last point coincides with the first one at a corner.
31*c8dee2aaSAndroid Build Coastguard Worker                            // The path looks closed, but final rendering has 2 ends with cap.
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker         FakeCloseMiddle,   // The last point coincides with the first one in the middle of a line.
34*c8dee2aaSAndroid Build Coastguard Worker                            // The path looks closed, and the final rendering looks closed too.
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker         kClosureTypeCount
37*c8dee2aaSAndroid Build Coastguard Worker     };
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const40*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("nonclosedpaths"); }
41*c8dee2aaSAndroid Build Coastguard Worker 
42*c8dee2aaSAndroid Build Coastguard Worker     // 12 * 18 + 3 cases, every case is 100 * 100 pixels.
getISize()43*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return SkISize::Make(1220, 1920); }
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker     // Use rect-like geometry for non-closed path, for right angles make it
46*c8dee2aaSAndroid Build Coastguard Worker     // easier to show the visual difference of lineCap and lineJoin.
MakePath(ClosureType type)47*c8dee2aaSAndroid Build Coastguard Worker     static SkPath MakePath(ClosureType type) {
48*c8dee2aaSAndroid Build Coastguard Worker         SkPathBuilder path;
49*c8dee2aaSAndroid Build Coastguard Worker         if (FakeCloseMiddle == type) {
50*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(30, 50);
51*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(30, 30);
52*c8dee2aaSAndroid Build Coastguard Worker         } else {
53*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(30, 30);
54*c8dee2aaSAndroid Build Coastguard Worker         }
55*c8dee2aaSAndroid Build Coastguard Worker         path.lineTo(70, 30);
56*c8dee2aaSAndroid Build Coastguard Worker         path.lineTo(70, 70);
57*c8dee2aaSAndroid Build Coastguard Worker         path.lineTo(30, 70);
58*c8dee2aaSAndroid Build Coastguard Worker         path.lineTo(30, 50);
59*c8dee2aaSAndroid Build Coastguard Worker         if (FakeCloseCorner == type) {
60*c8dee2aaSAndroid Build Coastguard Worker             path.lineTo(30, 30);
61*c8dee2aaSAndroid Build Coastguard Worker         }
62*c8dee2aaSAndroid Build Coastguard Worker         return path.detach();
63*c8dee2aaSAndroid Build Coastguard Worker     }
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker     // Set the location for the current test on the canvas
SetLocation(SkCanvas * canvas,int counter,int lineNum)66*c8dee2aaSAndroid Build Coastguard Worker     static void SetLocation(SkCanvas* canvas, int counter, int lineNum) {
67*c8dee2aaSAndroid Build Coastguard Worker         SkScalar x = SK_Scalar1 * 100 * (counter % lineNum) + 10 + SK_Scalar1 / 4;
68*c8dee2aaSAndroid Build Coastguard Worker         SkScalar y = SK_Scalar1 * 100 * (counter / lineNum) + 10 + 3 * SK_Scalar1 / 4;
69*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(x, y);
70*c8dee2aaSAndroid Build Coastguard Worker     }
71*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)72*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
73*c8dee2aaSAndroid Build Coastguard Worker         // Stroke widths are:
74*c8dee2aaSAndroid Build Coastguard Worker         // 0(may use hairline rendering), 10(common case for stroke-style)
75*c8dee2aaSAndroid Build Coastguard Worker         // 40 and 50(>= geometry width/height, make the contour filled in fact)
76*c8dee2aaSAndroid Build Coastguard Worker         constexpr int kStrokeWidth[] = {0, 10, 40, 50};
77*c8dee2aaSAndroid Build Coastguard Worker         int numWidths = std::size(kStrokeWidth);
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker         constexpr SkPaint::Style kStyle[] = {
80*c8dee2aaSAndroid Build Coastguard Worker             SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style
81*c8dee2aaSAndroid Build Coastguard Worker         };
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker         constexpr SkPaint::Cap kCap[] = {
84*c8dee2aaSAndroid Build Coastguard Worker             SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap
85*c8dee2aaSAndroid Build Coastguard Worker         };
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker         constexpr SkPaint::Join kJoin[] = {
88*c8dee2aaSAndroid Build Coastguard Worker             SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
89*c8dee2aaSAndroid Build Coastguard Worker         };
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker         constexpr ClosureType kType[] = {
92*c8dee2aaSAndroid Build Coastguard Worker             TotallyNonClosed, FakeCloseCorner, FakeCloseMiddle
93*c8dee2aaSAndroid Build Coastguard Worker         };
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker         int counter = 0;
96*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
97*c8dee2aaSAndroid Build Coastguard Worker         paint.setAntiAlias(true);
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker         // For stroke style painter and fill-and-stroke style painter
100*c8dee2aaSAndroid Build Coastguard Worker         for (size_t type = 0; type < kClosureTypeCount; ++type) {
101*c8dee2aaSAndroid Build Coastguard Worker             for (size_t style = 0; style < std::size(kStyle); ++style) {
102*c8dee2aaSAndroid Build Coastguard Worker                 for (size_t cap = 0; cap < std::size(kCap); ++cap) {
103*c8dee2aaSAndroid Build Coastguard Worker                     for (size_t join = 0; join < std::size(kJoin); ++join) {
104*c8dee2aaSAndroid Build Coastguard Worker                         for (int width = 0; width < numWidths; ++width) {
105*c8dee2aaSAndroid Build Coastguard Worker                             canvas->save();
106*c8dee2aaSAndroid Build Coastguard Worker                             SetLocation(canvas, counter, SkPaint::kJoinCount * numWidths);
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker                             SkPath path = MakePath(kType[type]);
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker                             paint.setStyle(kStyle[style]);
111*c8dee2aaSAndroid Build Coastguard Worker                             paint.setStrokeCap(kCap[cap]);
112*c8dee2aaSAndroid Build Coastguard Worker                             paint.setStrokeJoin(kJoin[join]);
113*c8dee2aaSAndroid Build Coastguard Worker                             paint.setStrokeWidth(SkIntToScalar(kStrokeWidth[width]));
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker                             canvas->drawPath(path, paint);
116*c8dee2aaSAndroid Build Coastguard Worker                             canvas->restore();
117*c8dee2aaSAndroid Build Coastguard Worker                             ++counter;
118*c8dee2aaSAndroid Build Coastguard Worker                         }
119*c8dee2aaSAndroid Build Coastguard Worker                     }
120*c8dee2aaSAndroid Build Coastguard Worker                 }
121*c8dee2aaSAndroid Build Coastguard Worker             }
122*c8dee2aaSAndroid Build Coastguard Worker         }
123*c8dee2aaSAndroid Build Coastguard Worker 
124*c8dee2aaSAndroid Build Coastguard Worker         // For fill style painter
125*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kFill_Style);
126*c8dee2aaSAndroid Build Coastguard Worker         for (size_t type = 0; type < kClosureTypeCount; ++type) {
127*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
128*c8dee2aaSAndroid Build Coastguard Worker             SetLocation(canvas, counter, SkPaint::kJoinCount * numWidths);
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker             SkPath path = MakePath(kType[type]);
131*c8dee2aaSAndroid Build Coastguard Worker 
132*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawPath(path, paint);
133*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
134*c8dee2aaSAndroid Build Coastguard Worker             ++counter;
135*c8dee2aaSAndroid Build Coastguard Worker         }
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker private:
139*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GM;
140*c8dee2aaSAndroid Build Coastguard Worker };
141*c8dee2aaSAndroid Build Coastguard Worker 
142*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
143*c8dee2aaSAndroid Build Coastguard Worker 
144*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new NonClosedPathsGM;)
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
147