blob: 56f192f345bcfcbccdea14dc5836b3bb69301cd0 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkColor.h"
11#include "include/core/SkPaint.h"
Mike Reede9d783c2020-08-17 14:14:13 -040012#include "include/core/SkPathBuilder.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040013#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"
Kevin Lubickdc6cc022023-01-13 11:24:27 -050019#include "include/private/base/SkTArray.h"
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000020
Herb Derbyec96c212023-03-06 10:31:22 -050021using namespace skia_private;
22
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000023namespace skiagm {
24
25class HairlinesGM : public GM {
26protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +000027 SkString getName() const override { return SkString("hairlines"); }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000028
Leandro Lovisolo8f023882023-08-15 21:13:52 +000029 SkISize getISize() override { return SkISize::Make(1250, 1250); }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000030
mtklein36352bf2015-03-25 18:17:31 -070031 void onOnceBeforeDraw() override {
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000032 {
Mike Reede9d783c2020-08-17 14:14:13 -040033 SkPathBuilder lineAngles;
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000034 enum {
35 kNumAngles = 15,
36 kRadius = 40,
37 };
38 for (int i = 0; i < kNumAngles; ++i) {
39 SkScalar angle = SK_ScalarPI * SkIntToScalar(i) / kNumAngles;
40 SkScalar x = kRadius * SkScalarCos(angle);
41 SkScalar y = kRadius * SkScalarSin(angle);
Mike Reede9d783c2020-08-17 14:14:13 -040042 lineAngles.moveTo(x, y).lineTo(-x, -y);
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000043 }
Mike Reede9d783c2020-08-17 14:14:13 -040044 fPaths.push_back(lineAngles.detach());
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000045 }
46
Mike Reede9d783c2020-08-17 14:14:13 -040047 fPaths.push_back(SkPathBuilder().moveTo(0, -10)
48 .quadTo(100, 100, -10, 0)
49 .detach());
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000050
Mike Reede9d783c2020-08-17 14:14:13 -040051 fPaths.push_back(SkPathBuilder().moveTo(0, -5)
52 .quadTo(100, 100, -5, 0)
53 .detach());
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000054
Mike Reede9d783c2020-08-17 14:14:13 -040055 fPaths.push_back(SkPathBuilder().moveTo(0, -2)
56 .quadTo(100, 100, -2, 0)
57 .detach());
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000058
Mike Reede9d783c2020-08-17 14:14:13 -040059 fPaths.push_back(SkPathBuilder().moveTo(0, -1)
60 .quadTo(100, 100, -2 + 306.0f / 4, 75)
61 .detach());
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000062
Mike Reede9d783c2020-08-17 14:14:13 -040063 fPaths.push_back(SkPathBuilder().moveTo(0, -1)
64 .quadTo(100, 100, -1, 0)
65 .detach());
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000066
Mike Reede9d783c2020-08-17 14:14:13 -040067 fPaths.push_back(SkPathBuilder().moveTo(0, -0)
68 .quadTo(100, 100, 0, 0)
69 .detach());
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +000070
Mike Reede9d783c2020-08-17 14:14:13 -040071 fPaths.push_back(SkPathBuilder().moveTo(0, -0)
72 .quadTo(100, 100, 75, 75)
73 .detach());
commit-bot@chromium.orgb8bd6cb2013-09-03 14:56:17 +000074
75 // Two problem cases for gpu hairline renderer found by shapeops testing. These used
76 // to assert that the computed bounding box didn't contain all the vertices.
commit-bot@chromium.orgb8bd6cb2013-09-03 14:56:17 +000077
Mike Reede9d783c2020-08-17 14:14:13 -040078 fPaths.push_back(SkPathBuilder().moveTo(4, 6)
79 .cubicTo(5, 6, 5, 4, 4, 0)
80 .close()
81 .detach());
82
83 fPaths.push_back(SkPathBuilder().moveTo(5, 1)
84 .lineTo( 4.32787323f, 1.67212653f)
85 .cubicTo(2.75223875f, 3.24776125f,
86 3.00581908f, 4.51236057f,
87 3.7580452f, 4.37367964f)
88 .cubicTo(4.66472578f, 3.888381f,
89 5.f, 2.875f,
90 5.f, 1.f)
91 .close()
92 .detach());
robertphillips@google.comada90da2013-09-18 22:14:49 +000093
94 // Three paths that show the same bug (missing end caps)
robertphillips@google.comada90da2013-09-18 22:14:49 +000095
Mike Reede9d783c2020-08-17 14:14:13 -040096 fPaths.push_back(SkPathBuilder().moveTo(6.5f,5.5f)
97 .lineTo(3.5f,0.5f)
98 .moveTo(0.5f,5.5f)
99 .lineTo(3.5f,0.5f)
100 .detach());
robertphillips@google.comada90da2013-09-18 22:14:49 +0000101
Mike Reede9d783c2020-08-17 14:14:13 -0400102 // An X (crbug.com/137317)
103 fPaths.push_back(SkPathBuilder().moveTo(1, 1)
104 .lineTo(6, 6)
105 .moveTo(1, 6)
106 .lineTo(6, 1)
107 .detach());
robertphillips@google.comada90da2013-09-18 22:14:49 +0000108
Mike Reede9d783c2020-08-17 14:14:13 -0400109 // A right angle (crbug.com/137465 and crbug.com/256776)
110 fPaths.push_back(SkPathBuilder().moveTo(5.5f, 5.5f)
111 .lineTo(5.5f, 0.5f)
112 .lineTo(0.5f, 0.5f)
113 .detach());
robertphillips@google.com6c000322013-09-26 12:05:32 +0000114
115 {
skia.committer@gmail.com65caeaf2013-09-27 07:01:29 +0000116 // Arc example to test imperfect truncation bug (crbug.com/295626)
mtkleindbfd7ab2016-09-01 11:24:54 -0700117 constexpr SkScalar kRad = SkIntToScalar(2000);
118 constexpr SkScalar kStartAngle = 262.59717f;
119 constexpr SkScalar kSweepAngle = SkScalarHalf(17.188717f);
robertphillips@google.com6c000322013-09-26 12:05:32 +0000120
Mike Reede9d783c2020-08-17 14:14:13 -0400121 SkPathBuilder bug;
robertphillips@google.com6c000322013-09-26 12:05:32 +0000122
123 // Add a circular arc
124 SkRect circle = SkRect::MakeLTRB(-kRad, -kRad, kRad, kRad);
Mike Reede9d783c2020-08-17 14:14:13 -0400125 bug.addArc(circle, kStartAngle, kSweepAngle);
robertphillips@google.com6c000322013-09-26 12:05:32 +0000126
127 // Now add the chord that should cap the circular arc
Brian Osman4428f2c2019-04-02 10:59:28 -0400128 SkPoint p0 = { kRad * SkScalarCos(SkDegreesToRadians(kStartAngle)),
129 kRad * SkScalarSin(SkDegreesToRadians(kStartAngle)) };
robertphillips@google.com6c000322013-09-26 12:05:32 +0000130
Brian Osman4428f2c2019-04-02 10:59:28 -0400131 SkPoint p1 = { kRad * SkScalarCos(SkDegreesToRadians(kStartAngle + kSweepAngle)),
132 kRad * SkScalarSin(SkDegreesToRadians(kStartAngle + kSweepAngle)) };
robertphillips@google.com6c000322013-09-26 12:05:32 +0000133
Mike Reede9d783c2020-08-17 14:14:13 -0400134 bug.moveTo(p0);
135 bug.lineTo(p1);
136 fPaths.push_back(bug.detach());
robertphillips@google.com6c000322013-09-26 12:05:32 +0000137 }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000138 }
139
mtklein36352bf2015-03-25 18:17:31 -0700140 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -0700141 constexpr SkAlpha kAlphaValue[] = { 0xFF, 0x40 };
142 constexpr SkScalar kWidths[] = { 0, 0.5f, 1.5f };
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000143
144 enum {
145 kMargin = 5,
146 };
reed9aeb2a12015-04-11 19:29:50 -0700147 int wrapX = 1250 - kMargin;
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000148
149 SkScalar maxH = 0;
150 canvas->translate(SkIntToScalar(kMargin), SkIntToScalar(kMargin));
151 canvas->save();
152
153 SkScalar x = SkIntToScalar(kMargin);
Herb Derbyffacce52022-11-09 10:51:34 -0500154 for (int p = 0; p < fPaths.size(); ++p) {
Herb Derbyc37b3862022-06-21 09:49:17 -0400155 for (size_t a = 0; a < std::size(kAlphaValue); ++a) {
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000156 for (int aa = 0; aa < 2; ++aa) {
Herb Derbyc37b3862022-06-21 09:49:17 -0400157 for (size_t w = 0; w < std::size(kWidths); w++) {
joshualittbd528cd2014-12-10 14:23:40 -0800158 const SkRect& bounds = fPaths[p].getBounds();
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000159
joshualittbd528cd2014-12-10 14:23:40 -0800160 if (x + bounds.width() > wrapX) {
161 canvas->restore();
162 canvas->translate(0, maxH + SkIntToScalar(kMargin));
163 canvas->save();
164 maxH = 0;
165 x = SkIntToScalar(kMargin);
166 }
167
168 SkPaint paint;
169 paint.setARGB(kAlphaValue[a], 0, 0, 0);
170 paint.setAntiAlias(SkToBool(aa));
171 paint.setStyle(SkPaint::kStroke_Style);
172 paint.setStrokeWidth(kWidths[w]);
173
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000174 canvas->save();
joshualittbd528cd2014-12-10 14:23:40 -0800175 canvas->translate(-bounds.fLeft, -bounds.fTop);
176 canvas->drawPath(fPaths[p], paint);
177 canvas->restore();
178
Brian Osman116b33e2020-02-05 13:34:09 -0500179 maxH = std::max(maxH, bounds.height());
joshualittbd528cd2014-12-10 14:23:40 -0800180
181 SkScalar dx = bounds.width() + SkIntToScalar(kMargin);
182 x += dx;
183 canvas->translate(dx, 0);
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000184 }
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000185 }
186 }
187 }
188 canvas->restore();
189 }
190
191private:
Herb Derbyec96c212023-03-06 10:31:22 -0500192 TArray<SkPath> fPaths;
John Stiles7571f9e2020-09-02 22:42:33 -0400193 using INHERITED = GM;
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000194};
195
caryclarkc3262572015-12-04 11:08:42 -0800196static void draw_squarehair_tests(SkCanvas* canvas, SkScalar width, SkPaint::Cap cap, bool aa) {
197 SkPaint paint;
198 paint.setStrokeCap(cap);
199 paint.setStrokeWidth(width);
200 paint.setAntiAlias(aa);
201 paint.setStyle(SkPaint::kStroke_Style);
202 canvas->drawLine(10, 10, 20, 10, paint);
203 canvas->drawLine(30, 10, 30, 20, paint);
204 canvas->drawLine(40, 10, 50, 20, paint);
Mike Reede9d783c2020-08-17 14:14:13 -0400205 SkPathBuilder path;
caryclarkc3262572015-12-04 11:08:42 -0800206 path.moveTo(60, 10);
207 path.quadTo(60, 20, 70, 20);
208 path.conicTo(70, 10, 80, 10, 0.707f);
Mike Reede9d783c2020-08-17 14:14:13 -0400209 canvas->drawPath(path.detach(), paint);
210
caryclarkc3262572015-12-04 11:08:42 -0800211 path.moveTo(90, 10);
212 path.cubicTo(90, 20, 100, 20, 100, 10);
213 path.lineTo(110, 10);
Mike Reede9d783c2020-08-17 14:14:13 -0400214 canvas->drawPath(path.detach(), paint);
caryclarkc3262572015-12-04 11:08:42 -0800215 canvas->translate(0, 30);
216}
217
218DEF_SIMPLE_GM(squarehair, canvas, 240, 360) {
219 const bool aliases[] = { false, true };
220 const SkScalar widths[] = { 0, 0.999f, 1, 1.001f };
221 const SkPaint::Cap caps[] = { SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap };
222 for (auto alias : aliases) {
223 canvas->save();
224 for (auto width : widths) {
225 for (auto cap : caps) {
226 draw_squarehair_tests(canvas, width, cap, alias);
227 }
228 }
229 canvas->restore();
230 canvas->translate(120, 0);
231 }
232}
233
Jim Van Verthb4610552020-07-15 13:26:43 -0400234// GM to test subdivision of hairlines
235static void draw_subdivided_quad(SkCanvas* canvas, int x0, int y0, int x1, int y1, SkColor color) {
236 SkPaint paint;
237 paint.setStrokeWidth(1);
238 paint.setAntiAlias(true);
239 paint.setStyle(SkPaint::kStroke_Style);
240 paint.setColor(color);
241
Mike Reedd16d6542020-08-22 15:08:27 -0400242 canvas->drawPath(SkPathBuilder().moveTo(0,0)
243 .quadTo(SkIntToScalar(x0), SkIntToScalar(y0),
244 SkIntToScalar(x1), SkIntToScalar(y1))
245 .detach(),
246 paint);
Jim Van Verthb4610552020-07-15 13:26:43 -0400247}
248
249DEF_SIMPLE_GM(hairline_subdiv, canvas, 512, 256) {
250 // no subdivisions
251 canvas->translate(45, -25);
252 draw_subdivided_quad(canvas, 334, 334, 467, 267, SK_ColorBLACK);
253
254 // one subdivision
255 canvas->translate(-185, -150);
256 draw_subdivided_quad(canvas, 472, 472, 660, 378, SK_ColorRED);
257
258 // two subdivisions
259 canvas->translate(-275, -200);
260 draw_subdivided_quad(canvas, 668, 668, 934, 535, SK_ColorGREEN);
261
262 // three subdivisions
263 canvas->translate(-385, -260);
264 draw_subdivided_quad(canvas, 944, 944, 1320, 756, SK_ColorBLUE);
265}
266
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000267//////////////////////////////////////////////////////////////////////////////
268
Hal Canarye964c182019-01-23 10:22:01 -0500269DEF_GM( return new HairlinesGM; )
commit-bot@chromium.org912e68e2013-05-24 18:51:55 +0000270
John Stilesa6841be2020-08-06 14:11:56 -0400271} // namespace skiagm