blob: 286cc82d56f0dcc1379c7cc3f89c8c2f1a7f5852 [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:
mtklein72c9faa2015-01-09 10:06:39 -080016 uint32_t onGetFlags() const SK_OVERRIDE {
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000017 return kSkipTiled_Flag;
18 }
19
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000020
mtklein72c9faa2015-01-09 10:06:39 -080021 SkString onShortName() SK_OVERRIDE {
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000022 return SkString("hairlines");
23 }
24
mtklein72c9faa2015-01-09 10:06:39 -080025 SkISize onISize() SK_OVERRIDE { return SkISize::Make(1250, 1250); }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000026
mtklein72c9faa2015-01-09 10:06:39 -080027 void onOnceBeforeDraw() SK_OVERRIDE {
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000028 {
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
mtklein72c9faa2015-01-09 10:06:39 -0800167 void onDraw(SkCanvas* canvas) SK_OVERRIDE {
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000168 static const SkAlpha kAlphaValue[] = { 0xFF, 0x40 };
joshualittbd528cd2014-12-10 14:23:40 -0800169 static const SkScalar kWidths[] = { 0, 0.5f, 1.5f };
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000170
171 enum {
172 kMargin = 5,
173 };
174 int wrapX = canvas->getDeviceSize().fWidth - kMargin;
175
176 SkScalar maxH = 0;
177 canvas->translate(SkIntToScalar(kMargin), SkIntToScalar(kMargin));
178 canvas->save();
179
180 SkScalar x = SkIntToScalar(kMargin);
181 for (int p = 0; p < fPaths.count(); ++p) {
182 for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphaValue); ++a) {
183 for (int aa = 0; aa < 2; ++aa) {
joshualittbd528cd2014-12-10 14:23:40 -0800184 for (size_t w = 0; w < SK_ARRAY_COUNT(kWidths); w++) {
185 const SkRect& bounds = fPaths[p].getBounds();
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000186
joshualittbd528cd2014-12-10 14:23:40 -0800187 if (x + bounds.width() > wrapX) {
188 canvas->restore();
189 canvas->translate(0, maxH + SkIntToScalar(kMargin));
190 canvas->save();
191 maxH = 0;
192 x = SkIntToScalar(kMargin);
193 }
194
195 SkPaint paint;
196 paint.setARGB(kAlphaValue[a], 0, 0, 0);
197 paint.setAntiAlias(SkToBool(aa));
198 paint.setStyle(SkPaint::kStroke_Style);
199 paint.setStrokeWidth(kWidths[w]);
200
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000201 canvas->save();
joshualittbd528cd2014-12-10 14:23:40 -0800202 canvas->translate(-bounds.fLeft, -bounds.fTop);
203 canvas->drawPath(fPaths[p], paint);
204 canvas->restore();
205
206 maxH = SkMaxScalar(maxH, bounds.height());
207
208 SkScalar dx = bounds.width() + SkIntToScalar(kMargin);
209 x += dx;
210 canvas->translate(dx, 0);
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000211 }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000212 }
213 }
214 }
215 canvas->restore();
216 }
217
218private:
219 SkTArray<SkPath> fPaths;
220 typedef GM INHERITED;
221};
222
223//////////////////////////////////////////////////////////////////////////////
224
225static GM* MyFactory(void*) { return new HairlinesGM; }
226static GMRegistry reg(MyFactory);
227
228}