17e4186accea094276c9f3c65c64e63ffc59aa644reed/* 27e4186accea094276c9f3c65c64e63ffc59aa644reed * Copyright 2015 Google Inc. 37e4186accea094276c9f3c65c64e63ffc59aa644reed * 47e4186accea094276c9f3c65c64e63ffc59aa644reed * Use of this source code is governed by a BSD-style license that can be 57e4186accea094276c9f3c65c64e63ffc59aa644reed * found in the LICENSE file. 67e4186accea094276c9f3c65c64e63ffc59aa644reed */ 77e4186accea094276c9f3c65c64e63ffc59aa644reed 87e4186accea094276c9f3c65c64e63ffc59aa644reed#include "gm.h" 9f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkBlurImageFilter.h" 107e4186accea094276c9f3c65c64e63ffc59aa644reed#include "SkColorMatrixFilter.h" 11f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkImage.h" 12f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkImageFilter.h" 13f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkSurface.h" 1446596ae50559e89a0a2462573ac9448cf309cf56Mike Reed#include "sk_tool_utils.h" 157e4186accea094276c9f3c65c64e63ffc59aa644reed 167e4186accea094276c9f3c65c64e63ffc59aa644reed/** 177e4186accea094276c9f3c65c64e63ffc59aa644reed * Test drawing a primitive w/ an imagefilter (in this case, just matrix w/ identity) to see 187e4186accea094276c9f3c65c64e63ffc59aa644reed * that we apply the xfermode *after* the image has been created and filtered, and not during 197e4186accea094276c9f3c65c64e63ffc59aa644reed * the creation step (i.e. before it is filtered). 207e4186accea094276c9f3c65c64e63ffc59aa644reed * 216950de6c4166fabb35e6c756fc009e0cf1c47819halcanary * see https://bug.skia.org/3741 227e4186accea094276c9f3c65c64e63ffc59aa644reed */ 23374772bd61951f01bf84fe17bf53d8867681c9aereedstatic void do_draw(SkCanvas* canvas, SkBlendMode mode, sk_sp<SkImageFilter> imf) { 2449124378913f3467eb67e653b3b48f80899a3f37reed SkAutoCanvasRestore acr(canvas, true); 2549124378913f3467eb67e653b3b48f80899a3f37reed canvas->clipRect(SkRect::MakeWH(220, 220)); 26467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 2749124378913f3467eb67e653b3b48f80899a3f37reed // want to force a layer, so modes like DstIn can combine meaningfully, but the final 2849124378913f3467eb67e653b3b48f80899a3f37reed // image can still be shown against our default (opaque) background. non-opaque GMs 2949124378913f3467eb67e653b3b48f80899a3f37reed // are a lot more trouble to compare/triage. 3096fcdcc219d2a0d3579719b84b28bede76efba64halcanary canvas->saveLayer(nullptr, nullptr); 3149124378913f3467eb67e653b3b48f80899a3f37reed canvas->drawColor(SK_ColorGREEN); 3249124378913f3467eb67e653b3b48f80899a3f37reed 337e4186accea094276c9f3c65c64e63ffc59aa644reed SkPaint paint; 347e4186accea094276c9f3c65c64e63ffc59aa644reed paint.setAntiAlias(true); 35467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 367e4186accea094276c9f3c65c64e63ffc59aa644reed SkRect r0 = SkRect::MakeXYWH(10, 60, 200, 100); 377e4186accea094276c9f3c65c64e63ffc59aa644reed SkRect r1 = SkRect::MakeXYWH(60, 10, 100, 200); 38467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 397e4186accea094276c9f3c65c64e63ffc59aa644reed paint.setColor(SK_ColorRED); 407e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->drawOval(r0, paint); 417e4186accea094276c9f3c65c64e63ffc59aa644reed 4249124378913f3467eb67e653b3b48f80899a3f37reed paint.setColor(0x660000FF); 43ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips paint.setImageFilter(std::move(imf)); 44374772bd61951f01bf84fe17bf53d8867681c9aereed paint.setBlendMode(mode); 457e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->drawOval(r1, paint); 462a24338c777462e04a2b26295f9c034155ee8f3ehalcanary} 477e4186accea094276c9f3c65c64e63ffc59aa644reed 482a24338c777462e04a2b26295f9c034155ee8f3ehalcanaryDEF_SIMPLE_GM(imagefilters_xfermodes, canvas, 480, 480) { 4949124378913f3467eb67e653b3b48f80899a3f37reed canvas->translate(10, 10); 5049124378913f3467eb67e653b3b48f80899a3f37reed 517e4186accea094276c9f3c65c64e63ffc59aa644reed // just need an imagefilter to trigger the code-path (which creates a tmp layer) 52ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips sk_sp<SkImageFilter> imf(SkImageFilter::MakeMatrixFilter(SkMatrix::I(), 53ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips kNone_SkFilterQuality, 54ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips nullptr)); 557e4186accea094276c9f3c65c64e63ffc59aa644reed 56374772bd61951f01bf84fe17bf53d8867681c9aereed const SkBlendMode modes[] = { 57374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kSrcATop, SkBlendMode::kDstIn 587e4186accea094276c9f3c65c64e63ffc59aa644reed }; 59467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 607e4186accea094276c9f3c65c64e63ffc59aa644reed for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) { 617e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->save(); 622a24338c777462e04a2b26295f9c034155ee8f3ehalcanary do_draw(canvas, modes[i], nullptr); 6349124378913f3467eb67e653b3b48f80899a3f37reed canvas->translate(240, 0); 642a24338c777462e04a2b26295f9c034155ee8f3ehalcanary do_draw(canvas, modes[i], imf); 657e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->restore(); 66467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 6749124378913f3467eb67e653b3b48f80899a3f37reed canvas->translate(0, 240); 687e4186accea094276c9f3c65c64e63ffc59aa644reed } 692a24338c777462e04a2b26295f9c034155ee8f3ehalcanary} 70f65fb658147da97b5010276fe99f15952e6333e3reed 719ce9d6772df650ceb0511f275e1a83dffa78ff72reedstatic sk_sp<SkImage> make_image(SkCanvas* canvas) { 725f500920e719b215d5e0e36a6679995ed3c9b4adBrian Osman const SkImageInfo info = SkImageInfo::MakeS32(100, 100, kPremul_SkAlphaType); 7346596ae50559e89a0a2462573ac9448cf309cf56Mike Reed auto surface(sk_tool_utils::makeSurface(canvas, info)); 74f65fb658147da97b5010276fe99f15952e6333e3reed surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 25, 50, 50), SkPaint()); 759ce9d6772df650ceb0511f275e1a83dffa78ff72reed return surface->makeImageSnapshot(); 76f65fb658147da97b5010276fe99f15952e6333e3reed} 77f65fb658147da97b5010276fe99f15952e6333e3reed 78f65fb658147da97b5010276fe99f15952e6333e3reed// Compare blurs when we're tightly clipped (fast) and not as tightly (slower) 79f65fb658147da97b5010276fe99f15952e6333e3reed// 80f65fb658147da97b5010276fe99f15952e6333e3reed// Expect the two to draw the same (modulo the extra border of pixels when the clip is larger) 81f65fb658147da97b5010276fe99f15952e6333e3reed// 82f65fb658147da97b5010276fe99f15952e6333e3reedDEF_SIMPLE_GM(fast_slow_blurimagefilter, canvas, 620, 260) { 839ce9d6772df650ceb0511f275e1a83dffa78ff72reed sk_sp<SkImage> image(make_image(canvas)); 84f65fb658147da97b5010276fe99f15952e6333e3reed const SkRect r = SkRect::MakeIWH(image->width(), image->height()); 85f65fb658147da97b5010276fe99f15952e6333e3reed 86f65fb658147da97b5010276fe99f15952e6333e3reed canvas->translate(10, 10); 87f65fb658147da97b5010276fe99f15952e6333e3reed for (SkScalar sigma = 8; sigma <= 128; sigma *= 2) { 88f65fb658147da97b5010276fe99f15952e6333e3reed SkPaint paint; 896e7025ab13dfc4f0037233e67b4b8e18d6dfd1e1robertphillips paint.setImageFilter(SkBlurImageFilter::Make(sigma, sigma, nullptr)); 90f65fb658147da97b5010276fe99f15952e6333e3reed 91f65fb658147da97b5010276fe99f15952e6333e3reed canvas->save(); 92f65fb658147da97b5010276fe99f15952e6333e3reed // we outset the clip by 1, to fall out of the fast-case in drawImage 93f65fb658147da97b5010276fe99f15952e6333e3reed // i.e. the clip is larger than the image 94f65fb658147da97b5010276fe99f15952e6333e3reed for (SkScalar outset = 0; outset <= 1; ++outset) { 95f65fb658147da97b5010276fe99f15952e6333e3reed canvas->save(); 96f65fb658147da97b5010276fe99f15952e6333e3reed canvas->clipRect(r.makeOutset(outset, outset)); 97f65fb658147da97b5010276fe99f15952e6333e3reed canvas->drawImage(image, 0, 0, &paint); 98f65fb658147da97b5010276fe99f15952e6333e3reed canvas->restore(); 99f65fb658147da97b5010276fe99f15952e6333e3reed canvas->translate(0, r.height() + 20); 100f65fb658147da97b5010276fe99f15952e6333e3reed } 101f65fb658147da97b5010276fe99f15952e6333e3reed canvas->restore(); 102f65fb658147da97b5010276fe99f15952e6333e3reed canvas->translate(r.width() + 20, 0); 103f65fb658147da97b5010276fe99f15952e6333e3reed } 104f65fb658147da97b5010276fe99f15952e6333e3reed} 105bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 106bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed/////////////////////////////////////////////////////////////////////////////////////////////////// 107bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "Resources.h" 108bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkBlurImageFilter.h" 109bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkMatrixConvolutionImageFilter.h" 110bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkMorphologyImageFilter.h" 111bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkColorMatrixFilter.h" 112bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkColorFilterImageFilter.h" 113bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkRRect.h" 114bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 115ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillipsstatic void draw_set(SkCanvas* canvas, sk_sp<SkImageFilter> filters[], int count) { 116bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const SkRect r = SkRect::MakeXYWH(30, 30, 200, 200); 117bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const SkScalar offset = 250; 118bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkScalar dx = 0, dy = 0; 119bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 120bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed for (int i = 0; i < count; ++i) { 121bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->save(); 122bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkRRect rr = SkRRect::MakeRectXY(r.makeOffset(dx, dy), 20, 20); 123669983856d99b9312be3166b7dd1f8483a90c315reed canvas->clipRRect(rr, true); 12453f77bd4fdd76525b66b7f26d1c5c550858120dfFlorin Malita canvas->saveLayer({ &rr.getBounds(), nullptr, filters[i].get(), nullptr, nullptr, 0 }); 125bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->drawColor(0x40FFFFFF); 126bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->restore(); 127bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->restore(); 128bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 129bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed if (0 == dx) { 130bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed dx = offset; 131bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } else { 132bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed dx = 0; 133bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed dy = offset; 134bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } 135bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } 136bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed} 137bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 138bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areedDEF_SIMPLE_GM(savelayer_with_backdrop, canvas, 830, 550) { 139bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkColorMatrix cm; 140bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed cm.setSaturation(10); 141fc11b0afe0ca922a42767d4a656ed640008da1bbrobertphillips sk_sp<SkColorFilter> cf(SkColorFilter::MakeMatrixFilterRowMajor255(cm.fMat)); 142bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const SkScalar kernel[] = { 4, 0, 4, 0, -15, 0, 4, 0, 4 }; 143ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips sk_sp<SkImageFilter> filters[] = { 144ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkBlurImageFilter::Make(10, 10, nullptr), 145ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkDilateImageFilter::Make(8, 8, nullptr), 146ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkMatrixConvolutionImageFilter::Make( 147ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips { 3, 3 }, kernel, 1, 0, { 0, 0 }, 148bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, 149ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips true, nullptr), 150ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkColorFilterImageFilter::Make(std::move(cf), nullptr), 151bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed }; 152bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 153bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const struct { 154bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkScalar fSx, fSy, fTx, fTy; 155bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } xforms[] = { 156bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 1, 1, 0, 0 }, 157bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 0.5f, 0.5f, 530, 0 }, 158bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 0.25f, 0.25f, 530, 275 }, 159bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 0.125f, 0.125f, 530, 420 }, 160bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed }; 161bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 162bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkPaint paint; 163bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed paint.setFilterQuality(kMedium_SkFilterQuality); 164c465d13e6fca5e171bde45d35b2dd43117f4702eHal Canary sk_sp<SkImage> image(GetResourceAsImage("images/mandrill_512.png")); 165bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 166bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->translate(20, 20); 167bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed for (const auto& xform : xforms) { 168bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->save(); 169bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->translate(xform.fTx, xform.fTy); 170bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->scale(xform.fSx, xform.fSy); 171bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->drawImage(image, 0, 0, &paint); 172bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed draw_set(canvas, filters, SK_ARRAY_COUNT(filters)); 173bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->restore(); 174bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } 175bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed} 176