1 /*
2 * Copyright 2013 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
8 #include "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPathBuilder.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkSize.h"
17 #include "include/core/SkString.h"
18 #include "include/core/SkTypes.h"
19 #include "include/private/SkFloatBits.h"
20 #include "include/private/SkTArray.h"
21
22 class ConicPathsGM : public skiagm::GM {
23 protected:
24
25 SkString onShortName() override {
26 return SkString("conicpaths");
27 }
28
29 SkISize onISize() override {
30 return SkISize::Make(920, 960);
31 }
32
append_path(Proc proc)33 template <typename Proc> void append_path(Proc proc) {
34 SkPathBuilder b;
35 proc(&b);
36 fPaths.push_back(b.detach());
37 }
38
39 void onOnceBeforeDraw() override {
40 this->append_path([](SkPathBuilder* conicCircle) {
41 const SkScalar w = SkScalarSqrt(2)/2;
42 conicCircle->moveTo(0, 0);
43 conicCircle->conicTo(0, 50, 50, 50, w);
44 conicCircle->rConicTo(50, 0, 50, -50, w);
45 conicCircle->rConicTo(0, -50, -50, -50, w);
46 conicCircle->rConicTo(-50, 0, -50, 50, w);
47 });
48
49 this->append_path([](SkPathBuilder* hyperbola) {
50 hyperbola->moveTo(0, 0);
51 hyperbola->conicTo(0, 100, 100, 100, 2);
52 });
53
54 this->append_path([](SkPathBuilder* thinHyperbola) {
55 thinHyperbola->moveTo(0, 0);
56 thinHyperbola->conicTo(100, 100, 5, 0, 2);
57 });
58
59 this->append_path([](SkPathBuilder* veryThinHyperbola) {
60 veryThinHyperbola->moveTo(0, 0);
61 veryThinHyperbola->conicTo(100, 100, 1, 0, 2);
62 });
63
64 this->append_path([](SkPathBuilder* closedHyperbola) {
65 closedHyperbola->moveTo(0, 0);
66 closedHyperbola->conicTo(100, 100, 0, 0, 2);
67 });
68
69 this->append_path([](SkPathBuilder* nearParabola) {
70 // using 1 as weight defaults to using quadTo
71 nearParabola->moveTo(0, 0);
72 nearParabola->conicTo(0, 100, 100, 100, 0.999f);
73 });
74
75 this->append_path([](SkPathBuilder* thinEllipse) {
76 thinEllipse->moveTo(0, 0);
77 thinEllipse->conicTo(100, 100, 5, 0, SK_ScalarHalf);
78 });
79
80 this->append_path([](SkPathBuilder* veryThinEllipse) {
81 veryThinEllipse->moveTo(0, 0);
82 veryThinEllipse->conicTo(100, 100, 1, 0, SK_ScalarHalf);
83 });
84
85 this->append_path([](SkPathBuilder* closedEllipse) {
86 closedEllipse->moveTo(0, 0);
87 closedEllipse->conicTo(100, 100, 0, 0, SK_ScalarHalf);
88 });
89
90 {
91 SkPathBuilder b;
92 const SkScalar w = SkScalarSqrt(2)/2;
93 b.moveTo(2.1e+11f, -1.05e+11f);
94 b.conicTo(2.1e+11f, 0, 1.05e+11f, 0, w);
95 b.conicTo(0, 0, 0, -1.05e+11f, w);
96 b.conicTo(0, -2.1e+11f, 1.05e+11f, -2.1e+11f, w);
97 b.conicTo(2.1e+11f, -2.1e+11f, 2.1e+11f, -1.05e+11f, w);
98 fGiantCircle = b.detach();
99 }
100 }
101
drawGiantCircle(SkCanvas* canvas)102 void drawGiantCircle(SkCanvas* canvas) {
103 SkPaint paint;
104 canvas->drawPath(fGiantCircle, paint);
105 }
106
107 void onDraw(SkCanvas* canvas) override {
108 const SkAlpha kAlphaValue[] = { 0xFF, 0x40 };
109
110 const SkScalar margin = 15;
111 canvas->translate(margin, margin);
112
113 SkPaint paint;
114 for (int p = 0; p < fPaths.count(); ++p) {
115 canvas->save();
116 for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphaValue); ++a) {
117 paint.setARGB(kAlphaValue[a], 0, 0, 0);
118 for (int aa = 0; aa < 2; ++aa) {
119 paint.setAntiAlias(SkToBool(aa));
120 for (int fh = 0; fh < 2; ++fh) {
121 paint.setStroke(fh != 0);
122
123 const SkRect& bounds = fPaths[p].getBounds();
124 canvas->save();
125 canvas->translate(-bounds.fLeft, -bounds.fTop);
126 canvas->drawPath(fPaths[p], paint);
127 canvas->restore();
128
129 canvas->translate(110, 0);
130 }
131 }
132 }
133 canvas->restore();
134 canvas->translate(0, 110);
135 }
136 canvas->restore();
137
138 this->drawGiantCircle(canvas);
139 }
140
141 private:
142 SkTArray<SkPath> fPaths;
143 SkPath fGiantCircle;
144 using INHERITED = skiagm::GM;
145 };
146 DEF_GM(return new ConicPathsGM;)
147
148 //////////////////////////////////////////////////////////////////////////////
149
150 /* arc should be on top of circle */
DEF_SIMPLE_GM(arccirclegap, canvas, 250, 250)151 DEF_SIMPLE_GM(arccirclegap, canvas, 250, 250) {
152 canvas->translate(50, 100);
153 SkPoint c = { 1052.5390625f, 506.8760978034711f };
154 SkScalar radius = 1096.702150363923f;
155 SkPaint paint;
156 paint.setAntiAlias(true);
157 paint.setStroke(true);
158 canvas->drawCircle(c, radius, paint);
159 SkPath path = SkPathBuilder().moveTo(288.88884710654133f, -280.26680862609f)
160 .arcTo({0, 0}, {-39.00216443306411f, 400.6058925796476f}, radius)
161 .detach();
162 paint.setColor(0xff007f00);
163 canvas->drawPath(path, paint);
164 }
165
166 /* circle should be antialiased */
DEF_SIMPLE_GM(largecircle, canvas, 250, 250)167 DEF_SIMPLE_GM(largecircle, canvas, 250, 250) {
168 canvas->translate(50, 100);
169 SkPoint c = { 1052.5390625f, 506.8760978034711f };
170 SkScalar radius = 1096.702150363923f;
171 SkPaint paint;
172 paint.setAntiAlias(true);
173 paint.setStroke(true);
174 canvas->drawCircle(c, radius, paint);
175 }
176
177 /* ovals should not be blurry */
DEF_SIMPLE_GM(largeovals, canvas, 250, 250)178 DEF_SIMPLE_GM(largeovals, canvas, 250, 250) {
179 // Test EllipseOp
180 SkRect r = SkRect::MakeXYWH(-520, -520, 5000, 4000);
181 SkPaint paint;
182 paint.setAntiAlias(true);
183 paint.setStroke(true);
184 paint.setStrokeWidth(100);
185 canvas->drawOval(r, paint);
186 r.offset(-15, -15);
187 paint.setColor(SK_ColorDKGRAY);
188 // we use stroke and fill to avoid falling into the SimpleFill path
189 paint.setStyle(SkPaint::kStrokeAndFill_Style);
190 paint.setStrokeWidth(1);
191 canvas->drawOval(r, paint);
192
193 // Test DIEllipseOp
194 canvas->rotate(1.0f);
195 r.offset(55, 55);
196 paint.setColor(SK_ColorGRAY);
197 paint.setStroke(true);
198 paint.setStrokeWidth(100);
199 canvas->drawOval(r, paint);
200 r.offset(-15, -15);
201 paint.setColor(SK_ColorLTGRAY);
202 paint.setStyle(SkPaint::kStrokeAndFill_Style);
203 paint.setStrokeWidth(1);
204 canvas->drawOval(r, paint);
205 }
206
DEF_SIMPLE_GM(crbug_640176, canvas, 250, 250)207 DEF_SIMPLE_GM(crbug_640176, canvas, 250, 250) {
208 SkPathBuilder path;
209 path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
210 path.lineTo(SkBits2Float(0x42cfd89a), SkBits2Float(0xc2700000)); // 103.923f, -60
211 path.lineTo(SkBits2Float(0x42cfd899), SkBits2Float(0xc2700006)); // 103.923f, -60
212 path.conicTo(SkBits2Float(0x42f00000), SkBits2Float(0xc2009d9c),
213 SkBits2Float(0x42f00001), SkBits2Float(0x00000000),
214 SkBits2Float(0x3f7746ea)); // 120, -32.1539f, 120, 0, 0.965926f
215
216 SkPaint paint;
217 paint.setAntiAlias(true);
218 canvas->translate(125, 125);
219 canvas->drawPath(path.detach(), paint);
220 }
221