Unify ShadowUtils interface
[platform/upstream/libSkiaSharp.git] / gm / path_stroke_with_zero_length.cpp
1 /*
2  * Copyright 2015 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 "SkPath.h"
9 #include "SkStream.h"
10 #include "gm.h"
11
12
13 // Test how short paths are stroked with various caps
14 class StrokeZeroGM : public skiagm::GM {
15     SkPath fPaths[8];
16     SkPath fClipL, fClipR, fClipS;
17
18 protected:
19     void onOnceBeforeDraw() override {
20         fClipL.moveTo(0, 0);
21         fClipL.lineTo(3, 0);
22         fClipL.lineTo(2.5f, 1);
23         fClipL.lineTo(3.5f, 2.5f);
24         fClipL.lineTo(2.5f, 4);
25         fClipL.lineTo(3, 5);
26         fClipL.lineTo(0, 5);
27         fClipL.close();
28
29         fClipR.moveTo(34, 0);
30         fClipR.lineTo(34, 5);
31         fClipR.lineTo(31, 5);
32         fClipR.lineTo(30.5, 4);
33         fClipR.lineTo(31.5, 2.5);
34         fClipR.lineTo(30.5, 1);
35         fClipR.lineTo(31, 0);
36         fClipR.close();
37
38         fClipS.addRect(SkRect::MakeIWH(4, 5));
39
40         fPaths[0].moveTo(30, 0);  // single line segment
41         fPaths[0].rLineTo(30, 0);
42
43         fPaths[1].moveTo(90, 0);  // single line segment with close (does not draw caps)
44         fPaths[1].rLineTo(30, 0);
45         fPaths[1].close();
46
47         fPaths[2].moveTo(150, 0);  // zero-length line
48         fPaths[2].rLineTo(0, 0);
49
50         fPaths[3].moveTo(180, 0);  // zero-length line with close (expected not to draw)
51         fPaths[3].rLineTo(0, 0);
52         fPaths[3].close();
53
54         fPaths[4].moveTo(210, 0);  // close only, no line
55         fPaths[4].close();
56
57         fPaths[5].moveTo(30, 90);  // all combos below should draw two caps
58         fPaths[5].rLineTo(0, 0);
59         fPaths[5].moveTo(60, 90);
60         fPaths[5].rLineTo(0, 0);
61
62         fPaths[6].moveTo(90, 90);
63         fPaths[6].close();
64         fPaths[6].moveTo(120, 90);
65         fPaths[6].close();
66
67         fPaths[7].moveTo(150, 90);
68         fPaths[7].rLineTo(0, 0);
69         fPaths[7].moveTo(180, 90);
70         fPaths[7].close();
71     }
72
73
74     SkString onShortName() override {
75         return SkString("path_stroke_with_zero_length");
76     }
77
78     SkISize onISize() override {
79         return SkISize::Make(1120, 840);
80     }
81
82     void onDraw(SkCanvas* canvas) override {
83         SkPaint bkgrnd;
84         bkgrnd.setColor(SK_ColorWHITE);
85         canvas->drawRect(SkRect::MakeIWH(onISize().fWidth, onISize().fHeight), bkgrnd);
86
87          auto drawPaths = [&](SkPaint& paint, int indexMask) {
88             canvas->translate(0, 30.0f);
89             int index = 0;
90             for (const SkPath& path : fPaths) {
91                 if (indexMask & (1 << index)) {
92                     canvas->drawPath(path, paint);
93                 }
94                 if (this->getMode() == skiagm::GM::kSample_Mode && paint.getStrokeWidth() < 2) {
95                     drawFat(canvas, path, paint, index);
96                 }
97                 ++index;
98             }
99         };
100
101         if (false) { // debugging variant that draws a single element
102             SkScalar width = 0;
103             bool antialias = true;
104
105             SkPaint butt;
106             butt.setAntiAlias(antialias);
107             butt.setStyle(SkPaint::kStroke_Style);
108             butt.setStrokeWidth(width);
109
110             SkPaint round(butt);
111             round.setStrokeCap(SkPaint::kRound_Cap);
112             drawPaths(round, 1 << 7);
113             return;
114         }
115
116         SkScalar widths[] = { 0, .999f, 1, 1.001f, 20 };
117         bool aliases[] = { false, true };
118         for (bool antialias : aliases) {
119             canvas->save();
120             for (SkScalar width : widths) {
121                 canvas->save();
122                 SkPaint butt;
123                 butt.setAntiAlias(antialias);
124                 butt.setStyle(SkPaint::kStroke_Style);
125                 butt.setStrokeWidth(width);
126                 drawPaths(butt, -1);
127
128                 SkPaint round(butt);
129                 round.setStrokeCap(SkPaint::kRound_Cap);
130                 drawPaths(round, -1);
131
132                 SkPaint square(butt);
133                 square.setStrokeCap(SkPaint::kSquare_Cap);
134                 drawPaths(square, -1);
135                 canvas->restore();
136                 canvas->translate(220, 0);
137             }
138             canvas->restore();
139             canvas->translate(0, 210);
140         }
141     }
142
143 private:
144     void drawFat(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, int index) {
145         const SkScalar scale = 10;
146         SkRect bounds = path.getBounds();
147         SkBitmap offscreen;
148         offscreen.allocN32Pixels(SkScalarRoundToInt(bounds.width() + 4),
149                 SkScalarRoundToInt(bounds.height() + 4));
150         offscreen.eraseColor(SK_ColorWHITE);
151         SkScalar pathX = bounds.fLeft - 2;
152         SkScalar pathY = bounds.fTop - 2;
153         SkMatrix cMatrix = canvas->getTotalMatrix();
154         if (!canvas->readPixels(offscreen, SkScalarRoundToInt(pathX + cMatrix.getTranslateX()),
155                 SkScalarRoundToInt(pathY + cMatrix.getTranslateY()))) {
156             return;
157         }
158
159         canvas->save();
160         SkMatrix clipM;
161         clipM.reset();
162         clipM.preScale(scale, scale);
163         clipM.postTranslate(bounds.fLeft - 17, bounds.fTop - 24.5f + 420);
164         SkPath clip;
165         if (index < 2) {
166             fClipL.transform(clipM, &clip);
167         } else {
168             fClipS.transform(clipM, &clip);
169         }
170         canvas->clipPath(clip, true);
171         canvas->scale(scale, scale);
172         canvas->drawBitmap(offscreen, (bounds.fLeft - 17) / scale,
173                     (bounds.fTop - 20 + 420) / scale);
174         canvas->restore();
175
176         if (bounds.width() > 20) {
177             canvas->save();
178             clipM.reset();
179             clipM.preScale(scale, scale);
180             clipM.postTranslate(bounds.fLeft - 17 - 275, bounds.fTop - 24.5f + 420);
181             SkPath clip;
182             fClipR.transform(clipM, &clip);
183             canvas->clipPath(clip, true);
184             canvas->scale(10.f, 10.f);
185             canvas->drawBitmap(offscreen, (bounds.fLeft - 17 - 275
186                     + (index >= 5 ? 5 : 0)) / scale, (bounds.fTop - 20 + 420) / scale);
187             canvas->restore();
188         }
189     }
190
191 };
192
193 ///////////////////////////////////////////////////////////////////////////////
194
195 DEF_GM( return new StrokeZeroGM(); )