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