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