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