blob: 9ebf1d40456d7d80d5669ce312ba0bfbdc983373 [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
Hal Canary6cc65e12019-07-03 15:53:04 -040037 bool onChar(SkUnichar uni) override {
hstern9bd4c692016-06-15 09:13:34 -070038 switch (uni) {
39 case ',':
40 fStroke += 1.0;
hstern9bd4c692016-06-15 09:13:34 -070041 return true;
42 case '.':
43 fStroke -= 1.0;
hstern9bd4c692016-06-15 09:13:34 -070044 return true;
45 case 'x':
hsterne2463ed2016-06-30 10:04:21 -070046 fPathType = (fPathType + 1) % 4;
hstern9bd4c692016-06-15 09:13:34 -070047 return true;
48 case 'c':
49 fClosePath = !fClosePath;
hstern9bd4c692016-06-15 09:13:34 -070050 return true;
51 case 'f':
52 fDrawFillPath = !fDrawFillPath;
hstern9bd4c692016-06-15 09:13:34 -070053 return true;
hsterne2463ed2016-06-30 10:04:21 -070054 case 'D':
55 fDumpHex = !fDumpHex;
hsterne2463ed2016-06-30 10:04:21 -070056 return true;
hstern9bd4c692016-06-15 09:13:34 -070057 default:
58 break;
59 }
Hal Canary6cc65e12019-07-03 15:53:04 -040060 return false;
hstern9bd4c692016-06-15 09:13:34 -070061 }
62
63 SkPath quadPath(SkPoint p1, SkPoint p2) {
64 SkASSERT(p1.y() == p2.y());
65
66 SkPath path;
67 path.moveTo(p1);
68 path.lineTo(p2);
69
70 SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f);
71
72 path.quadTo(p3, p1);
73
74 return path;
75 }
76
hsterne2463ed2016-06-30 10:04:21 -070077 SkPath cubicPath(SkPoint p1, SkPoint p2) {
78 SkASSERT(p1.y() == p2.y());
79
80 SkPath path;
81 path.moveTo(p1);
82
83 SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 3.0f, p1.y() * 0.7f);
84 SkPoint p4 = SkPoint::Make(2.0f*(p1.x() + p2.x()) / 3.0f, p1.y() * 1.5f);
85
86 path.cubicTo(p3, p4, p2);
87
88 return path;
89 }
90
hstern9bd4c692016-06-15 09:13:34 -070091 SkPath linSemicirclePath(SkPoint p1, SkPoint p2) {
92 SkASSERT(p1.y() == p2.y());
93
94 SkPath path;
95 path.moveTo(p1);
96 path.lineTo(p2);
97
98 SkPoint pt;
99
100 for (int i = 0; i < LIN_SEGMENTS; i++) {
101 float theta = i * PI / (LIN_SEGMENTS);
102 SkScalar x = 65 + 15 * cos(theta);
103 SkScalar y = 50 - 15 * sin(theta);
104 pt = SkPoint::Make(x, y);
105 path.lineTo(pt);
106 }
107 path.lineTo(p1);
108
109 return path;
110 }
111
112 SkPath rectPath(SkPoint p1) {
113 SkRect r = SkRect::MakeXYWH(p1.fX, p1.fY, 20, 20);
114 SkPath path;
115 path.addRect(r);
116
117 return path;
118 }
119
120 void onDrawContent(SkCanvas* canvas) override {
121 const float SCALE = 1;
122
123 canvas->translate(30, 40);
124 canvas->scale(SCALE, SCALE);
125
126 SkPoint p1 = SkPoint::Make(50, 50);
127 SkPoint p2 = SkPoint::Make(80, 50);
128
129 SkPath path;
130 switch (fPathType) {
131 case 0:
132 path = quadPath(p1, p2);
133 break;
134 case 1:
hsterne2463ed2016-06-30 10:04:21 -0700135 path = cubicPath(p1, p2);
hstern9bd4c692016-06-15 09:13:34 -0700136 break;
137 case 2:
138 path = rectPath(p1);
139 break;
hsterne2463ed2016-06-30 10:04:21 -0700140 case 3:
141 path = linSemicirclePath(p1, p2);
142 break;
hstern9bd4c692016-06-15 09:13:34 -0700143 default:
144 path = quadPath(p1, p2);
145 break;
146 }
147
148 if (fClosePath) {
149 path.close();
150 }
151
152 SkPaint p;
153 p.setColor(SK_ColorRED);
154 p.setAntiAlias(true);
155 p.setStyle(SkPaint::kStroke_Style);
156 p.setStrokeWidth(fStroke);
157
158 canvas->drawPath(path, p);
159
hsterne2463ed2016-06-30 10:04:21 -0700160 if (fDumpHex) {
161 std::cerr << "path dumpHex" << std::endl;
162 path.dumpHex();
163 }
164
165 SkPaint hairp;
166 hairp.setColor(SK_ColorBLACK);
167 hairp.setAntiAlias(true);
168 hairp.setStyle(SkPaint::kStroke_Style);
169
hstern9bd4c692016-06-15 09:13:34 -0700170 if (fDrawFillPath) {
171 SkPath fillpath;
172 p.getFillPath(path, &fillpath);
173
hsterne2463ed2016-06-30 10:04:21 -0700174 canvas->drawPath(fillpath, hairp);
hstern9bd4c692016-06-15 09:13:34 -0700175
hsterne2463ed2016-06-30 10:04:21 -0700176 if (fDumpHex) {
177 std::cerr << "fillpath dumpHex" << std::endl;
178 fillpath.dumpHex();
179 }
hstern9bd4c692016-06-15 09:13:34 -0700180 }
hsterne2463ed2016-06-30 10:04:21 -0700181
182 if (fDumpHex) {
183 std::cerr << std::endl;
184
185 fDumpHex = false;
186 }
187
188 // draw original path with green hairline
189 hairp.setColor(SK_ColorGREEN);
190 canvas->drawPath(path, hairp);
hstern9bd4c692016-06-15 09:13:34 -0700191 }
192
193 private:
John Stiles7571f9e2020-09-02 22:42:33 -0400194 using INHERITED = Sample;
hstern9bd4c692016-06-15 09:13:34 -0700195};
196
197///////////////////////////////////////////////////////////////////////////////
198
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400199DEF_SAMPLE( return new OverstrokeView(); )