blob: e017d8b22d6916beae28c5ba94c8f0548baea59c [file] [log] [blame]
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +00001/*
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.h"
9#include "SkCanvas.h"
10#include "SkTArray.h"
11
12namespace skiagm {
13
14class HairlinesGM : public GM {
15protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000016 virtual uint32_t onGetFlags() const SK_OVERRIDE {
17 return kSkipTiled_Flag;
18 }
19
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000020
21 virtual SkString onShortName() SK_OVERRIDE {
22 return SkString("hairlines");
23 }
24
tfarinaf5393182014-06-09 23:59:03 -070025 virtual SkISize onISize() { return SkISize::Make(800, 600); }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000026
27 virtual void onOnceBeforeDraw() SK_OVERRIDE {
28 {
29 SkPath* lineAnglesPath = &fPaths.push_back();
30 enum {
31 kNumAngles = 15,
32 kRadius = 40,
33 };
34 for (int i = 0; i < kNumAngles; ++i) {
35 SkScalar angle = SK_ScalarPI * SkIntToScalar(i) / kNumAngles;
36 SkScalar x = kRadius * SkScalarCos(angle);
37 SkScalar y = kRadius * SkScalarSin(angle);
38 lineAnglesPath->moveTo(x, y);
39 lineAnglesPath->lineTo(-x, -y);
40 }
41 }
42
43 {
44 SkPath* kindaTightQuad = &fPaths.push_back();
45 kindaTightQuad->moveTo(0, -10 * SK_Scalar1);
46 kindaTightQuad->quadTo(SkIntToScalar(100), SkIntToScalar(100), -10 * SK_Scalar1, 0);
47 }
48
49 {
50 SkPath* tightQuad = &fPaths.push_back();
51 tightQuad->moveTo(0, -5 * SK_Scalar1);
52 tightQuad->quadTo(SkIntToScalar(100), SkIntToScalar(100), -5 * SK_Scalar1, 0);
53 }
54
55 {
56 SkPath* tighterQuad = &fPaths.push_back();
57 tighterQuad->moveTo(0, -2 * SK_Scalar1);
58 tighterQuad->quadTo(SkIntToScalar(100), SkIntToScalar(100), -2 * SK_Scalar1, 0);
59 }
60
61 {
62 SkPath* unevenTighterQuad = &fPaths.push_back();
63 unevenTighterQuad->moveTo(0, -1 * SK_Scalar1);
64 SkPoint p;
65 p.set(-2 * SK_Scalar1 + 3 * SkIntToScalar(102) / 4, SkIntToScalar(75));
66 unevenTighterQuad->quadTo(SkIntToScalar(100), SkIntToScalar(100), p.fX, p.fY);
67 }
68
69 {
70 SkPath* reallyTightQuad = &fPaths.push_back();
71 reallyTightQuad->moveTo(0, -1 * SK_Scalar1);
72 reallyTightQuad->quadTo(SkIntToScalar(100), SkIntToScalar(100), -1 * SK_Scalar1, 0);
73 }
74
75 {
76 SkPath* closedQuad = &fPaths.push_back();
77 closedQuad->moveTo(0, -0);
78 closedQuad->quadTo(SkIntToScalar(100), SkIntToScalar(100), 0, 0);
79 }
80
81 {
82 SkPath* unevenClosedQuad = &fPaths.push_back();
83 unevenClosedQuad->moveTo(0, -0);
84 unevenClosedQuad->quadTo(SkIntToScalar(100), SkIntToScalar(100),
85 SkIntToScalar(75), SkIntToScalar(75));
86 }
commit-bot@chromium.orgb8bd6cb2013-09-03 14:56:17 +000087
88 // Two problem cases for gpu hairline renderer found by shapeops testing. These used
89 // to assert that the computed bounding box didn't contain all the vertices.
90 {
91 SkPath* problem1 = &fPaths.push_back();
92 problem1->moveTo(SkIntToScalar(4), SkIntToScalar(6));
93 problem1->cubicTo(SkIntToScalar(5), SkIntToScalar(6),
94 SkIntToScalar(5), SkIntToScalar(4),
95 SkIntToScalar(4), SkIntToScalar(0));
96 problem1->close();
97 }
98
99 {
100 SkPath* problem2 = &fPaths.push_back();
101 problem2->moveTo(SkIntToScalar(5), SkIntToScalar(1));
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000102 problem2->lineTo(4.32787323f, 1.67212653f);
103 problem2->cubicTo(2.75223875f, 3.24776125f,
104 3.00581908f, 4.51236057f,
105 3.7580452f, 4.37367964f);
106 problem2->cubicTo(4.66472578f, 3.888381f,
107 5.f, 2.875f,
108 5.f, 1.f);
commit-bot@chromium.orgb8bd6cb2013-09-03 14:56:17 +0000109 problem2->close();
110 }
robertphillips@google.comada90da2013-09-18 22:14:49 +0000111
112 // Three paths that show the same bug (missing end caps)
113 {
114 // A caret (crbug.com/131770)
115 SkPath* bug0 = &fPaths.push_back();
116 bug0->moveTo(6.5f,5.5f);
117 bug0->lineTo(3.5f,0.5f);
118 bug0->moveTo(0.5f,5.5f);
119 bug0->lineTo(3.5f,0.5f);
120 }
121
122 {
123 // An X (crbug.com/137317)
124 SkPath* bug1 = &fPaths.push_back();
125
126 bug1->moveTo(1, 1);
127 bug1->lineTo(6, 6);
128 bug1->moveTo(1, 6);
129 bug1->lineTo(6, 1);
130 }
131
132 {
133 // A right angle (crbug.com/137465 and crbug.com/256776)
134 SkPath* bug2 = &fPaths.push_back();
135
136 bug2->moveTo(5.5f, 5.5f);
137 bug2->lineTo(5.5f, 0.5f);
138 bug2->lineTo(0.5f, 0.5f);
139 }
robertphillips@google.com6c000322013-09-26 12:05:32 +0000140
141 {
skia.committer@gmail.com65caeaf2013-09-27 07:01:29 +0000142 // Arc example to test imperfect truncation bug (crbug.com/295626)
robertphillips@google.com6c000322013-09-26 12:05:32 +0000143 static const SkScalar kRad = SkIntToScalar(2000);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000144 static const SkScalar kStartAngle = 262.59717f;
145 static const SkScalar kSweepAngle = SkScalarHalf(17.188717f);
robertphillips@google.com6c000322013-09-26 12:05:32 +0000146
147 SkPath* bug = &fPaths.push_back();
148
149 // Add a circular arc
150 SkRect circle = SkRect::MakeLTRB(-kRad, -kRad, kRad, kRad);
151 bug->addArc(circle, kStartAngle, kSweepAngle);
152
153 // Now add the chord that should cap the circular arc
154 SkScalar cosV, sinV = SkScalarSinCos(SkDegreesToRadians(kStartAngle), &cosV);
155
156 SkPoint p0 = SkPoint::Make(kRad * cosV, kRad * sinV);
157
158 sinV = SkScalarSinCos(SkDegreesToRadians(kStartAngle + kSweepAngle), &cosV);
159
160 SkPoint p1 = SkPoint::Make(kRad * cosV, kRad * sinV);
161
162 bug->moveTo(p0);
163 bug->lineTo(p1);
164 }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000165 }
166
167 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
168 static const SkAlpha kAlphaValue[] = { 0xFF, 0x40 };
169
170 enum {
171 kMargin = 5,
172 };
173 int wrapX = canvas->getDeviceSize().fWidth - kMargin;
174
175 SkScalar maxH = 0;
176 canvas->translate(SkIntToScalar(kMargin), SkIntToScalar(kMargin));
177 canvas->save();
178
179 SkScalar x = SkIntToScalar(kMargin);
180 for (int p = 0; p < fPaths.count(); ++p) {
181 for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphaValue); ++a) {
182 for (int aa = 0; aa < 2; ++aa) {
183 const SkRect& bounds = fPaths[p].getBounds();
184
185 if (x + bounds.width() > wrapX) {
186 canvas->restore();
187 canvas->translate(0, maxH + SkIntToScalar(kMargin));
188 canvas->save();
189 maxH = 0;
190 x = SkIntToScalar(kMargin);
191 }
192
193 SkPaint paint;
194 paint.setARGB(kAlphaValue[a], 0, 0, 0);
195 paint.setAntiAlias(SkToBool(aa));
196 paint.setStyle(SkPaint::kStroke_Style);
197 paint.setStrokeWidth(0);
198
199 canvas->save();
200 canvas->translate(-bounds.fLeft, -bounds.fTop);
201 canvas->drawPath(fPaths[p], paint);
202 canvas->restore();
203
204 maxH = SkMaxScalar(maxH, bounds.height());
205
206 SkScalar dx = bounds.width() + SkIntToScalar(kMargin);
207 x += dx;
208 canvas->translate(dx, 0);
209 }
210 }
211 }
212 canvas->restore();
213 }
214
215private:
216 SkTArray<SkPath> fPaths;
217 typedef GM INHERITED;
218};
219
220//////////////////////////////////////////////////////////////////////////////
221
222static GM* MyFactory(void*) { return new HairlinesGM; }
223static GMRegistry reg(MyFactory);
224
225}