blob: 6346564ec3677be5e3eaa1f302162d78578e4e06 [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 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "include/core/SkCanvas.h"
8#include "include/core/SkPath.h"
9#include "samplecode/Sample.h"
hstern9bd4c692016-06-15 09:13:34 -070010
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:
Hal Canary8a027312019-07-03 10:55:44 -040035 SkString name() override { return SkString("PathOverstroke"); }
36
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040037 bool onQuery(Sample::Event* evt) override {
hstern9bd4c692016-06-15 09:13:34 -070038 SkUnichar uni;
Ben Wagnerb2c4ea62018-08-08 11:36:17 -040039 if (Sample::CharQ(*evt, &uni)) {
hstern9bd4c692016-06-15 09:13:34 -070040 switch (uni) {
41 case ',':
42 fStroke += 1.0;
hstern9bd4c692016-06-15 09:13:34 -070043 return true;
44 case '.':
45 fStroke -= 1.0;
hstern9bd4c692016-06-15 09:13:34 -070046 return true;
47 case 'x':
hsterne2463ed2016-06-30 10:04:21 -070048 fPathType = (fPathType + 1) % 4;
hstern9bd4c692016-06-15 09:13:34 -070049 return true;
50 case 'c':
51 fClosePath = !fClosePath;
hstern9bd4c692016-06-15 09:13:34 -070052 return true;
53 case 'f':
54 fDrawFillPath = !fDrawFillPath;
hstern9bd4c692016-06-15 09:13:34 -070055 return true;
hsterne2463ed2016-06-30 10:04:21 -070056 case 'D':
57 fDumpHex = !fDumpHex;
hsterne2463ed2016-06-30 10:04:21 -070058 return true;
hstern9bd4c692016-06-15 09:13:34 -070059 default:
60 break;
61 }
62 }
63 return this->INHERITED::onQuery(evt);
64 }
65
66 SkPath quadPath(SkPoint p1, SkPoint p2) {
67 SkASSERT(p1.y() == p2.y());
68
69 SkPath path;
70 path.moveTo(p1);
71 path.lineTo(p2);
72
73 SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f);
74
75 path.quadTo(p3, p1);
76
77 return path;
78 }
79
hsterne2463ed2016-06-30 10:04:21 -070080 SkPath cubicPath(SkPoint p1, SkPoint p2) {
81 SkASSERT(p1.y() == p2.y());
82
83 SkPath path;
84 path.moveTo(p1);
85
86 SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 3.0f, p1.y() * 0.7f);
87 SkPoint p4 = SkPoint::Make(2.0f*(p1.x() + p2.x()) / 3.0f, p1.y() * 1.5f);
88
89 path.cubicTo(p3, p4, p2);
90
91 return path;
92 }
93
hstern9bd4c692016-06-15 09:13:34 -070094 SkPath linSemicirclePath(SkPoint p1, SkPoint p2) {
95 SkASSERT(p1.y() == p2.y());
96
97 SkPath path;
98 path.moveTo(p1);
99 path.lineTo(p2);
100
101 SkPoint pt;
102
103 for (int i = 0; i < LIN_SEGMENTS; i++) {
104 float theta = i * PI / (LIN_SEGMENTS);
105 SkScalar x = 65 + 15 * cos(theta);
106 SkScalar y = 50 - 15 * sin(theta);
107 pt = SkPoint::Make(x, y);
108 path.lineTo(pt);
109 }
110 path.lineTo(p1);
111
112 return path;
113 }
114
115 SkPath rectPath(SkPoint p1) {
116 SkRect r = SkRect::MakeXYWH(p1.fX, p1.fY, 20, 20);
117 SkPath path;
118 path.addRect(r);
119
120 return path;
121 }
122
123 void onDrawContent(SkCanvas* canvas) override {
124 const float SCALE = 1;
125
126 canvas->translate(30, 40);
127 canvas->scale(SCALE, SCALE);
128
129 SkPoint p1 = SkPoint::Make(50, 50);
130 SkPoint p2 = SkPoint::Make(80, 50);
131
132 SkPath path;
133 switch (fPathType) {
134 case 0:
135 path = quadPath(p1, p2);
136 break;
137 case 1:
hsterne2463ed2016-06-30 10:04:21 -0700138 path = cubicPath(p1, p2);
hstern9bd4c692016-06-15 09:13:34 -0700139 break;
140 case 2:
141 path = rectPath(p1);
142 break;
hsterne2463ed2016-06-30 10:04:21 -0700143 case 3:
144 path = linSemicirclePath(p1, p2);
145 break;
hstern9bd4c692016-06-15 09:13:34 -0700146 default:
147 path = quadPath(p1, p2);
148 break;
149 }
150
151 if (fClosePath) {
152 path.close();
153 }
154
155 SkPaint p;
156 p.setColor(SK_ColorRED);
157 p.setAntiAlias(true);
158 p.setStyle(SkPaint::kStroke_Style);
159 p.setStrokeWidth(fStroke);
160
161 canvas->drawPath(path, p);
162
hsterne2463ed2016-06-30 10:04:21 -0700163 if (fDumpHex) {
164 std::cerr << "path dumpHex" << std::endl;
165 path.dumpHex();
166 }
167
168 SkPaint hairp;
169 hairp.setColor(SK_ColorBLACK);
170 hairp.setAntiAlias(true);
171 hairp.setStyle(SkPaint::kStroke_Style);
172
hstern9bd4c692016-06-15 09:13:34 -0700173 if (fDrawFillPath) {
174 SkPath fillpath;
175 p.getFillPath(path, &fillpath);
176
hsterne2463ed2016-06-30 10:04:21 -0700177 canvas->drawPath(fillpath, hairp);
hstern9bd4c692016-06-15 09:13:34 -0700178
hsterne2463ed2016-06-30 10:04:21 -0700179 if (fDumpHex) {
180 std::cerr << "fillpath dumpHex" << std::endl;
181 fillpath.dumpHex();
182 }
hstern9bd4c692016-06-15 09:13:34 -0700183 }
hsterne2463ed2016-06-30 10:04:21 -0700184
185 if (fDumpHex) {
186 std::cerr << std::endl;
187
188 fDumpHex = false;
189 }
190
191 // draw original path with green hairline
192 hairp.setColor(SK_ColorGREEN);
193 canvas->drawPath(path, hairp);
hstern9bd4c692016-06-15 09:13:34 -0700194 }
195
196 private:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400197 typedef Sample INHERITED;
hstern9bd4c692016-06-15 09:13:34 -0700198};
199
200///////////////////////////////////////////////////////////////////////////////
201
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400202DEF_SAMPLE( return new OverstrokeView(); )