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