1 /*
2 * Copyright 2011 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/SkPath.h"
13 #include "include/core/SkPathEffect.h"
14 #include "include/core/SkPathUtils.h"
15 #include "include/core/SkPoint.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkScalar.h"
18 #include "include/core/SkSize.h"
19 #include "include/core/SkString.h"
20 #include "include/core/SkTypes.h"
21 #include "include/effects/SkDashPathEffect.h"
22 #include "include/utils/SkParsePath.h"
23 #include "src/base/SkFloatBits.h"
24 #include "src/base/SkRandom.h"
25 #include "tools/ToolUtils.h"
26
27 #include <string.h>
28
29 #if defined(SK_GRAPHITE)
30 #include "include/gpu/graphite/ContextOptions.h"
31 #endif
32
33 #define W 400
34 #define H 400
35 #define N 50
36
37 constexpr SkScalar SW = SkIntToScalar(W);
38 constexpr SkScalar SH = SkIntToScalar(H);
39
rnd_rect(SkRect * r,SkPaint * paint,SkRandom & rand)40 static void rnd_rect(SkRect* r, SkPaint* paint, SkRandom& rand) {
41 SkScalar x = rand.nextUScalar1() * W;
42 SkScalar y = rand.nextUScalar1() * H;
43 SkScalar w = rand.nextUScalar1() * (W >> 2);
44 SkScalar h = rand.nextUScalar1() * (H >> 2);
45 SkScalar hoffset = rand.nextSScalar1();
46 SkScalar woffset = rand.nextSScalar1();
47
48 r->setXYWH(x, y, w, h);
49 r->offset(-w/2 + woffset, -h/2 + hoffset);
50
51 paint->setColor(rand.nextU());
52 paint->setAlphaf(1.0f);
53 }
54
55
56 class StrokesGM : public skiagm::GM {
57 public:
StrokesGM()58 StrokesGM() {}
59
60 protected:
getName() const61 SkString getName() const override { return SkString("strokes_round"); }
62
getISize()63 SkISize getISize() override { return SkISize::Make(W, H * 2); }
64
65 #if defined(SK_GRAPHITE)
modifyGraphiteContextOptions(skgpu::graphite::ContextOptions * options) const66 void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions* options) const override {
67 options->fMaxPathAtlasTextureSize = 0;
68 options->fAllowMultipleAtlasTextures = false;
69 }
70 #endif
71
onDraw(SkCanvas * canvas)72 void onDraw(SkCanvas* canvas) override {
73 SkPaint paint;
74 paint.setStyle(SkPaint::kStroke_Style);
75 paint.setStrokeWidth(SkIntToScalar(9)/2);
76
77 for (int y = 0; y < 2; y++) {
78 paint.setAntiAlias(!!y);
79 SkAutoCanvasRestore acr(canvas, true);
80 canvas->translate(0, SH * y);
81 canvas->clipRect(SkRect::MakeLTRB(
82 SkIntToScalar(2), SkIntToScalar(2)
83 , SW - SkIntToScalar(2), SH - SkIntToScalar(2)
84 ));
85
86 SkRandom rand;
87 for (int i = 0; i < N; i++) {
88 SkRect r;
89 rnd_rect(&r, &paint, rand);
90 canvas->drawOval(r, paint);
91 rnd_rect(&r, &paint, rand);
92 canvas->drawRoundRect(r, r.width()/4, r.height()/4, paint);
93 rnd_rect(&r, &paint, rand);
94 }
95 }
96 }
97
98 private:
99 using INHERITED = skiagm::GM;
100 };
101
102 /* See
103 https://code.google.com/p/chromium/issues/detail?id=422974 and
104 http://jsfiddle.net/1xnku3sg/2/
105 */
106 class ZeroLenStrokesGM : public skiagm::GM {
107 SkPath fMoveHfPath, fMoveZfPath, fDashedfPath, fRefPath[4];
108 SkPath fCubicPath, fQuadPath, fLinePath;
109 protected:
onOnceBeforeDraw()110 void onOnceBeforeDraw() override {
111
112 SkAssertResult(SkParsePath::FromSVGString("M0,0h0M10,0h0M20,0h0", &fMoveHfPath));
113 SkAssertResult(SkParsePath::FromSVGString("M0,0zM10,0zM20,0z", &fMoveZfPath));
114 SkAssertResult(SkParsePath::FromSVGString("M0,0h25", &fDashedfPath));
115 SkAssertResult(SkParsePath::FromSVGString("M 0 0 C 0 0 0 0 0 0", &fCubicPath));
116 SkAssertResult(SkParsePath::FromSVGString("M 0 0 Q 0 0 0 0", &fQuadPath));
117 SkAssertResult(SkParsePath::FromSVGString("M 0 0 L 0 0", &fLinePath));
118
119 for (int i = 0; i < 3; ++i) {
120 fRefPath[0].addCircle(i * 10.f, 0, 5);
121 fRefPath[1].addCircle(i * 10.f, 0, 10);
122 fRefPath[2].addRect(i * 10.f - 4, -2, i * 10.f + 4, 6);
123 fRefPath[3].addRect(i * 10.f - 10, -10, i * 10.f + 10, 10);
124 }
125 }
126
getName() const127 SkString getName() const override { return SkString("zeroPath"); }
128
getISize()129 SkISize getISize() override { return SkISize::Make(W, H * 2); }
130
onDraw(SkCanvas * canvas)131 void onDraw(SkCanvas* canvas) override {
132 SkPaint fillPaint, strokePaint, dashPaint;
133 fillPaint.setAntiAlias(true);
134 strokePaint = fillPaint;
135 strokePaint.setStyle(SkPaint::kStroke_Style);
136 for (int i = 0; i < 2; ++i) {
137 fillPaint.setAlphaf(1.0f);
138 strokePaint.setAlphaf(1.0f);
139 strokePaint.setStrokeWidth(i ? 8.f : 10.f);
140 strokePaint.setStrokeCap(i ? SkPaint::kSquare_Cap : SkPaint::kRound_Cap);
141 canvas->save();
142 canvas->translate(10 + i * 100.f, 10);
143 canvas->drawPath(fMoveHfPath, strokePaint);
144 canvas->translate(0, 20);
145 canvas->drawPath(fMoveZfPath, strokePaint);
146 dashPaint = strokePaint;
147 const SkScalar intervals[] = { 0, 10 };
148 dashPaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
149 SkPath fillPath;
150 skpathutils::FillPathWithPaint(fDashedfPath, dashPaint, &fillPath);
151 canvas->translate(0, 20);
152 canvas->drawPath(fDashedfPath, dashPaint);
153 canvas->translate(0, 20);
154 canvas->drawPath(fRefPath[i * 2], fillPaint);
155 strokePaint.setStrokeWidth(20);
156 strokePaint.setAlphaf(0.5f);
157 canvas->translate(0, 50);
158 canvas->drawPath(fMoveHfPath, strokePaint);
159 canvas->translate(0, 30);
160 canvas->drawPath(fMoveZfPath, strokePaint);
161 canvas->translate(0, 30);
162 fillPaint.setAlphaf(0.5f);
163 canvas->drawPath(fRefPath[1 + i * 2], fillPaint);
164 canvas->translate(0, 30);
165 canvas->drawPath(fCubicPath, strokePaint);
166 canvas->translate(0, 30);
167 canvas->drawPath(fQuadPath, strokePaint);
168 canvas->translate(0, 30);
169 canvas->drawPath(fLinePath, strokePaint);
170 canvas->restore();
171 }
172 }
173
174 private:
175 using INHERITED = skiagm::GM;
176 };
177
178 class TeenyStrokesGM : public skiagm::GM {
getName() const179 SkString getName() const override { return SkString("teenyStrokes"); }
180
getISize()181 SkISize getISize() override { return SkISize::Make(W, H * 2); }
182
line(SkScalar scale,SkCanvas * canvas,SkColor color)183 static void line(SkScalar scale, SkCanvas* canvas, SkColor color) {
184 SkPaint p;
185 p.setAntiAlias(true);
186 p.setStyle(SkPaint::kStroke_Style);
187 p.setColor(color);
188 canvas->translate(50, 0);
189 canvas->save();
190 p.setStrokeWidth(scale * 5);
191 canvas->scale(1 / scale, 1 / scale);
192 canvas->drawLine(20 * scale, 20 * scale, 20 * scale, 100 * scale, p);
193 canvas->drawLine(20 * scale, 20 * scale, 100 * scale, 100 * scale, p);
194 canvas->restore();
195 }
196
onDraw(SkCanvas * canvas)197 void onDraw(SkCanvas* canvas) override {
198 line(0.00005f, canvas, SK_ColorBLACK);
199 line(0.000045f, canvas, SK_ColorRED);
200 line(0.0000035f, canvas, SK_ColorGREEN);
201 line(0.000003f, canvas, SK_ColorBLUE);
202 line(0.000002f, canvas, SK_ColorBLACK);
203 }
204 private:
205 using INHERITED = skiagm::GM;
206 };
207
208 DEF_SIMPLE_GM(CubicStroke, canvas, 384, 384) {
209 SkPaint p;
210 p.setAntiAlias(true);
211 p.setStyle(SkPaint::kStroke_Style);
212 p.setStrokeWidth(1.0720f);
213 SkPath path;
214 path.moveTo(-6000,-6000);
215 path.cubicTo(-3500,5500,-500,5500,2500,-6500);
216 canvas->drawPath(path, p);
217 p.setStrokeWidth(1.0721f);
218 canvas->translate(10, 10);
219 canvas->drawPath(path, p);
220 p.setStrokeWidth(1.0722f);
221 canvas->translate(10, 10);
222 canvas->drawPath(path, p);
223 }
224
225 DEF_SIMPLE_GM(zerolinestroke, canvas, 90, 120) {
226 SkPaint paint;
227 paint.setStyle(SkPaint::kStroke_Style);
228 paint.setStrokeWidth(20);
229 paint.setAntiAlias(true);
230 paint.setStrokeCap(SkPaint::kRound_Cap);
231
232 SkPath path;
233 path.moveTo(30, 90);
234 path.lineTo(30, 90);
235 path.lineTo(60, 90);
236 path.lineTo(60, 90);
237 canvas->drawPath(path, paint);
238
239 path.reset();
240 path.moveTo(30, 30);
241 path.lineTo(60, 30);
242 canvas->drawPath(path, paint);
243
244 path.reset();
245 path.moveTo(30, 60);
246 path.lineTo(30, 60);
247 path.lineTo(60, 60);
248 canvas->drawPath(path, paint);
249 }
250
251 DEF_SIMPLE_GM(quadcap, canvas, 200, 200) {
252 SkPaint p;
253 p.setAntiAlias(true);
254 p.setStyle(SkPaint::kStroke_Style);
255 p.setStrokeWidth(0);
256 SkPath path;
257 SkPoint pts[] = {{105.738571f,13.126318f},
258 {105.738571f,13.126318f},
259 {123.753784f,1.f}};
260 SkVector tangent = pts[1] - pts[2];
261 tangent.normalize();
262 SkPoint pts2[3];
263 memcpy(pts2, pts, sizeof(pts));
264 const SkScalar capOutset = SK_ScalarPI / 8;
265 pts2[0].fX += tangent.fX * capOutset;
266 pts2[0].fY += tangent.fY * capOutset;
267 pts2[1].fX += tangent.fX * capOutset;
268 pts2[1].fY += tangent.fY * capOutset;
269 pts2[2].fX += -tangent.fX * capOutset;
270 pts2[2].fY += -tangent.fY * capOutset;
271 path.moveTo(pts2[0]);
272 path.quadTo(pts2[1], pts2[2]);
273 canvas->drawPath(path, p);
274
275 path.reset();
276 path.moveTo(pts[0]);
277 path.quadTo(pts[1], pts[2]);
278 p.setStrokeCap(SkPaint::kRound_Cap);
279 canvas->translate(30, 0);
280 canvas->drawPath(path, p);
281 }
282
283 class Strokes2GM : public skiagm::GM {
284 SkPath fPath;
285 protected:
onOnceBeforeDraw()286 void onOnceBeforeDraw() override {
287 SkRandom rand;
288 fPath.moveTo(0, 0);
289 for (int i = 0; i < 13; i++) {
290 SkScalar x = rand.nextUScalar1() * (W >> 1);
291 SkScalar y = rand.nextUScalar1() * (H >> 1);
292 fPath.lineTo(x, y);
293 }
294 }
295
getName() const296 SkString getName() const override { return SkString("strokes_poly"); }
297
getISize()298 SkISize getISize() override { return SkISize::Make(W, H * 2); }
299
onDraw(SkCanvas * canvas)300 void onDraw(SkCanvas* canvas) override {
301 canvas->drawColor(SK_ColorWHITE);
302
303 SkPaint paint;
304 paint.setStyle(SkPaint::kStroke_Style);
305 paint.setStrokeWidth(SkIntToScalar(9)/2);
306
307 for (int y = 0; y < 2; y++) {
308 paint.setAntiAlias(!!y);
309 SkAutoCanvasRestore acr(canvas, true);
310 canvas->translate(0, SH * y);
311 canvas->clipRect(SkRect::MakeLTRB(SkIntToScalar(2),
312 SkIntToScalar(2),
313 SW - SkIntToScalar(2),
314 SH - SkIntToScalar(2)));
315
316 SkRandom rand;
317 for (int i = 0; i < N/2; i++) {
318 SkRect r;
319 rnd_rect(&r, &paint, rand);
320 canvas->rotate(SkIntToScalar(15), SW/2, SH/2);
321 canvas->drawPath(fPath, paint);
322 }
323 }
324 }
325
326 private:
327 using INHERITED = skiagm::GM;
328 };
329
330 //////////////////////////////////////////////////////////////////////////////
331
inset(const SkRect & r)332 static SkRect inset(const SkRect& r) {
333 SkRect rr(r);
334 rr.inset(r.width()/10, r.height()/10);
335 return rr;
336 }
337
338 class Strokes3GM : public skiagm::GM {
make0(SkPath * path,const SkRect & bounds,SkString * title)339 static void make0(SkPath* path, const SkRect& bounds, SkString* title) {
340 path->addRect(bounds, SkPathDirection::kCW);
341 path->addRect(inset(bounds), SkPathDirection::kCW);
342 title->set("CW CW");
343 }
344
make1(SkPath * path,const SkRect & bounds,SkString * title)345 static void make1(SkPath* path, const SkRect& bounds, SkString* title) {
346 path->addRect(bounds, SkPathDirection::kCW);
347 path->addRect(inset(bounds), SkPathDirection::kCCW);
348 title->set("CW CCW");
349 }
350
make2(SkPath * path,const SkRect & bounds,SkString * title)351 static void make2(SkPath* path, const SkRect& bounds, SkString* title) {
352 path->addOval(bounds, SkPathDirection::kCW);
353 path->addOval(inset(bounds), SkPathDirection::kCW);
354 title->set("CW CW");
355 }
356
make3(SkPath * path,const SkRect & bounds,SkString * title)357 static void make3(SkPath* path, const SkRect& bounds, SkString* title) {
358 path->addOval(bounds, SkPathDirection::kCW);
359 path->addOval(inset(bounds), SkPathDirection::kCCW);
360 title->set("CW CCW");
361 }
362
make4(SkPath * path,const SkRect & bounds,SkString * title)363 static void make4(SkPath* path, const SkRect& bounds, SkString* title) {
364 path->addRect(bounds, SkPathDirection::kCW);
365 SkRect r = bounds;
366 r.inset(bounds.width() / 10, -bounds.height() / 10);
367 path->addOval(r, SkPathDirection::kCW);
368 title->set("CW CW");
369 }
370
make5(SkPath * path,const SkRect & bounds,SkString * title)371 static void make5(SkPath* path, const SkRect& bounds, SkString* title) {
372 path->addRect(bounds, SkPathDirection::kCW);
373 SkRect r = bounds;
374 r.inset(bounds.width() / 10, -bounds.height() / 10);
375 path->addOval(r, SkPathDirection::kCCW);
376 title->set("CW CCW");
377 }
378
379 public:
Strokes3GM()380 Strokes3GM() {}
381
382 protected:
getName() const383 SkString getName() const override { return SkString("strokes3"); }
384
getISize()385 SkISize getISize() override { return SkISize::Make(1500, 1500); }
386
onDraw(SkCanvas * canvas)387 void onDraw(SkCanvas* canvas) override {
388 SkPaint origPaint;
389 origPaint.setAntiAlias(true);
390 origPaint.setStyle(SkPaint::kStroke_Style);
391 SkPaint fillPaint(origPaint);
392 fillPaint.setColor(SK_ColorRED);
393 SkPaint strokePaint(origPaint);
394 strokePaint.setColor(ToolUtils::color_to_565(0xFF4444FF));
395
396 void (*procs[])(SkPath*, const SkRect&, SkString*) = {
397 make0, make1, make2, make3, make4, make5
398 };
399
400 canvas->translate(SkIntToScalar(20), SkIntToScalar(80));
401
402 SkRect bounds = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50));
403 SkScalar dx = bounds.width() * 4/3;
404 SkScalar dy = bounds.height() * 5;
405
406 for (size_t i = 0; i < std::size(procs); ++i) {
407 SkPath orig;
408 SkString str;
409 procs[i](&orig, bounds, &str);
410
411 canvas->save();
412 for (int j = 0; j < 13; ++j) {
413 strokePaint.setStrokeWidth(SK_Scalar1 * j * j);
414 canvas->drawPath(orig, strokePaint);
415 canvas->drawPath(orig, origPaint);
416 SkPath fill;
417 skpathutils::FillPathWithPaint(orig, strokePaint, &fill);
418 canvas->drawPath(fill, fillPaint);
419 canvas->translate(dx + strokePaint.getStrokeWidth(), 0);
420 }
421 canvas->restore();
422 canvas->translate(0, dy);
423 }
424 }
425
426 private:
427 using INHERITED = skiagm::GM;
428 };
429
430 class Strokes4GM : public skiagm::GM {
431 public:
Strokes4GM()432 Strokes4GM() {}
433
434 protected:
getName() const435 SkString getName() const override { return SkString("strokes_zoomed"); }
436
getISize()437 SkISize getISize() override { return SkISize::Make(W, H * 2); }
438
onDraw(SkCanvas * canvas)439 void onDraw(SkCanvas* canvas) override {
440 SkPaint paint;
441 paint.setStyle(SkPaint::kStroke_Style);
442 paint.setStrokeWidth(0.055f);
443
444 canvas->scale(1000, 1000);
445 canvas->drawCircle(0, 2, 1.97f, paint);
446 }
447
448 private:
449 using INHERITED = skiagm::GM;
450 };
451
452 // Test stroking for curves that produce degenerate tangents when t is 0 or 1 (see bug 4191)
453 class Strokes5GM : public skiagm::GM {
454 public:
Strokes5GM()455 Strokes5GM() {}
456
457 protected:
getName() const458 SkString getName() const override { return SkString("zero_control_stroke"); }
459
getISize()460 SkISize getISize() override { return SkISize::Make(W, H * 2); }
461
onDraw(SkCanvas * canvas)462 void onDraw(SkCanvas* canvas) override {
463 SkPaint p;
464 p.setColor(SK_ColorRED);
465 p.setAntiAlias(true);
466 p.setStyle(SkPaint::kStroke_Style);
467 p.setStrokeWidth(40);
468 p.setStrokeCap(SkPaint::kButt_Cap);
469
470 SkPath path;
471 path.moveTo(157.474f,111.753f);
472 path.cubicTo(128.5f,111.5f,35.5f,29.5f,35.5f,29.5f);
473 canvas->drawPath(path, p);
474 path.reset();
475 path.moveTo(250, 50);
476 path.quadTo(280, 80, 280, 80);
477 canvas->drawPath(path, p);
478 path.reset();
479 path.moveTo(150, 50);
480 path.conicTo(180, 80, 180, 80, 0.707f);
481 canvas->drawPath(path, p);
482
483 path.reset();
484 path.moveTo(157.474f,311.753f);
485 path.cubicTo(157.474f,311.753f,85.5f,229.5f,35.5f,229.5f);
486 canvas->drawPath(path, p);
487 path.reset();
488 path.moveTo(280, 250);
489 path.quadTo(280, 250, 310, 280);
490 canvas->drawPath(path, p);
491 path.reset();
492 path.moveTo(180, 250);
493 path.conicTo(180, 250, 210, 280, 0.707f);
494 canvas->drawPath(path, p);
495 }
496
497 private:
498 using INHERITED = skiagm::GM;
499 };
500
501
502 //////////////////////////////////////////////////////////////////////////////
503
504 DEF_GM( return new StrokesGM; )
DEF_GM(return new Strokes2GM;)505 DEF_GM( return new Strokes2GM; )
506 DEF_GM( return new Strokes3GM; )
507 DEF_GM( return new Strokes4GM; )
508 DEF_GM( return new Strokes5GM; )
509
510 DEF_GM( return new ZeroLenStrokesGM; )
511 DEF_GM( return new TeenyStrokesGM; )
512
513 DEF_SIMPLE_GM(zerolinedash, canvas, 256, 256) {
514 canvas->clear(SK_ColorWHITE);
515
516 SkPaint paint;
517 paint.setColor(SkColorSetARGB(255, 0, 0, 0));
518 paint.setStrokeWidth(11);
519 paint.setStrokeCap(SkPaint::kRound_Cap);
520 paint.setStrokeJoin(SkPaint::kBevel_Join);
521
522 SkScalar dash_pattern[] = {1, 5};
523 paint.setPathEffect(SkDashPathEffect::Make(dash_pattern, 2, 0));
524
525 canvas->drawLine(100, 100, 100, 100, paint);
526 }
527
528 #ifdef PDF_IS_FIXED_SO_THIS_DOESNT_BREAK_IT
529 DEF_SIMPLE_GM(longrect_dash, canvas, 250, 250) {
530 canvas->clear(SK_ColorWHITE);
531
532 SkPaint paint;
533 paint.setColor(SkColorSetARGB(255, 0, 0, 0));
534 paint.setStrokeWidth(5);
535 paint.setStrokeCap(SkPaint::kRound_Cap);
536 paint.setStrokeJoin(SkPaint::kBevel_Join);
537 paint.setStyle(SkPaint::kStroke_Style);
538 SkScalar dash_pattern[] = {1, 5};
539 paint.setPathEffect(SkDashPathEffect::Make(dash_pattern, 2, 0));
540 // try all combinations of stretching bounds
541 for (auto left : { 20.f, -100001.f } ) {
542 for (auto top : { 20.f, -100001.f } ) {
543 for (auto right : { 40.f, 100001.f } ) {
544 for (auto bottom : { 40.f, 100001.f } ) {
545 canvas->save();
546 canvas->clipRect({10, 10, 50, 50});
547 canvas->drawRect({left, top, right, bottom}, paint);
548 canvas->restore();
549 canvas->translate(60, 0);
550 }
551 }
552 canvas->translate(-60 * 4, 60);
553 }
554 }
555 }
556 #endif
557
558 DEF_SIMPLE_GM(inner_join_geometry, canvas, 1000, 700) {
559 // These paths trigger cases where we must add inner join geometry.
560 // skbug.com/11964
561 const SkPoint pathPoints[] = {
562 /*moveTo*/ /*lineTo*/ /*lineTo*/
563 {119, 71}, {129, 151}, {230, 24},
564 {200, 144}, {129, 151}, {230, 24},
565 {192, 176}, {224, 175}, {281, 103},
566 {233, 205}, {224, 175}, {281, 103},
567 {121, 216}, {234, 189}, {195, 147},
568 {141, 216}, {254, 189}, {238, 250},
569 {159, 202}, {269, 197}, {289, 165},
570 {159, 202}, {269, 197}, {287, 227},
571 };
572
573 SkPaint pathPaint;
574 pathPaint.setStroke(true);
575 pathPaint.setAntiAlias(true);
576 pathPaint.setStrokeWidth(100);
577
578 SkPaint skeletonPaint;
579 skeletonPaint.setStroke(true);
580 skeletonPaint.setAntiAlias(true);
581 skeletonPaint.setStrokeWidth(0);
582 skeletonPaint.setColor(SK_ColorRED);
583
584 canvas->translate(0, 50);
585 for (size_t i = 0; i < std::size(pathPoints) / 3; i++) {
586 auto path = SkPath::Polygon(pathPoints + i * 3, 3, false);
587 canvas->drawPath(path, pathPaint);
588
589 SkPath fillPath;
590 skpathutils::FillPathWithPaint(path, pathPaint, &fillPath);
591 canvas->drawPath(fillPath, skeletonPaint);
592
593 canvas->translate(200, 0);
594 if ((i + 1) % 4 == 0) {
595 canvas->translate(-800, 200);
596 }
597 }
598 }
599
600 DEF_SIMPLE_GM(skbug12244, canvas, 150, 150) {
601 // Should look like a stroked triangle; these vertices are the results of the SkStroker
602 // but we draw as a filled path in order to highlight that it's the GPU triangulating path
603 // renderer that's the source of the problem, and not the stroking operation. The original
604 // path was a simple:
605 // m(0,0), l(100, 40), l(0, 80), l(0,0) with a stroke width of 15px
606 SkPath path;
607 path.moveTo(2.7854299545288085938, -6.9635753631591796875);
608 path.lineTo( 120.194366455078125, 40);
609 path.lineTo(-7.5000004768371582031, 91.07775115966796875);
610 path.lineTo(-7.5000004768371582031, -11.077748298645019531);
611 path.lineTo(2.7854299545288085938, -6.9635753631591796875);
612 path.moveTo(-2.7854299545288085938, 6.9635753631591796875);
613 path.lineTo( 0, 0);
614 path.lineTo( 7.5, 0);
615 path.lineTo(7.5000004768371582031, 68.92224884033203125);
616 path.lineTo( 79.805633544921875, 40);
617 path.lineTo(-2.7854299545288085938, 6.9635753631591796875);
618
619 SkPaint p;
620 p.setColor(SK_ColorGREEN);
621
622 canvas->translate(20.f, 20.f);
623 canvas->drawPath(path, p);
624 }
625
626 DEF_SIMPLE_GM(b_340982297, canvas, 80, 50) {
627 SkPaint paint;
628 paint.setAntiAlias(true);
629
630 SkPath path;
631 path.moveTo(30.23983f, 48.5674667f);
632 path.lineTo(1.30884242f, 45.5222702f);
633 path.lineTo(2.97688866f, 29.6749554f);
634 path.lineTo(17.4423828f, 31.1975555f);
635 path.lineTo(2.94269657f, 30.0452003f);
636 path.lineTo(4.38597536f, 11.8849154f);
637 path.lineTo(33.3853493f, 14.1896257f);
638 path.close();
639
640 canvas->drawPath(path, paint);
641
642 path.reset();
643 path.moveTo(73.3853455f, 4.18963623f);
644 path.lineTo(69.995636f, 39.1360626f);
645 path.lineTo(42.83145142f, 21.056778f);
646 path.lineTo(42.97689819f, 19.6749573f);
647 path.lineTo(57.4423828f, 21.1975555f);
648 path.lineTo(42.94268799f, 20.0451965f);
649 path.lineTo(44.38595581f, 1.88491821f);
650 path.close();
651
652 canvas->drawPath(path, paint);
653 }
654