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