1/* 2 * Copyright 2014 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 "SkBitmapSource.h" 10#include "SkBlurImageFilter.h" 11#include "SkDropShadowImageFilter.h" 12#include "SkOffsetImageFilter.h" 13#include "SkPictureImageFilter.h" 14#include "SkPictureRecorder.h" 15#include "SkRandom.h" 16 17namespace skiagm { 18 19// Each method of this type must draw its geometry inside 'r' using 'p' 20typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p); 21 22static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 23 canvas->drawRect(r, p); 24} 25 26static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 27 canvas->drawOval(r, p); 28} 29 30static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 31 SkScalar xRad = r.width() / 4.0f; 32 SkScalar yRad = r.height() / 4.0f; 33 34 SkRRect rr; 35 rr.setRectXY(r, xRad, yRad); 36 canvas->drawRRect(rr, p); 37} 38 39static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 40 SkScalar xRad = r.width() / 4.0f; 41 SkScalar yRad = r.height() / 4.0f; 42 43 SkRRect outer; 44 outer.setRectXY(r, xRad, yRad); 45 SkRRect inner = outer; 46 inner.inset(xRad, yRad); 47 canvas->drawDRRect(outer, inner, p); 48} 49 50static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 51 SkPath path; 52 53 path.moveTo(r.fLeft, r.fTop); 54 path.lineTo(r.fLeft, r.fBottom); 55 path.lineTo(r.fRight, r.fBottom); 56 path.close(); 57 58 canvas->drawPath(path, p); 59} 60 61static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 62 SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } }; 63 SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } }; 64 65 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p); 66 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p); 67} 68 69static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { 70 SkBitmap bm; 71 72 bm.allocN32Pixels(64, 64); 73 SkCanvas temp(bm); 74 temp.clear(SK_ColorMAGENTA); 75 76 canvas->drawBitmapRect(bm, r, &p); 77} 78 79static const drawMth gDrawMthds[] = { 80 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap 81}; 82 83static void add_paint(SkImageFilter* filter, SkTArray<SkPaint>* paints) { 84 SkPaint& p = paints->push_back(); 85 p.setImageFilter(filter); 86 SkASSERT(p.canComputeFastBounds()); 87} 88 89// Create a selection of imagefilter-based paints to test 90static void create_paints(SkImageFilter* source, SkTArray<SkPaint>* paints) { 91 { 92 SkMatrix scale; 93 scale.setScale(2.0f, 2.0f); 94 95 SkAutoTUnref<SkImageFilter> scaleMIF( 96 SkImageFilter::CreateMatrixFilter(scale, kLow_SkFilterQuality, source)); 97 98 add_paint(scaleMIF, paints); 99 } 100 101 { 102 SkMatrix rot; 103 rot.setRotate(-33.3f); 104 105 SkAutoTUnref<SkImageFilter> rotMIF( 106 SkImageFilter::CreateMatrixFilter(rot, kLow_SkFilterQuality, source)); 107 108 add_paint(rotMIF, paints); 109 } 110 111 { 112 static const SkDropShadowImageFilter::ShadowMode kBoth = 113 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode; 114 115 SkAutoTUnref<SkDropShadowImageFilter> dsif( 116 SkDropShadowImageFilter::Create(10.0f, 10.0f, 117 3.0f, 3.0f, 118 SK_ColorRED, kBoth, 119 source, NULL)); 120 121 add_paint(dsif, paints); 122 } 123 124 { 125 SkAutoTUnref<SkDropShadowImageFilter> dsif( 126 SkDropShadowImageFilter::Create(27.0f, 27.0f, 127 3.0f, 3.0f, 128 SK_ColorRED, 129 SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, 130 source, NULL)); 131 132 add_paint(dsif, paints); 133 } 134 135 { 136 SkAutoTUnref<SkBlurImageFilter> bif(SkBlurImageFilter::Create(3, 3, source)); 137 138 add_paint(bif, paints); 139 } 140 141 { 142 SkAutoTUnref<SkOffsetImageFilter> oif(SkOffsetImageFilter::Create(15, 15, source)); 143 144 add_paint(oif, paints); 145 } 146} 147 148// This GM visualizes the fast bounds for various combinations of geometry 149// and image filter 150class ImageFilterFastBoundGM : public GM { 151public: 152 ImageFilterFastBoundGM() { 153 this->setBGColor(0xFFCCCCCC); 154 } 155 156protected: 157 static const int kTileWidth = 100; 158 static const int kTileHeight = 100; 159 static const int kNumVertTiles = 6; 160 static const int kNumXtraCols = 2; 161 162 SkString onShortName() override{ return SkString("filterfastbounds"); } 163 164 SkISize onISize() override{ 165 return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth, 166 kNumVertTiles * kTileHeight); 167 } 168 169 static void draw_geom_with_paint(drawMth draw, const SkIPoint& off, 170 SkCanvas* canvas, const SkPaint& p) { 171 SkPaint redStroked; 172 redStroked.setColor(SK_ColorRED); 173 redStroked.setStyle(SkPaint::kStroke_Style); 174 175 SkPaint blueStroked; 176 blueStroked.setColor(SK_ColorBLUE); 177 blueStroked.setStyle(SkPaint::kStroke_Style); 178 179 const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30); 180 SkRect storage; 181 182 canvas->save(); 183 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY)); 184 canvas->scale(1.5f, 1.5f); 185 186 const SkRect& fastBound = p.computeFastBounds(r, &storage); 187 188 canvas->save(); 189 canvas->clipRect(fastBound); 190 (*draw)(canvas, r, p); 191 canvas->restore(); 192 193 canvas->drawRect(r, redStroked); 194 canvas->drawRect(fastBound, blueStroked); 195 canvas->restore(); 196 } 197 198 static void draw_savelayer_with_paint(const SkIPoint& off, 199 SkCanvas* canvas, 200 const SkPaint& p) { 201 SkPaint redStroked; 202 redStroked.setColor(SK_ColorRED); 203 redStroked.setStyle(SkPaint::kStroke_Style); 204 205 SkPaint blueStroked; 206 blueStroked.setColor(SK_ColorBLUE); 207 blueStroked.setStyle(SkPaint::kStroke_Style); 208 209 const SkRect bounds = SkRect::MakeWH(10, 10); 210 SkRect storage; 211 212 canvas->save(); 213 canvas->translate(30, 30); 214 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY)); 215 canvas->scale(1.5f, 1.5f); 216 217 const SkRect& fastBound = p.computeFastBounds(bounds, &storage); 218 219 canvas->saveLayer(&fastBound, &p); 220 canvas->restore(); 221 222 canvas->drawRect(bounds, redStroked); 223 canvas->drawRect(fastBound, blueStroked); 224 canvas->restore(); 225 } 226 227 void onDraw(SkCanvas* canvas) override{ 228 229 SkPaint blackFill; 230 231 //----------- 232 // Normal paints (no source) 233 SkTArray<SkPaint> paints; 234 create_paints(NULL, &paints); 235 236 //----------- 237 // Paints with a PictureImageFilter as a source 238 SkAutoTUnref<SkPicture> pic; 239 240 { 241 SkPictureRecorder rec; 242 243 SkCanvas* c = rec.beginRecording(10, 10); 244 c->drawRect(SkRect::MakeWH(10, 10), blackFill); 245 pic.reset(rec.endRecording()); 246 } 247 248 SkAutoTUnref<SkPictureImageFilter> pif(SkPictureImageFilter::Create(pic)); 249 250 SkTArray<SkPaint> pifPaints; 251 create_paints(pif, &pifPaints); 252 253 //----------- 254 // Paints with a BitmapSource as a source 255 SkBitmap bm; 256 257 { 258 SkPaint p; 259 bm.allocN32Pixels(10, 10); 260 SkCanvas temp(bm); 261 temp.clear(SK_ColorYELLOW); 262 p.setColor(SK_ColorBLUE); 263 temp.drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p); 264 p.setColor(SK_ColorGREEN); 265 temp.drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p); 266 } 267 268 SkAutoTUnref<SkBitmapSource> bms(SkBitmapSource::Create(bm)); 269 270 SkTArray<SkPaint> bmsPaints; 271 create_paints(bms, &bmsPaints); 272 273 //----------- 274 SkASSERT(paints.count() == kNumVertTiles); 275 SkASSERT(paints.count() == pifPaints.count()); 276 SkASSERT(paints.count() == bmsPaints.count()); 277 278 // horizontal separators 279 for (int i = 1; i < paints.count(); ++i) { 280 canvas->drawLine(0, 281 i*SkIntToScalar(kTileHeight), 282 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth), 283 i*SkIntToScalar(kTileHeight), 284 blackFill); 285 } 286 // vertical separators 287 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) { 288 canvas->drawLine(SkIntToScalar(i * kTileWidth), 289 0, 290 SkIntToScalar(i * kTileWidth), 291 SkIntToScalar(paints.count() * kTileWidth), 292 blackFill); 293 } 294 295 // A column of saveLayers with PictureImageFilters 296 for (int i = 0; i < pifPaints.count(); ++i) { 297 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight), 298 canvas, pifPaints[i]); 299 } 300 301 // A column of saveLayers with BitmapSources 302 for (int i = 0; i < pifPaints.count(); ++i) { 303 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight), 304 canvas, bmsPaints[i]); 305 } 306 307 // Multiple columns with different geometry 308 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) { 309 for (int j = 0; j < paints.count(); ++j) { 310 draw_geom_with_paint(*gDrawMthds[i], 311 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight), 312 canvas, paints[j]); 313 } 314 } 315 316 } 317 318private: 319 typedef GM INHERITED; 320}; 321 322////////////////////////////////////////////////////////////////////////////// 323 324DEF_GM(return SkNEW(ImageFilterFastBoundGM);) 325 326} 327