blob: 0ed6e4b45b189f71139c41a02c8550a661dee21d [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 */
Ben Wagnerb2c4ea62018-08-08 11:36:17 -04007#include "Sample.h"
hstern9bd4c692016-06-15 09:13:34 -07008#include "SkCanvas.h"
9#include "SkPath.h"
10
hsterne2463ed2016-06-30 10:04:21 -070011#include <iostream>
hstern9bd4c692016-06-15 09:13:34 -070012#include <cmath>
13
14#define PI SK_ScalarPI
15
16#define LIN_SEGMENTS 10
17
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040018class OverstrokeView : public Sample {
hstern9bd4c692016-06-15 09:13:34 -070019 public:
20 SkScalar fStroke;
21 int fPathType; // super lazy enum
22 bool fClosePath;
23 bool fDrawFillPath;
hsterne2463ed2016-06-30 10:04:21 -070024 bool fDumpHex;
hstern9bd4c692016-06-15 09:13:34 -070025 OverstrokeView() {
26 fStroke = 5;
27 fPathType = 0;
28 fClosePath = false;
29 fDrawFillPath = false;
hsterne2463ed2016-06-30 10:04:21 -070030 fDumpHex = false;
hstern9bd4c692016-06-15 09:13:34 -070031 this->setBGColor(0xFFFFFFFF);
32 }
33
34 protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040035 bool onQuery(Sample::Event* evt) override {
36 if (Sample::TitleQ(*evt)) {
37 Sample::TitleR(evt, "PathOverstroke");
hstern9bd4c692016-06-15 09:13:34 -070038 return true;
39 }
40 SkUnichar uni;
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040041 if (Sample::CharQ(*evt, &uni)) {
hstern9bd4c692016-06-15 09:13:34 -070042 switch (uni) {
43 case ',':
44 fStroke += 1.0;
hstern9bd4c692016-06-15 09:13:34 -070045 return true;
46 case '.':
47 fStroke -= 1.0;
hstern9bd4c692016-06-15 09:13:34 -070048 return true;
49 case 'x':
hsterne2463ed2016-06-30 10:04:21 -070050 fPathType = (fPathType + 1) % 4;
hstern9bd4c692016-06-15 09:13:34 -070051 return true;
52 case 'c':
53 fClosePath = !fClosePath;
hstern9bd4c692016-06-15 09:13:34 -070054 return true;
55 case 'f':
56 fDrawFillPath = !fDrawFillPath;
hstern9bd4c692016-06-15 09:13:34 -070057 return true;
hsterne2463ed2016-06-30 10:04:21 -070058 case 'D':
59 fDumpHex = !fDumpHex;
hsterne2463ed2016-06-30 10:04:21 -070060 return true;
hstern9bd4c692016-06-15 09:13:34 -070061 default:
62 break;
63 }
64 }
65 return this->INHERITED::onQuery(evt);
66 }
67
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
hsterne2463ed2016-06-30 10:04:21 -070082 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
hstern9bd4c692016-06-15 09:13:34 -070096 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
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
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:
hsterne2463ed2016-06-30 10:04:21 -0700140 path = cubicPath(p1, p2);
hstern9bd4c692016-06-15 09:13:34 -0700141 break;
142 case 2:
143 path = rectPath(p1);
144 break;
hsterne2463ed2016-06-30 10:04:21 -0700145 case 3:
146 path = linSemicirclePath(p1, p2);
147 break;
hstern9bd4c692016-06-15 09:13:34 -0700148 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
hsterne2463ed2016-06-30 10:04:21 -0700165 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
hstern9bd4c692016-06-15 09:13:34 -0700175 if (fDrawFillPath) {
176 SkPath fillpath;
177 p.getFillPath(path, &fillpath);
178
hsterne2463ed2016-06-30 10:04:21 -0700179 canvas->drawPath(fillpath, hairp);
hstern9bd4c692016-06-15 09:13:34 -0700180
hsterne2463ed2016-06-30 10:04:21 -0700181 if (fDumpHex) {
182 std::cerr << "fillpath dumpHex" << std::endl;
183 fillpath.dumpHex();
184 }
hstern9bd4c692016-06-15 09:13:34 -0700185 }
hsterne2463ed2016-06-30 10:04:21 -0700186
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);
hstern9bd4c692016-06-15 09:13:34 -0700196 }
197
198 private:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400199 typedef Sample INHERITED;
hstern9bd4c692016-06-15 09:13:34 -0700200};
201
202///////////////////////////////////////////////////////////////////////////////
203
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400204DEF_SAMPLE( return new OverstrokeView(); )