1 /*
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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkImage.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkRRect.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkSize.h"
16 #include "include/core/SkString.h"
17 #include "include/core/SkSurface.h"
18 #include "include/core/SkTypes.h"
19
20 namespace skiagm {
21
22 // Draw various width thin rects at 1/8 horizontal pixel increments
23 class ThinRectsGM : public GM {
24 public:
ThinRectsGM(bool round)25 ThinRectsGM(bool round) : fRound(round) {
26 this->setBGColor(0xFF000000);
27 }
28
29 protected:
30 SkString onShortName() override {
31 return SkString(fRound ? "thinroundrects" : "thinrects");
32 }
33
34 SkISize onISize() override {
35 return SkISize::Make(240, 320);
36 }
37
38 void onDraw(SkCanvas* canvas) override {
39
40 SkPaint white;
41 white.setColor(SK_ColorWHITE);
42 white.setAntiAlias(true);
43
44 SkPaint green;
45 green.setColor(SK_ColorGREEN);
46 green.setAntiAlias(true);
47
48 for (int i = 0; i < 8; ++i) {
49 canvas->save();
50 canvas->translate(i*0.125f, i*40.0f);
51 this->drawVertRects(canvas, white);
52
53 canvas->translate(40.0f, 0.0f);
54 this->drawVertRects(canvas, green);
55 canvas->restore();
56
57 canvas->save();
58 canvas->translate(80.0f, i*40.0f + i*0.125f);
59 this->drawHorizRects(canvas, white);
60
61 canvas->translate(40.0f, 0.0f);
62 this->drawHorizRects(canvas, green);
63 canvas->restore();
64
65 canvas->save();
66 canvas->translate(160.0f + i*0.125f,
67 i*40.0f + i*0.125f);
68 this->drawSquares(canvas, white);
69
70 canvas->translate(40.0f, 0.0f);
71 this->drawSquares(canvas, green);
72 canvas->restore();
73 }
74 }
75
76 private:
drawVertRects(SkCanvas* canvas, const SkPaint& p)77 void drawVertRects(SkCanvas* canvas, const SkPaint& p) {
78 constexpr SkRect vertRects[] = {
79 { 1, 1, 5.0f, 21 }, // 4 pix wide
80 { 8, 1, 10.0f, 21 }, // 2 pix wide
81 { 13, 1, 14.0f, 21 }, // 1 pix wide
82 { 17, 1, 17.5f, 21 }, // 1/2 pix wide
83 { 21, 1, 21.25f, 21 }, // 1/4 pix wide
84 { 25, 1, 25.125f, 21 }, // 1/8 pix wide
85 { 29, 1, 29.0f, 21 } // 0 pix wide
86 };
87
88 static constexpr SkVector radii[4] = {{1/32.f, 2/32.f}, {3/32.f, 1/32.f}, {2/32.f, 3/32.f},
89 {1/32.f, 3/32.f}};
90 SkRRect rrect;
91 for (size_t j = 0; j < SK_ARRAY_COUNT(vertRects); ++j) {
92 if (fRound) {
93 rrect.setRectRadii(vertRects[j], radii);
94 canvas->drawRRect(rrect, p);
95 } else {
96 canvas->drawRect(vertRects[j], p);
97 }
98 }
99 }
100
drawHorizRects(SkCanvas* canvas, const SkPaint& p)101 void drawHorizRects(SkCanvas* canvas, const SkPaint& p) {
102 constexpr SkRect horizRects[] = {
103 { 1, 1, 21, 5.0f }, // 4 pix high
104 { 1, 8, 21, 10.0f }, // 2 pix high
105 { 1, 13, 21, 14.0f }, // 1 pix high
106 { 1, 17, 21, 17.5f }, // 1/2 pix high
107 { 1, 21, 21, 21.25f }, // 1/4 pix high
108 { 1, 25, 21, 25.125f }, // 1/8 pix high
109 { 1, 29, 21, 29.0f } // 0 pix high
110 };
111
112 SkRRect rrect;
113 for (size_t j = 0; j < SK_ARRAY_COUNT(horizRects); ++j) {
114 if (fRound) {
115 rrect.setNinePatch(horizRects[j], 1/32.f, 2/32.f, 3/32.f, 4/32.f);
116 canvas->drawRRect(rrect, p);
117 } else {
118 canvas->drawRect(horizRects[j], p);
119 }
120 }
121 }
122
drawSquares(SkCanvas* canvas, const SkPaint& p)123 void drawSquares(SkCanvas* canvas, const SkPaint& p) {
124 constexpr SkRect squares[] = {
125 { 1, 1, 5.0f, 5.0f }, // 4 pix
126 { 8, 8, 10.0f, 10.0f }, // 2 pix
127 { 13, 13, 14.0f, 14.0f }, // 1 pix
128 { 17, 17, 17.5f, 17.5f }, // 1/2 pix
129 { 21, 21, 21.25f, 21.25f }, // 1/4 pix
130 { 25, 25, 25.125f, 25.125f }, // 1/8 pix
131 { 29, 29, 29.0f, 29.0f } // 0 pix
132 };
133
134 SkRRect rrect;
135 for (size_t j = 0; j < SK_ARRAY_COUNT(squares); ++j) {
136 if (fRound) {
137 rrect.setRectXY(squares[j], 1/32.f, 2/32.f);
138 canvas->drawRRect(rrect, p);
139 } else {
140 canvas->drawRect(squares[j], p);
141 }
142 }
143 }
144
145 const bool fRound;
146
147 using INHERITED = GM;
148 };
149
150 //////////////////////////////////////////////////////////////////////////////
151
152 DEF_GM( return new ThinRectsGM(false); )
153 DEF_GM( return new ThinRectsGM(true); )
154
155 } // namespace skiagm
156
DEF_SIMPLE_GM_CAN_FAIL(clipped_thinrect, canvas, errorMsg, 256, 256)157 DEF_SIMPLE_GM_CAN_FAIL(clipped_thinrect, canvas, errorMsg, 256, 256) {
158 auto zoomed = canvas->makeSurface(canvas->imageInfo().makeWH(10, 10));
159 if (!zoomed) {
160 errorMsg->printf("makeSurface not supported");
161 return skiagm::DrawResult::kSkip;
162 }
163 auto zoomedCanvas = zoomed->getCanvas();
164
165 SkPaint p;
166 p.setColor(SK_ColorRED);
167 p.setAntiAlias(true);
168 p.setStyle(SkPaint::kFill_Style);
169 zoomedCanvas->save();
170 zoomedCanvas->clipRect(SkRect::MakeXYWH(0, 5, 256, 10), true /*doAntialias*/);
171 zoomedCanvas->drawRect(SkRect::MakeXYWH(0, 0, 100, 5.5), p);
172 zoomedCanvas->restore();
173
174 // Zoom-in. Should see one line of red representing zoomed in 1/2px coverage and *not*
175 // two lines of varying coverage from hairline rendering.
176 auto img = zoomed->makeImageSnapshot();
177 canvas->drawImageRect(img, SkRect::MakeXYWH(0, 10, 200, 200), SkSamplingOptions());
178 return skiagm::DrawResult::kOk;
179 }
180