• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkPaint.h"
14 #include "include/core/SkPoint.h"
15 #include "include/core/SkRect.h"
16 #include "include/core/SkShader.h"
17 #include "include/core/SkSize.h"
18 #include "include/core/SkString.h"
19 #include "include/core/SkTileMode.h"
20 #include "include/core/SkTypes.h"
21 #include "include/effects/SkGradientShader.h"
22 
make_bitmap(SkBitmap * bitmap)23 static void make_bitmap(SkBitmap* bitmap) {
24     bitmap->allocN32Pixels(64, 64);
25 
26     SkCanvas canvas(*bitmap);
27 
28     canvas.drawColor(SK_ColorRED);
29     SkPaint paint;
30     paint.setAntiAlias(true);
31     const SkPoint pts[] = { { 0, 0 }, { 64, 64 } };
32     const SkColor colors[] = { SK_ColorWHITE, SK_ColorBLUE };
33     paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp));
34     canvas.drawCircle(32, 32, 32, paint);
35 }
36 
37 class DrawBitmapRect2 : public skiagm::GM {
38     bool fUseIRect;
39 public:
DrawBitmapRect2(bool useIRect)40     DrawBitmapRect2(bool useIRect) : fUseIRect(useIRect) {
41     }
42 
43 protected:
onShortName()44     SkString onShortName() override {
45         SkString str;
46         str.printf("bitmaprect_%s", fUseIRect ? "i" : "s");
47         return str;
48     }
49 
onISize()50     SkISize onISize() override {
51         return SkISize::Make(640, 480);
52     }
53 
onDraw(SkCanvas * canvas)54     void onDraw(SkCanvas* canvas) override {
55         canvas->drawColor(0xFFCCCCCC);
56 
57         const SkIRect src[] = {
58             { 0, 0, 32, 32 },
59             { 0, 0, 80, 80 },
60             { 32, 32, 96, 96 },
61             { -32, -32, 32, 32, }
62         };
63 
64         SkPaint paint;
65         paint.setStyle(SkPaint::kStroke_Style);
66 
67         SkBitmap bitmap;
68         make_bitmap(&bitmap);
69 
70         SkRect dstR = { 0, 200, 128, 380 };
71 
72         canvas->translate(16, 40);
73         for (size_t i = 0; i < SK_ARRAY_COUNT(src); i++) {
74             SkRect srcR;
75             srcR.set(src[i]);
76 
77             canvas->drawBitmap(bitmap, 0, 0, &paint);
78             if (!fUseIRect) {
79                 canvas->drawBitmapRect(bitmap, srcR, dstR, &paint,
80                                        SkCanvas::kStrict_SrcRectConstraint);
81             } else {
82                 canvas->drawBitmapRect(bitmap, src[i], dstR, &paint);
83             }
84 
85             canvas->drawRect(dstR, paint);
86             canvas->drawRect(srcR, paint);
87 
88             canvas->translate(160, 0);
89         }
90     }
91 
92 private:
93     typedef skiagm::GM INHERITED;
94 };
95 
96 //////////////////////////////////////////////////////////////////////////////
97 
make_3x3_bitmap(SkBitmap * bitmap)98 static void make_3x3_bitmap(SkBitmap* bitmap) {
99     const int xSize = 3;
100     const int ySize = 3;
101 
102     const SkColor textureData[xSize][ySize] = {
103         { SK_ColorRED,    SK_ColorWHITE, SK_ColorBLUE },
104         { SK_ColorGREEN,  SK_ColorBLACK, SK_ColorCYAN },
105         { SK_ColorYELLOW, SK_ColorGRAY,  SK_ColorMAGENTA }
106     };
107 
108     bitmap->allocN32Pixels(xSize, ySize, true);
109     SkCanvas canvas(*bitmap);
110     SkPaint paint;
111 
112     for (int y = 0; y < ySize; y++) {
113         for (int x = 0; x < xSize; x++) {
114             paint.setColor(textureData[x][y]);
115             canvas.drawIRect(SkIRect::MakeXYWH(x, y, 1, 1), paint);
116         }
117     }
118 }
119 
120 // This GM attempts to make visible any issues drawBitmapRect may have
121 // with partial source rects. In this case the eight pixels on the border
122 // should be half the width/height of the central pixel, i.e.:
123 //                         __|____|__
124 //                           |    |
125 //                         __|____|__
126 //                           |    |
127 class DrawBitmapRect3 : public skiagm::GM {
128 public:
DrawBitmapRect3()129     DrawBitmapRect3() {
130         this->setBGColor(SK_ColorBLACK);
131     }
132 
133 protected:
onShortName()134     SkString onShortName() override {
135         SkString str;
136         str.printf("3x3bitmaprect");
137         return str;
138     }
139 
onISize()140     SkISize onISize() override {
141         return SkISize::Make(640, 480);
142     }
143 
onDraw(SkCanvas * canvas)144     void onDraw(SkCanvas* canvas) override {
145 
146         SkBitmap bitmap;
147         make_3x3_bitmap(&bitmap);
148 
149         SkRect srcR = { 0.5f, 0.5f, 2.5f, 2.5f };
150         SkRect dstR = { 100, 100, 300, 200 };
151 
152         canvas->drawBitmapRect(bitmap, srcR, dstR, nullptr, SkCanvas::kStrict_SrcRectConstraint);
153     }
154 
155 private:
156     typedef skiagm::GM INHERITED;
157 };
158 
159 //////////////////////////////////////////////////////////////////////////////
make_big_bitmap(SkBitmap * bitmap)160 static void make_big_bitmap(SkBitmap* bitmap) {
161 
162     constexpr int gXSize = 4096;
163     constexpr int gYSize = 4096;
164     constexpr int gBorderWidth = 10;
165 
166     bitmap->allocN32Pixels(gXSize, gYSize);
167     for (int y = 0; y < gYSize; ++y) {
168         for (int x = 0; x < gXSize; ++x) {
169             if (x <= gBorderWidth || x >= gXSize-gBorderWidth ||
170                 y <= gBorderWidth || y >= gYSize-gBorderWidth) {
171                 *bitmap->getAddr32(x, y) = SkPreMultiplyColor(0x88FFFFFF);
172             } else {
173                 *bitmap->getAddr32(x, y) = SkPreMultiplyColor(0x88FF0000);
174             }
175         }
176     }
177 }
178 
179 // This GM attempts to reveal any issues we may have when the GPU has to
180 // break up a large texture in order to draw it. The XOR transfer mode will
181 // create stripes in the image if there is imprecision in the destination
182 // tile placement.
183 class DrawBitmapRect4 : public skiagm::GM {
184     bool fUseIRect;
185     SkBitmap fBigBitmap;
186 
187 public:
DrawBitmapRect4(bool useIRect)188     DrawBitmapRect4(bool useIRect) : fUseIRect(useIRect) {
189         this->setBGColor(0x88444444);
190     }
191 
192 protected:
onShortName()193     SkString onShortName() override {
194         SkString str;
195         str.printf("bigbitmaprect_%s", fUseIRect ? "i" : "s");
196         return str;
197     }
198 
onISize()199     SkISize onISize() override {
200         return SkISize::Make(640, 480);
201     }
202 
onOnceBeforeDraw()203     void onOnceBeforeDraw() override {
204         make_big_bitmap(&fBigBitmap);
205     }
206 
onDraw(SkCanvas * canvas)207     void onDraw(SkCanvas* canvas) override {
208         SkPaint paint;
209         paint.setAlpha(128);
210         paint.setBlendMode(SkBlendMode::kXor);
211 
212         SkRect srcR1 = { 0.0f, 0.0f, 4096.0f, 2040.0f };
213         SkRect dstR1 = { 10.1f, 10.1f, 629.9f, 400.9f };
214 
215         SkRect srcR2 = { 4085.0f, 10.0f, 4087.0f, 12.0f };
216         SkRect dstR2 = { 10, 410, 30, 430 };
217 
218         if (!fUseIRect) {
219             canvas->drawBitmapRect(fBigBitmap, srcR1, dstR1, &paint,
220                                    SkCanvas::kStrict_SrcRectConstraint);
221             canvas->drawBitmapRect(fBigBitmap, srcR2, dstR2, &paint,
222                                    SkCanvas::kStrict_SrcRectConstraint);
223         } else {
224             canvas->drawBitmapRect(fBigBitmap, srcR1.roundOut(), dstR1, &paint);
225             canvas->drawBitmapRect(fBigBitmap, srcR2.roundOut(), dstR2, &paint);
226         }
227     }
228 
229 private:
230     typedef skiagm::GM INHERITED;
231 };
232 
233 class BitmapRectRounding : public skiagm::GM {
234     SkBitmap fBM;
235 
236 public:
BitmapRectRounding()237     BitmapRectRounding() {}
238 
239 protected:
onShortName()240     SkString onShortName() override {
241         SkString str;
242         str.printf("bitmaprect_rounding");
243         return str;
244     }
245 
onISize()246     SkISize onISize() override {
247         return SkISize::Make(640, 480);
248     }
249 
onOnceBeforeDraw()250     void onOnceBeforeDraw() override {
251         fBM.allocN32Pixels(10, 10);
252         fBM.eraseColor(SK_ColorBLUE);
253     }
254 
255     // This choice of coordinates and matrix land the bottom edge of the clip (and bitmap dst)
256     // at exactly 1/2 pixel boundary. However, drawBitmapRect may lose precision along the way.
257     // If it does, we may see a red-line at the bottom, instead of the bitmap exactly matching
258     // the clip (in which case we should see all blue).
259     // The correct image should be all blue.
onDraw(SkCanvas * canvas)260     void onDraw(SkCanvas* canvas) override {
261         SkPaint paint;
262         paint.setColor(SK_ColorRED);
263 
264         const SkRect r = SkRect::MakeXYWH(1, 1, 110, 114);
265         canvas->scale(0.9f, 0.9f);
266 
267         // the drawRect shows the same problem as clipRect(r) followed by drawcolor(red)
268         canvas->drawRect(r, paint);
269         canvas->drawBitmapRect(fBM, r, nullptr);
270     }
271 
272 private:
273     typedef skiagm::GM INHERITED;
274 };
275 DEF_GM( return new BitmapRectRounding; )
276 
277 //////////////////////////////////////////////////////////////////////////////
278 
279 DEF_GM( return new DrawBitmapRect2(false); )
280 DEF_GM( return new DrawBitmapRect2(true); )
281 DEF_GM( return new DrawBitmapRect3(); )
282 
283 #ifndef SK_BUILD_FOR_ANDROID
284 DEF_GM( return new DrawBitmapRect4(false); )
285 DEF_GM( return new DrawBitmapRect4(true); )
286 #endif
287