bleed.cpp revision b7061176c7f414616fe2e79e832b3e0abe326af6
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.h"
9#include "SkBlurMask.h"
10#include "SkBlurMaskFilter.h"
11#include "SkCanvas.h"
12
13#if SK_SUPPORT_GPU
14#include "GrContext.h"
15
16namespace skiagm {
17extern GrContext* GetGr();
18};
19#endif
20
21// Create a black&white checked texture with a 1-pixel red ring
22// around the outside edge
23static void make_red_ringed_bitmap(SkBitmap* result, int width, int height) {
24    SkASSERT(0 == width % 2 && 0 == width % 2);
25
26    result->setConfig(SkBitmap::kARGB_8888_Config, width, height);
27    result->allocPixels();
28    SkAutoLockPixels lock(*result);
29
30    SkPMColor* scanline = result->getAddr32(0, 0);
31    for (int x = 0; x < width; ++x) {
32        scanline[x] = SK_ColorRED;
33    }
34
35    for (int y = 1; y < height/2; ++y) {
36        scanline = result->getAddr32(0, y);
37        scanline[0] = SK_ColorRED;
38        for (int x = 1; x < width/2; ++x) {
39            scanline[x] = SK_ColorBLACK;
40        }
41        for (int x = width/2; x < width-1; ++x) {
42            scanline[x] = SK_ColorWHITE;
43        }
44        scanline[width-1] = SK_ColorRED;
45    }
46
47    for (int y = height/2; y < height-1; ++y) {
48        scanline = result->getAddr32(0, y);
49        scanline[0] = SK_ColorRED;
50        for (int x = 1; x < width/2; ++x) {
51            scanline[x] = SK_ColorWHITE;
52        }
53        for (int x = width/2; x < width-1; ++x) {
54            scanline[x] = SK_ColorBLACK;
55        }
56        scanline[width-1] = SK_ColorRED;
57    }
58
59    scanline = result->getAddr32(0, height-1);
60    for (int x = 0; x < width; ++x) {
61        scanline[x] = SK_ColorRED;
62    }
63    result->setIsOpaque(true);
64    result->setImmutable();
65}
66
67// This GM exercises the drawBitmapRectToRect "bleed" flag
68class BleedGM : public skiagm::GM {
69public:
70    BleedGM() {}
71
72protected:
73    virtual SkString onShortName() SK_OVERRIDE {
74        return SkString("bleed");
75    }
76
77    virtual SkISize onISize() SK_OVERRIDE {
78        return SkISize::Make(kWidth, kHeight);
79    }
80
81    virtual void onOnceBeforeDraw() SK_OVERRIDE {
82        make_red_ringed_bitmap(&fBitmapSmall, kSmallTextureSize, kSmallTextureSize);
83
84        // To exercise the GPU's tiling path we need a texture
85        // too big for the GPU to handle in one go
86        make_red_ringed_bitmap(&fBitmapBig, 2*kMaxTextureSize, 2*kMaxTextureSize);
87    }
88
89    // Draw only the center of the small bitmap
90    void drawCase1(SkCanvas* canvas, int transX, int transY,
91                   SkCanvas::DrawBitmapRectFlags flags, bool filter) {
92        SkRect src = SkRect::MakeXYWH(1, 1,
93                                      kSmallTextureSize-2,
94                                      kSmallTextureSize-2);
95        SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
96
97        SkPaint paint;
98        paint.setFilterBitmap(filter);
99
100        canvas->save();
101        canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
102        canvas->drawBitmapRectToRect(fBitmapSmall, &src, dst, &paint, flags);
103        canvas->restore();
104    }
105
106    // Draw almost all of the large bitmap
107    void drawCase2(SkCanvas* canvas, int transX, int transY,
108                   SkCanvas::DrawBitmapRectFlags flags, bool filter) {
109        SkRect src = SkRect::MakeXYWH(1, 1,
110                                      SkIntToScalar(fBitmapBig.width()-2),
111                                      SkIntToScalar(fBitmapBig.height()-2));
112        SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
113
114        SkPaint paint;
115        paint.setFilterBitmap(filter);
116
117        canvas->save();
118        canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
119        canvas->drawBitmapRectToRect(fBitmapBig, &src, dst, &paint, flags);
120        canvas->restore();
121    }
122
123    // Draw ~1/4 of the large bitmap
124    void drawCase3(SkCanvas* canvas, int transX, int transY,
125                   SkCanvas::DrawBitmapRectFlags flags, bool filter) {
126        SkRect src = SkRect::MakeXYWH(1, 1,
127                                      SkIntToScalar(fBitmapBig.width()/2-1),
128                                      SkIntToScalar(fBitmapBig.height()/2-1));
129        SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
130
131        SkPaint paint;
132        paint.setFilterBitmap(filter);
133
134        canvas->save();
135        canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
136        canvas->drawBitmapRectToRect(fBitmapBig, &src, dst, &paint, flags);
137        canvas->restore();
138    }
139
140    // Draw the center of the small bitmap with a mask filter
141    void drawCase4(SkCanvas* canvas, int transX, int transY,
142                   SkCanvas::DrawBitmapRectFlags flags, bool filter) {
143        SkRect src = SkRect::MakeXYWH(1, 1,
144                                      kSmallTextureSize-2,
145                                      kSmallTextureSize-2);
146        SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
147
148        SkPaint paint;
149        paint.setFilterBitmap(filter);
150        SkMaskFilter* mf = SkBlurMaskFilter::Create(SkBlurMaskFilter::kNormal_BlurStyle,
151                                         SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)));
152        paint.setMaskFilter(mf)->unref();
153
154        canvas->save();
155        canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
156        canvas->drawBitmapRectToRect(fBitmapSmall, &src, dst, &paint, flags);
157        canvas->restore();
158    }
159
160    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
161
162        canvas->clear(SK_ColorGRAY);
163
164        // First draw a column with no bleeding, tiling, or filtering
165        this->drawCase1(canvas, kCol0X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, false);
166        this->drawCase2(canvas, kCol0X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, false);
167        this->drawCase3(canvas, kCol0X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, false);
168        this->drawCase4(canvas, kCol0X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, false);
169
170        // Then draw a column with no bleeding or tiling but with filtering
171        this->drawCase1(canvas, kCol1X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
172        this->drawCase2(canvas, kCol1X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
173        this->drawCase3(canvas, kCol1X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
174        this->drawCase4(canvas, kCol1X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
175
176
177#if SK_SUPPORT_GPU
178        GrContext* ctx = skiagm::GetGr();
179        int oldMaxTextureSize = 0;
180        if (NULL != ctx) {
181            // shrink the max texture size so all our textures can be reasonably sized
182            oldMaxTextureSize = ctx->getMaxTextureSize();
183            ctx->setMaxTextureSizeOverride(kMaxTextureSize);
184        }
185#endif
186
187        // Then draw a column with no bleeding but with tiling and filtering
188        this->drawCase1(canvas, kCol2X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
189        this->drawCase2(canvas, kCol2X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
190        this->drawCase3(canvas, kCol2X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
191        this->drawCase4(canvas, kCol2X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, true);
192
193        // Finally draw a column with all three (bleeding, tiling, and filtering)
194        this->drawCase1(canvas, kCol3X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, true);
195        this->drawCase2(canvas, kCol3X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, true);
196        this->drawCase3(canvas, kCol3X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, true);
197        this->drawCase4(canvas, kCol3X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, true);
198
199#if SK_SUPPORT_GPU
200        if (NULL != ctx) {
201            ctx->setMaxTextureSizeOverride(oldMaxTextureSize);
202        }
203#endif
204    }
205
206private:
207    static const int kBlockSize = 90;
208    static const int kBlockSpacing = 10;
209
210    static const int kCol0X = kBlockSpacing;
211    static const int kCol1X = 2*kBlockSpacing + kBlockSize;
212    static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
213    static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
214    static const int kWidth = 5*kBlockSpacing + 4*kBlockSize;
215
216    static const int kRow0Y = kBlockSpacing;
217    static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
218    static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
219    static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
220    static const int kHeight = 5*kBlockSpacing + 4*kBlockSize;
221
222    static const int kSmallTextureSize = 4;
223    static const int kMaxTextureSize = 32;
224
225    SkBitmap fBitmapSmall;
226    SkBitmap fBitmapBig;
227
228    typedef GM INHERITED;
229};
230
231DEF_GM( return new BleedGM(); )
232