blob: b6202a7784037310b4ac728ff1abce8be372bc96 [file] [log] [blame]
hstern9bd4c692016-06-15 09:13:34 -07001/*
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
hsterne2463ed2016-06-30 10:04:21 -070012#include <iostream>
hstern9bd4c692016-06-15 09:13:34 -070013#include <cmath>
14
15#define PI SK_ScalarPI
16
17#define LIN_SEGMENTS 10
18
19class OverstrokeView : public SampleView {
20 public:
21 SkScalar fStroke;
22 int fPathType; // super lazy enum
23 bool fClosePath;
24 bool fDrawFillPath;
hsterne2463ed2016-06-30 10:04:21 -070025 bool fDumpHex;
hstern9bd4c692016-06-15 09:13:34 -070026 OverstrokeView() {
27 fStroke = 5;
28 fPathType = 0;
29 fClosePath = false;
30 fDrawFillPath = false;
hsterne2463ed2016-06-30 10:04:21 -070031 fDumpHex = false;
hstern9bd4c692016-06-15 09:13:34 -070032 this->setBGColor(0xFFFFFFFF);
33 }
34
35 protected:
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;
hstern9bd4c692016-06-15 09:13:34 -070046 return true;
47 case '.':
48 fStroke -= 1.0;
hstern9bd4c692016-06-15 09:13:34 -070049 return true;
50 case 'x':
hsterne2463ed2016-06-30 10:04:21 -070051 fPathType = (fPathType + 1) % 4;
hstern9bd4c692016-06-15 09:13:34 -070052 return true;
53 case 'c':
54 fClosePath = !fClosePath;
hstern9bd4c692016-06-15 09:13:34 -070055 return true;
56 case 'f':
57 fDrawFillPath = !fDrawFillPath;
hstern9bd4c692016-06-15 09:13:34 -070058 return true;
hsterne2463ed2016-06-30 10:04:21 -070059 case 'D':
60 fDumpHex = !fDumpHex;
hsterne2463ed2016-06-30 10:04:21 -070061 return true;
hstern9bd4c692016-06-15 09:13:34 -070062 default:
63 break;
64 }
65 }
66 return this->INHERITED::onQuery(evt);
67 }
68
69 SkPath quadPath(SkPoint p1, SkPoint p2) {
70 SkASSERT(p1.y() == p2.y());
71
72 SkPath path;
73 path.moveTo(p1);
74 path.lineTo(p2);
75
76 SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f);
77
78 path.quadTo(p3, p1);
79
80 return path;
81 }
82
hsterne2463ed2016-06-30 10:04:21 -070083 SkPath cubicPath(SkPoint p1, SkPoint p2) {
84 SkASSERT(p1.y() == p2.y());
85
86 SkPath path;
87 path.moveTo(p1);
88
89 SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 3.0f, p1.y() * 0.7f);
90 SkPoint p4 = SkPoint::Make(2.0f*(p1.x() + p2.x()) / 3.0f, p1.y() * 1.5f);
91
92 path.cubicTo(p3, p4, p2);
93
94 return path;
95 }
96
hstern9bd4c692016-06-15 09:13:34 -070097 SkPath linSemicirclePath(SkPoint p1, SkPoint p2) {
98 SkASSERT(p1.y() == p2.y());
99
100 SkPath path;
101 path.moveTo(p1);
102 path.lineTo(p2);
103
104 SkPoint pt;
105
106 for (int i = 0; i < LIN_SEGMENTS; i++) {
107 float theta = i * PI / (LIN_SEGMENTS);
108 SkScalar x = 65 + 15 * cos(theta);
109 SkScalar y = 50 - 15 * sin(theta);
110 pt = SkPoint::Make(x, y);
111 path.lineTo(pt);
112 }
113 path.lineTo(p1);
114
115 return path;
116 }
117
118 SkPath rectPath(SkPoint p1) {
119 SkRect r = SkRect::MakeXYWH(p1.fX, p1.fY, 20, 20);
120 SkPath path;
121 path.addRect(r);
122
123 return path;
124 }
125
126 void onDrawContent(SkCanvas* canvas) override {
127 const float SCALE = 1;
128
129 canvas->translate(30, 40);
130 canvas->scale(SCALE, SCALE);
131
132 SkPoint p1 = SkPoint::Make(50, 50);
133 SkPoint p2 = SkPoint::Make(80, 50);
134
135 SkPath path;
136 switch (fPathType) {
137 case 0:
138 path = quadPath(p1, p2);
139 break;
140 case 1:
hsterne2463ed2016-06-30 10:04:21 -0700141 path = cubicPath(p1, p2);
hstern9bd4c692016-06-15 09:13:34 -0700142 break;
143 case 2:
144 path = rectPath(p1);
145 break;
hsterne2463ed2016-06-30 10:04:21 -0700146 case 3:
147 path = linSemicirclePath(p1, p2);
148 break;
hstern9bd4c692016-06-15 09:13:34 -0700149 default:
150 path = quadPath(p1, p2);
151 break;
152 }
153
154 if (fClosePath) {
155 path.close();
156 }
157
158 SkPaint p;
159 p.setColor(SK_ColorRED);
160 p.setAntiAlias(true);
161 p.setStyle(SkPaint::kStroke_Style);
162 p.setStrokeWidth(fStroke);
163
164 canvas->drawPath(path, p);
165
hsterne2463ed2016-06-30 10:04:21 -0700166 if (fDumpHex) {
167 std::cerr << "path dumpHex" << std::endl;
168 path.dumpHex();
169 }
170
171 SkPaint hairp;
172 hairp.setColor(SK_ColorBLACK);
173 hairp.setAntiAlias(true);
174 hairp.setStyle(SkPaint::kStroke_Style);
175
hstern9bd4c692016-06-15 09:13:34 -0700176 if (fDrawFillPath) {
177 SkPath fillpath;
178 p.getFillPath(path, &fillpath);
179
hsterne2463ed2016-06-30 10:04:21 -0700180 canvas->drawPath(fillpath, hairp);
hstern9bd4c692016-06-15 09:13:34 -0700181
hsterne2463ed2016-06-30 10:04:21 -0700182 if (fDumpHex) {
183 std::cerr << "fillpath dumpHex" << std::endl;
184 fillpath.dumpHex();
185 }
hstern9bd4c692016-06-15 09:13:34 -0700186 }
hsterne2463ed2016-06-30 10:04:21 -0700187
188 if (fDumpHex) {
189 std::cerr << std::endl;
190
191 fDumpHex = false;
192 }
193
194 // draw original path with green hairline
195 hairp.setColor(SK_ColorGREEN);
196 canvas->drawPath(path, hairp);
hstern9bd4c692016-06-15 09:13:34 -0700197 }
198
199 private:
200 typedef SampleView INHERITED;
201};
202
203///////////////////////////////////////////////////////////////////////////////
204
205static SkView* MyFactory() { return new OverstrokeView; }
206static SkViewRegister reg(MyFactory);