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