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