• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #endif
16 
17 // Create a black&white checked texture with 2 1-pixel rings
18 // around the outside edge. The inner ring is red and the outer ring is blue.
make_ringed_bitmap(SkBitmap * result,int width,int height)19 static void make_ringed_bitmap(SkBitmap* result, int width, int height) {
20     SkASSERT(0 == width % 2 && 0 == height % 2);
21 
22     static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
23     static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
24     static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
25     static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
26 
27     result->setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
28                       kOpaque_SkAlphaType);
29     result->allocPixels();
30     SkAutoLockPixels lock(*result);
31 
32     SkPMColor* scanline = result->getAddr32(0, 0);
33     for (int x = 0; x < width; ++x) {
34         scanline[x] = kBlue;
35     }
36     scanline = result->getAddr32(0, 1);
37     scanline[0] = kBlue;
38     for (int x = 1; x < width - 1; ++x) {
39         scanline[x] = kRed;
40     }
41     scanline[width-1] = kBlue;
42 
43     for (int y = 2; y < height/2; ++y) {
44         scanline = result->getAddr32(0, y);
45         scanline[0] = kBlue;
46         scanline[1] = kRed;
47         for (int x = 2; x < width/2; ++x) {
48             scanline[x] = kBlack;
49         }
50         for (int x = width/2; x < width-2; ++x) {
51             scanline[x] = kWhite;
52         }
53         scanline[width-2] = kRed;
54         scanline[width-1] = kBlue;
55     }
56 
57     for (int y = height/2; y < height-2; ++y) {
58         scanline = result->getAddr32(0, y);
59         scanline[0] = kBlue;
60         scanline[1] = kRed;
61         for (int x = 2; x < width/2; ++x) {
62             scanline[x] = kWhite;
63         }
64         for (int x = width/2; x < width-2; ++x) {
65             scanline[x] = kBlack;
66         }
67         scanline[width-2] = kRed;
68         scanline[width-1] = kBlue;
69     }
70 
71     scanline = result->getAddr32(0, height-2);
72     scanline[0] = kBlue;
73     for (int x = 1; x < width - 1; ++x) {
74         scanline[x] = kRed;
75     }
76     scanline[width-1] = kBlue;
77 
78     scanline = result->getAddr32(0, height-1);
79     for (int x = 0; x < width; ++x) {
80         scanline[x] = kBlue;
81     }
82     result->setImmutable();
83 }
84 
85 // This GM exercises the drawBitmapRectToRect "bleed" flag
86 class BleedGM : public skiagm::GM {
87 public:
BleedGM()88     BleedGM() {}
89 
90 protected:
onShortName()91     virtual SkString onShortName() SK_OVERRIDE {
92         return SkString("bleed");
93     }
94 
onISize()95     virtual SkISize onISize() SK_OVERRIDE {
96         return SkISize::Make(kWidth, 780);
97     }
98 
onOnceBeforeDraw()99     virtual void onOnceBeforeDraw() SK_OVERRIDE {
100         make_ringed_bitmap(&fBitmapSmall, kSmallTextureSize, kSmallTextureSize);
101 
102         // To exercise the GPU's tiling path we need a texture
103         // too big for the GPU to handle in one go
104         make_ringed_bitmap(&fBitmapBig, 2*kMaxTextureSize, 2*kMaxTextureSize);
105     }
106 
107     // Draw only the center of the small bitmap
drawCase1(SkCanvas * canvas,int transX,int transY,SkCanvas::DrawBitmapRectFlags flags,SkPaint::FilterLevel filter)108     void drawCase1(SkCanvas* canvas, int transX, int transY,
109                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
110         SkRect src = SkRect::MakeXYWH(2, 2,
111                                       SkIntToScalar(kSmallTextureSize-4),
112                                       SkIntToScalar(kSmallTextureSize-4));
113         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
114 
115         SkPaint paint;
116         paint.setFilterLevel(filter);
117 
118         canvas->save();
119         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
120         canvas->drawBitmapRectToRect(fBitmapSmall, &src, dst, &paint, flags);
121         canvas->restore();
122     }
123 
124     // Draw almost all of the large bitmap
drawCase2(SkCanvas * canvas,int transX,int transY,SkCanvas::DrawBitmapRectFlags flags,SkPaint::FilterLevel filter)125     void drawCase2(SkCanvas* canvas, int transX, int transY,
126                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
127         SkRect src = SkRect::MakeXYWH(2, 2,
128                                       SkIntToScalar(fBitmapBig.width()-4),
129                                       SkIntToScalar(fBitmapBig.height()-4));
130         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
131 
132         SkPaint paint;
133         paint.setFilterLevel(filter);
134 
135         canvas->save();
136         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
137         canvas->drawBitmapRectToRect(fBitmapBig, &src, dst, &paint, flags);
138         canvas->restore();
139     }
140 
141     // Draw ~1/4 of the large bitmap
drawCase3(SkCanvas * canvas,int transX,int transY,SkCanvas::DrawBitmapRectFlags flags,SkPaint::FilterLevel filter)142     void drawCase3(SkCanvas* canvas, int transX, int transY,
143                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
144         SkRect src = SkRect::MakeXYWH(2, 2,
145                                       SkIntToScalar(fBitmapBig.width()/2-2),
146                                       SkIntToScalar(fBitmapBig.height()/2-2));
147         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
148 
149         SkPaint paint;
150         paint.setFilterLevel(filter);
151 
152         canvas->save();
153         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
154         canvas->drawBitmapRectToRect(fBitmapBig, &src, dst, &paint, flags);
155         canvas->restore();
156     }
157 
158     // Draw the center of the small bitmap with a mask filter
drawCase4(SkCanvas * canvas,int transX,int transY,SkCanvas::DrawBitmapRectFlags flags,SkPaint::FilterLevel filter)159     void drawCase4(SkCanvas* canvas, int transX, int transY,
160                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
161         SkRect src = SkRect::MakeXYWH(2, 2,
162                                       SkIntToScalar(kSmallTextureSize-4),
163                                       SkIntToScalar(kSmallTextureSize-4));
164         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
165 
166         SkPaint paint;
167         paint.setFilterLevel(filter);
168         SkMaskFilter* mf = SkBlurMaskFilter::Create(SkBlurMaskFilter::kNormal_BlurStyle,
169                                          SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)));
170         paint.setMaskFilter(mf)->unref();
171 
172         canvas->save();
173         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
174         canvas->drawBitmapRectToRect(fBitmapSmall, &src, dst, &paint, flags);
175         canvas->restore();
176     }
177 
onDraw(SkCanvas * canvas)178     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
179 
180         canvas->clear(SK_ColorGRAY);
181 
182         for (int m = 0; m < 2; ++m) {
183             canvas->save();
184             if (m) {
185                 static const SkScalar kBottom = SkIntToScalar(kRow3Y + kBlockSize + kBlockSpacing);
186                 canvas->translate(0, kBottom);
187                 SkMatrix rotate;
188                 rotate.setRotate(15.f, 0, kBottom + kBlockSpacing);
189                 canvas->concat(rotate);
190                 canvas->scale(0.71f, 1.22f);
191             }
192 
193             // First draw a column with no bleeding, tiling, or filtering
194             this->drawCase1(canvas, kCol0X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
195             this->drawCase2(canvas, kCol0X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
196             this->drawCase3(canvas, kCol0X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
197             this->drawCase4(canvas, kCol0X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
198 
199             // Then draw a column with no bleeding or tiling but with low filtering
200             this->drawCase1(canvas, kCol1X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
201             this->drawCase2(canvas, kCol1X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
202             this->drawCase3(canvas, kCol1X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
203             this->drawCase4(canvas, kCol1X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
204 
205             // Then draw a column with no bleeding or tiling but with high filtering
206             this->drawCase1(canvas, kCol2X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
207             this->drawCase2(canvas, kCol2X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
208             this->drawCase3(canvas, kCol2X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
209             this->drawCase4(canvas, kCol2X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
210 
211 #if SK_SUPPORT_GPU
212             GrContext* ctx = canvas->getGrContext();
213             int oldMaxTextureSize = 0;
214             if (NULL != ctx) {
215                 // shrink the max texture size so all our textures can be reasonably sized
216                 oldMaxTextureSize = ctx->getMaxTextureSize();
217                 ctx->setMaxTextureSizeOverride(kMaxTextureSize);
218             }
219 #endif
220 
221             // Then draw a column with no bleeding but with tiling and low filtering
222             this->drawCase1(canvas, kCol3X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
223             this->drawCase2(canvas, kCol3X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
224             this->drawCase3(canvas, kCol3X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
225             this->drawCase4(canvas, kCol3X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
226 
227             // Then draw a column with no bleeding but with tiling and high filtering
228             this->drawCase1(canvas, kCol4X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
229             this->drawCase2(canvas, kCol4X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
230             this->drawCase3(canvas, kCol4X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
231             this->drawCase4(canvas, kCol4X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
232 
233             // Then draw a column with bleeding, tiling, and low filtering
234             this->drawCase1(canvas, kCol5X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
235             this->drawCase2(canvas, kCol5X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
236             this->drawCase3(canvas, kCol5X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
237             this->drawCase4(canvas, kCol5X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
238 
239             // Finally draw a column with bleeding, tiling, and high filtering
240             this->drawCase1(canvas, kCol6X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
241             this->drawCase2(canvas, kCol6X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
242             this->drawCase3(canvas, kCol6X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
243             this->drawCase4(canvas, kCol6X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
244 
245 #if SK_SUPPORT_GPU
246             if (NULL != ctx) {
247                 ctx->setMaxTextureSizeOverride(oldMaxTextureSize);
248             }
249 #endif
250             canvas->restore();
251         }
252     }
253 
254 private:
255     static const int kBlockSize = 70;
256     static const int kBlockSpacing = 5;
257 
258     static const int kCol0X = kBlockSpacing;
259     static const int kCol1X = 2*kBlockSpacing + kBlockSize;
260     static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
261     static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
262     static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
263     static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
264     static const int kCol6X = 7*kBlockSpacing + 6*kBlockSize;
265     static const int kWidth = 8*kBlockSpacing + 7*kBlockSize;
266 
267     static const int kRow0Y = kBlockSpacing;
268     static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
269     static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
270     static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
271 
272     static const int kSmallTextureSize = 6;
273     static const int kMaxTextureSize = 32;
274 
275     SkBitmap fBitmapSmall;
276     SkBitmap fBitmapBig;
277 
278     typedef GM INHERITED;
279 };
280 
281 DEF_GM( return new BleedGM(); )
282