1 /* 2 * Copyright 2015 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 "SkColorMatrixFilter.h" 11 #include "SkImage.h" 12 #include "SkImageFilter.h" 13 #include "SkSurface.h" 14 15 /** 16 * Test drawing a primitive w/ an imagefilter (in this case, just matrix w/ identity) to see 17 * that we apply the xfermode *after* the image has been created and filtered, and not during 18 * the creation step (i.e. before it is filtered). 19 * 20 * see https://bug.skia.org/3741 21 */ 22 static void do_draw(SkCanvas* canvas, SkXfermode::Mode mode, SkImageFilter* imf) { 23 SkAutoCanvasRestore acr(canvas, true); 24 canvas->clipRect(SkRect::MakeWH(220, 220)); 25 26 // want to force a layer, so modes like DstIn can combine meaningfully, but the final 27 // image can still be shown against our default (opaque) background. non-opaque GMs 28 // are a lot more trouble to compare/triage. 29 canvas->saveLayer(nullptr, nullptr); 30 canvas->drawColor(SK_ColorGREEN); 31 32 SkPaint paint; 33 paint.setAntiAlias(true); 34 35 SkRect r0 = SkRect::MakeXYWH(10, 60, 200, 100); 36 SkRect r1 = SkRect::MakeXYWH(60, 10, 100, 200); 37 38 paint.setColor(SK_ColorRED); 39 canvas->drawOval(r0, paint); 40 41 paint.setColor(0x660000FF); 42 paint.setImageFilter(imf); 43 paint.setXfermodeMode(mode); 44 canvas->drawOval(r1, paint); 45 } 46 47 DEF_SIMPLE_GM(imagefilters_xfermodes, canvas, 480, 480) { 48 canvas->translate(10, 10); 49 50 // just need an imagefilter to trigger the code-path (which creates a tmp layer) 51 SkAutoTUnref<SkImageFilter> imf(SkImageFilter::CreateMatrixFilter(SkMatrix::I(), 52 kNone_SkFilterQuality)); 53 54 const SkXfermode::Mode modes[] = { 55 SkXfermode::kSrcATop_Mode, SkXfermode::kDstIn_Mode 56 }; 57 58 for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) { 59 canvas->save(); 60 do_draw(canvas, modes[i], nullptr); 61 canvas->translate(240, 0); 62 do_draw(canvas, modes[i], imf); 63 canvas->restore(); 64 65 canvas->translate(0, 240); 66 } 67 } 68 69 static SkImage* make_image(SkCanvas* canvas) { 70 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 71 SkAutoTUnref<SkSurface> surface(canvas->newSurface(info)); 72 if (!surface) { 73 surface.reset(SkSurface::NewRaster(info)); 74 } 75 surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 25, 50, 50), SkPaint()); 76 return surface->newImageSnapshot(); 77 } 78 79 // Compare blurs when we're tightly clipped (fast) and not as tightly (slower) 80 // 81 // Expect the two to draw the same (modulo the extra border of pixels when the clip is larger) 82 // 83 DEF_SIMPLE_GM(fast_slow_blurimagefilter, canvas, 620, 260) { 84 SkAutoTUnref<SkImage> image(make_image(canvas)); 85 const SkRect r = SkRect::MakeIWH(image->width(), image->height()); 86 87 canvas->translate(10, 10); 88 for (SkScalar sigma = 8; sigma <= 128; sigma *= 2) { 89 SkPaint paint; 90 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(sigma, sigma)); 91 paint.setImageFilter(blur); 92 93 canvas->save(); 94 // we outset the clip by 1, to fall out of the fast-case in drawImage 95 // i.e. the clip is larger than the image 96 for (SkScalar outset = 0; outset <= 1; ++outset) { 97 canvas->save(); 98 canvas->clipRect(r.makeOutset(outset, outset)); 99 canvas->drawImage(image, 0, 0, &paint); 100 canvas->restore(); 101 canvas->translate(0, r.height() + 20); 102 } 103 canvas->restore(); 104 canvas->translate(r.width() + 20, 0); 105 } 106 } 107 108 /////////////////////////////////////////////////////////////////////////////////////////////////// 109 #include "Resources.h" 110 #include "SkBlurImageFilter.h" 111 #include "SkMatrixConvolutionImageFilter.h" 112 #include "SkMorphologyImageFilter.h" 113 #include "SkColorMatrixFilter.h" 114 #include "SkColorFilterImageFilter.h" 115 #include "SkRRect.h" 116 117 static void draw_set(SkCanvas* canvas, SkImageFilter* filters[], int count) { 118 const SkRect r = SkRect::MakeXYWH(30, 30, 200, 200); 119 const SkScalar offset = 250; 120 SkScalar dx = 0, dy = 0; 121 122 for (int i = 0; i < count; ++i) { 123 canvas->save(); 124 SkRRect rr = SkRRect::MakeRectXY(r.makeOffset(dx, dy), 20, 20); 125 canvas->clipRRect(rr, SkRegion::kIntersect_Op, true); 126 canvas->saveLayer({ &rr.getBounds(), nullptr, filters[i], 0 }); 127 canvas->drawColor(0x40FFFFFF); 128 canvas->restore(); 129 canvas->restore(); 130 131 if (0 == dx) { 132 dx = offset; 133 } else { 134 dx = 0; 135 dy = offset; 136 } 137 } 138 } 139 140 DEF_SIMPLE_GM(savelayer_with_backdrop, canvas, 830, 550) { 141 SkColorMatrix cm; 142 cm.setSaturation(10); 143 SkAutoTUnref<SkColorFilter> cf(SkColorMatrixFilter::Create(cm)); 144 const SkScalar kernel[] = { 4, 0, 4, 0, -15, 0, 4, 0, 4 }; 145 SkImageFilter* filters[] = { 146 SkBlurImageFilter::Create(10, 10), 147 SkDilateImageFilter::Create(8, 8), 148 SkMatrixConvolutionImageFilter::Create({ 3, 3 }, kernel, 1, 0, { 0, 0 }, 149 SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, 150 true), 151 SkColorFilterImageFilter::Create(cf), 152 }; 153 154 const struct { 155 SkScalar fSx, fSy, fTx, fTy; 156 } xforms[] = { 157 { 1, 1, 0, 0 }, 158 { 0.5f, 0.5f, 530, 0 }, 159 { 0.25f, 0.25f, 530, 275 }, 160 { 0.125f, 0.125f, 530, 420 }, 161 }; 162 163 SkPaint paint; 164 paint.setFilterQuality(kMedium_SkFilterQuality); 165 SkAutoTUnref<SkImage> image(GetResourceAsImage("mandrill_512.png")); 166 167 canvas->translate(20, 20); 168 for (const auto& xform : xforms) { 169 canvas->save(); 170 canvas->translate(xform.fTx, xform.fTy); 171 canvas->scale(xform.fSx, xform.fSy); 172 canvas->drawImage(image, 0, 0, &paint); 173 draw_set(canvas, filters, SK_ARRAY_COUNT(filters)); 174 canvas->restore(); 175 } 176 177 for (auto& filter : filters) { 178 filter->unref(); 179 } 180 } 181