bleed.cpp revision d6ca4ac1ee2a0096b42b02e9408181c9e0387939
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. 19static 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 86class BleedGM : public skiagm::GM { 87public: 88 BleedGM() {} 89 90protected: 91 virtual SkString onShortName() SK_OVERRIDE { 92 return SkString("bleed"); 93 } 94 95 virtual SkISize onISize() SK_OVERRIDE { 96 return SkISize::Make(kWidth, 780); 97 } 98 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 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 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 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 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 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 254private: 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 281DEF_GM( return new BleedGM(); ) 282