16e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed/* 26e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed * Copyright 2018 Google Inc. 36e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed * 46e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed * Use of this source code is governed by a BSD-style license that can be 56e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed * found in the LICENSE file. 66e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed */ 76e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 86e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed#include "gm.h" 96e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed#include "sk_tool_utils.h" 10547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed#include "SkBlendModePriv.h" 1120dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed#include "SkBlurMaskFilter.h" 126e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed#include "SkCanvas.h" 136e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed#include "SkImage.h" 146e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed#include "SkShaderMaskFilter.h" 156e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 166e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reedstatic void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y, 17547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed const SkImage* mask, sk_sp<SkMaskFilter> outer, SkBlendMode mode) { 186e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(), 196e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed SkIntToScalar(image->height() / mask->height())); 206e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed SkPaint paint; 2120dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed auto mf = SkShaderMaskFilter::Make(mask->makeShader(&matrix)); 2220dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed if (outer) { 2320dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed mf = SkMaskFilter::MakeCompose(outer, mf); 2420dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed } 2520dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed paint.setMaskFilter(mf); 2628eaed254dcd73b42c15b73528f349cccd7797e5Mike Reed paint.setAntiAlias(true); 27547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed paint.setBlendMode(mode); 286e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed canvas->drawImage(image, x, y, &paint); 296e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed} 306e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 316e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed#include "SkGradientShader.h" 326e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reedstatic sk_sp<SkShader> make_shader(const SkRect& r) { 336e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed const SkPoint pts[] = { 346e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed { r.fLeft, r.fTop }, { r.fRight, r.fBottom }, 356e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed }; 366e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed const SkColor colors[] = { 0, SK_ColorWHITE }; 376e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode); 386e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed} 396e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 406e87eee2a0494e11610e5535427a9f86ccffa4bbMike ReedDEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) { 416e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed SkRect r = { 0, 0, 100, 150 }; 426e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed auto shader = make_shader(r); 436e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed auto mf = SkShaderMaskFilter::Make(shader); 446e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 456e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed canvas->translate(20, 20); 466e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed canvas->scale(2, 2); 476e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 486e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed SkPaint paint; 496e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed paint.setMaskFilter(mf); 506e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed paint.setColor(SK_ColorRED); 5128eaed254dcd73b42c15b73528f349cccd7797e5Mike Reed paint.setAntiAlias(true); 526e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed canvas->drawOval(r, paint); 536e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed} 546e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 556e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed#include "Resources.h" 56547c8590a553efef7bcfb4c04e52072eb1271beaMike ReedDEF_SIMPLE_GM(shadermaskfilter_image, canvas, 560, 370) { 576e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed canvas->scale(1.25f, 1.25f); 586e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 596e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed auto image = GetResourceAsImage("images/mandrill_128.png"); 606e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed auto mask = GetResourceAsImage("images/color_wheel.png"); 6120dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed auto blurmf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 5); 62547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed auto gradmf = SkShaderMaskFilter::Make(make_shader(SkRect::MakeIWH(mask->width(), 63547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed mask->height()))); 646e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed 65547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed const sk_sp<SkMaskFilter> array[] = { nullptr , blurmf, gradmf }; 66547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed for (SkBlendMode mode : {SkBlendMode::kSrcOver, SkBlendMode::kSrcIn}) { 67547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->save(); 68547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed for (sk_sp<SkMaskFilter> mf : array) { 69547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed draw_masked_image(canvas, image.get(), 10, 10, mask.get(), mf, mode); 70547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->translate(image->width() + 20.f, 0); 71547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed } 72547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->restore(); 73547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->translate(0, image->height() + 20.f); 74547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed } 7520dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed} 7620dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed 7720dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed/////////////////////////////////////////////////////////////////////////////////////////////////// 7820dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed 7920dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed#include "SkPictureRecorder.h" 8020dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed#include "SkPath.h" 811bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed 8220dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reedstatic sk_sp<SkMaskFilter> make_path_mf(const SkPath& path, unsigned alpha) { 8320dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed SkPaint paint; 8420dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed paint.setAntiAlias(true); 8520dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed paint.setAlpha(alpha); 8620dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed 8720dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed SkPictureRecorder recorder; 8820dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed recorder.beginRecording(1000, 1000)->drawPath(path, paint); 8920dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed auto shader = SkShader::MakePictureShader(recorder.finishRecordingAsPicture(), 9020dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 9120dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed nullptr, nullptr); 9220dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed return SkShaderMaskFilter::Make(shader); 9320dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed} 9420dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed 951bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reedtypedef void (*MakePathsProc)(const SkRect&, SkPath*, SkPath*); 961bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed 971bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reedconst char* gCoverageName[] = { 981bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed "union", "sect", "diff", "rev-diff", "xor" 991bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed}; 1001bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed 101547c8590a553efef7bcfb4c04e52072eb1271beaMike ReedDEF_SIMPLE_GM(combinemaskfilter, canvas, 560, 510) { 10220dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed const SkRect r = { 0, 0, 100, 100 }; 10320dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed 1041bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed SkPaint paint; 1051bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed paint.setColor(SK_ColorRED); 1061bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed 1071bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed SkPaint labelP; 1081bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed labelP.setAntiAlias(true); 1091bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed labelP.setTextSize(20); 1101bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed labelP.setTextAlign(SkPaint::kCenter_Align); 1111bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed 11220dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed const SkRect r2 = r.makeOutset(1.5f, 1.5f); 113547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed SkPaint strokePaint; 114547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed strokePaint.setStyle(SkPaint::kStroke_Style); 11520dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed 1161bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed auto proc0 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) { 1171bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathA->moveTo(r.fLeft, r.fBottom); 1181bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathA->lineTo(r.fRight, r.fTop); 1191bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathA->lineTo(r.fRight, r.fBottom); 1201bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathB->moveTo(r.fLeft, r.fTop); 1211bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathB->lineTo(r.fRight, r.fBottom); 1221bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathB->lineTo(r.fLeft, r.fBottom); 1231bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed }; 1241bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed auto proc1 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) { 1251bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathA->addCircle(r.width()*0.25f, r.height()*0.25f, r.width()*0.5f); 1261bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed pathB->addCircle(r.width()*0.75f, r.height()*0.75f, r.width()*0.5f); 1271bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed }; 1281bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed MakePathsProc procs[] = { proc0, proc1 }; 1291bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed 1301bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed sk_sp<SkMaskFilter> mfA[2], mfB[2]; 1311bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed for (int i = 0; i < 2; ++i) { 1321bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed SkPath a, b; 1331bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed procs[i](r, &a, &b); 1341bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed mfA[i] = make_path_mf(a, 1 * 0xFF / 3); 1351bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed mfB[i] = make_path_mf(b, 2 * 0xFF / 3); 1361bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed } 13720dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed 1381bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed canvas->translate(10, 10 + 20); 13920dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed canvas->save(); 1401bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed for (int i = 0; i < 5; ++i) { 1411bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed canvas->drawText(gCoverageName[i], strlen(gCoverageName[i]), r.width()*0.5f, -10, labelP); 1421bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed 143547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed SkCoverageMode cmode = static_cast<SkCoverageMode>(i); 1441bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed canvas->save(); 145547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed // esp. on gpu side, its valuable to exercise modes that do and do-not convolve coverage 146547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed // with alpha. SrcOver and SrcIn have these properties, but also happen to "look" the same 147547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed // for this test. 148547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed const SkBlendMode bmodes[] = { SkBlendMode::kSrcOver, SkBlendMode::kSrcIn }; 149547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed SkASSERT( SkBlendMode_SupportsCoverageAsAlpha(bmodes[0])); // test as-alpha 150547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed SkASSERT(!SkBlendMode_SupportsCoverageAsAlpha(bmodes[1])); // test not-as-alpha 151547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed for (auto bmode : bmodes) { 152547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed paint.setBlendMode(bmode); 153547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed for (int j = 0; j < 2; ++j) { 154547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed paint.setMaskFilter(SkMaskFilter::MakeCombine(mfA[j], mfB[j], cmode)); 155547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->drawRect(r2, strokePaint); 156547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->drawRect(r, paint); 157547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->translate(0, r.height() + 10); 158547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed } 159547c8590a553efef7bcfb4c04e52072eb1271beaMike Reed canvas->translate(0, 40); 16020dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed } 1611bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed canvas->restore(); 1621bd556a1776c6c0b2a7b940516bc53f329516dc7Mike Reed canvas->translate(r.width() + 10, 0); 16320dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed } 16420dc672821d743a0c32f07dc6ec994f9deb478d7Mike Reed canvas->restore(); 1656e87eee2a0494e11610e5535427a9f86ccffa4bbMike Reed} 166be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed 167be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed#include "SkSurface.h" 1682179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed#include "SkBlurImageFilter.h" 1692179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed#include "SkBlurMaskFilter.h" 170be33bab92b83c116cf3f62cff982a2ee7892717eMike Reedstatic sk_sp<SkImage> make_circle_image(SkCanvas* canvas, SkScalar radius, int margin) { 171be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed const int n = SkScalarCeilToInt(radius) * 2 + margin * 2; 172be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed auto surf = sk_tool_utils::makeSurface(canvas, SkImageInfo::MakeN32Premul(n, n)); 173be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed SkPaint paint; 174be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed paint.setAntiAlias(true); 175be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed surf->getCanvas()->drawCircle(n * 0.5f, n * 0.5f, radius, paint); 176be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed return surf->makeImageSnapshot(); 177be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed} 178be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed 1792179b78ef221b6df73f1b8a085e5ca86e85a525bMike ReedDEF_SIMPLE_GM(savelayer_maskfilter, canvas, 450, 675) { 1802179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed auto layerImage = GetResourceAsImage("images/mandrill_128.png"); 1812179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed auto maskImage = make_circle_image(canvas, 50, 1); 182be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed SkRect r = SkRect::MakeWH(102, 102); 183be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed 1842179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed SkPaint overlayPaint; 1852179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed overlayPaint.setStyle(SkPaint::kStroke_Style); 186be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed 187be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed // test that the maskfilter sees these changes to the ctm 188be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed canvas->translate(10, 10); 189be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed canvas->scale(2, 2); 190be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed 1912179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed sk_sp<SkMaskFilter> mfs[] = { 1922179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed SkShaderMaskFilter::Make(maskImage->makeShader()), 1932179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 3.5f), 1942179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed nullptr, 1952179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed }; 1962179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed mfs[2] = SkMaskFilter::MakeCompose(mfs[1], mfs[0]); 197be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed 1982179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed // Important that we test with and without an imagefilter attached to the layer, 1992179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed // as cpu and gpu backends treat these differently (w/ or w/o a SkSpecialImage) 2002179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed const sk_sp<SkImageFilter> imfs[] = {nullptr, SkBlurImageFilter::Make(3.5f, 3.5f, nullptr)}; 2012179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed 202b9fc24e465767db8bd9dbddfd67c905392346e66Mike Reed for (auto& mf : mfs) { 2032179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed SkPaint layerPaint; 2042179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed layerPaint.setMaskFilter(mf); 2052179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->save(); 206b9fc24e465767db8bd9dbddfd67c905392346e66Mike Reed for (auto& imf : imfs) { 2072179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed layerPaint.setImageFilter(imf); 2082179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed 2092179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->saveLayer(&r, &layerPaint); 2102179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->drawImage(layerImage, 0, 0, nullptr); 2112179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->restore(); 2122179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed 2132179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed // now draw the (approximage) expected bounds of the mask 2142179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->drawRect(r.makeOutset(1, 1), overlayPaint); 2152179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed 2162179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->translate(r.width() + 10, 0); 2172179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed } 2182179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->restore(); 2192179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed canvas->translate(0, r.height() + 10); 2202179b78ef221b6df73f1b8a085e5ca86e85a525bMike Reed } 221be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed} 222be33bab92b83c116cf3f62cff982a2ee7892717eMike Reed 223