xref: /aosp_15_r20/external/skia/tools/viewer/PathOverstrokeSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2016 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 "include/core/SkCanvas.h"
8 #include "include/core/SkPath.h"
9 #include "include/core/SkPathUtils.h"
10 #include "tools/viewer/Slide.h"
11 
12 #include <iostream>
13 #include <cmath>
14 
15 #define PI SK_ScalarPI
16 
17 #define LIN_SEGMENTS 10
18 
19 class OverstrokeSlide : public Slide {
20     SkScalar fStroke;
21     int fPathType;  // super lazy enum
22     bool fClosePath;
23     bool fDrawFillPath;
24     bool fDumpHex;
25 
26 public:
OverstrokeSlide()27     OverstrokeSlide() {
28         fStroke = 5;
29         fPathType = 0;
30         fClosePath = false;
31         fDrawFillPath = false;
32         fDumpHex = false;
33         fName = "PathOverstroke";
34     }
35 
onChar(SkUnichar uni)36     bool onChar(SkUnichar uni) override {
37             switch (uni) {
38                 case ',':
39                     fStroke += 1.0;
40                     return true;
41                 case '.':
42                     fStroke -= 1.0;
43                     return true;
44                 case 'x':
45                     fPathType = (fPathType + 1) % 4;
46                     return true;
47                 case 'c':
48                     fClosePath = !fClosePath;
49                     return true;
50                 case 'f':
51                     fDrawFillPath = !fDrawFillPath;
52                     return true;
53                 case 'D':
54                     fDumpHex = !fDumpHex;
55                     return true;
56                 default:
57                     break;
58             }
59             return false;
60     }
61 
quadPath(SkPoint p1,SkPoint p2)62     SkPath quadPath(SkPoint p1, SkPoint p2) {
63         SkASSERT(p1.y() == p2.y());
64 
65         SkPath path;
66         path.moveTo(p1);
67         path.lineTo(p2);
68 
69         SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f);
70 
71         path.quadTo(p3, p1);
72 
73         return path;
74     }
75 
cubicPath(SkPoint p1,SkPoint p2)76     SkPath cubicPath(SkPoint p1, SkPoint p2) {
77         SkASSERT(p1.y() == p2.y());
78 
79         SkPath path;
80         path.moveTo(p1);
81 
82         SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 3.0f, p1.y() * 0.7f);
83         SkPoint p4 = SkPoint::Make(2.0f*(p1.x() + p2.x()) / 3.0f, p1.y() * 1.5f);
84 
85         path.cubicTo(p3, p4, p2);
86 
87         return path;
88     }
89 
linSemicirclePath(SkPoint p1,SkPoint p2)90     SkPath linSemicirclePath(SkPoint p1, SkPoint p2) {
91         SkASSERT(p1.y() == p2.y());
92 
93         SkPath path;
94         path.moveTo(p1);
95         path.lineTo(p2);
96 
97         SkPoint pt;
98 
99         for (int i = 0; i < LIN_SEGMENTS; i++) {
100             float theta = i * PI / (LIN_SEGMENTS);
101             SkScalar x = 65 + 15 * cos(theta);
102             SkScalar y = 50 - 15 * sin(theta);
103             pt = SkPoint::Make(x, y);
104             path.lineTo(pt);
105         }
106         path.lineTo(p1);
107 
108         return path;
109     }
110 
rectPath(SkPoint p1)111     SkPath rectPath(SkPoint p1) {
112         SkRect r = SkRect::MakeXYWH(p1.fX, p1.fY, 20, 20);
113         SkPath path;
114         path.addRect(r);
115 
116         return path;
117     }
118 
draw(SkCanvas * canvas)119     void draw(SkCanvas* canvas) override {
120         canvas->clear(0xFFFFFFFF);
121         const float SCALE = 1;
122 
123         canvas->translate(30, 40);
124         canvas->scale(SCALE, SCALE);
125 
126         SkPoint p1 = SkPoint::Make(50, 50);
127         SkPoint p2 = SkPoint::Make(80, 50);
128 
129         SkPath path;
130         switch (fPathType) {
131             case 0:
132                 path = quadPath(p1, p2);
133                 break;
134             case 1:
135                 path = cubicPath(p1, p2);
136                 break;
137             case 2:
138                 path = rectPath(p1);
139                 break;
140             case 3:
141                 path = linSemicirclePath(p1, p2);
142                 break;
143             default:
144                 path = quadPath(p1, p2);
145                 break;
146         }
147 
148         if (fClosePath) {
149             path.close();
150         }
151 
152         SkPaint p;
153         p.setColor(SK_ColorRED);
154         p.setAntiAlias(true);
155         p.setStyle(SkPaint::kStroke_Style);
156         p.setStrokeWidth(fStroke);
157 
158         canvas->drawPath(path, p);
159 
160         if (fDumpHex) {
161             std::cerr << "path dumpHex" << std::endl;
162             path.dumpHex();
163         }
164 
165         SkPaint hairp;
166         hairp.setColor(SK_ColorBLACK);
167         hairp.setAntiAlias(true);
168         hairp.setStyle(SkPaint::kStroke_Style);
169 
170         if (fDrawFillPath) {
171             SkPath fillpath;
172             skpathutils::FillPathWithPaint(path, p, &fillpath);
173 
174             canvas->drawPath(fillpath, hairp);
175 
176             if (fDumpHex) {
177                 std::cerr << "fillpath dumpHex" << std::endl;
178                 fillpath.dumpHex();
179             }
180         }
181 
182         if (fDumpHex) {
183             std::cerr << std::endl;
184 
185             fDumpHex = false;
186         }
187 
188         // draw original path with green hairline
189         hairp.setColor(SK_ColorGREEN);
190         canvas->drawPath(path, hairp);
191     }
192 };
193 
194 ///////////////////////////////////////////////////////////////////////////////
195 
196 DEF_SLIDE( return new OverstrokeSlide(); )
197