shadermaskfilter.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * Copyright 2018 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. #include "gm/gm.h"
  8. #include "include/core/SkBlendMode.h"
  9. #include "include/core/SkBlurTypes.h"
  10. #include "include/core/SkCanvas.h"
  11. #include "include/core/SkColor.h"
  12. #include "include/core/SkCoverageMode.h"
  13. #include "include/core/SkFont.h"
  14. #include "include/core/SkImage.h"
  15. #include "include/core/SkImageFilter.h"
  16. #include "include/core/SkImageInfo.h"
  17. #include "include/core/SkMaskFilter.h"
  18. #include "include/core/SkMatrix.h"
  19. #include "include/core/SkPaint.h"
  20. #include "include/core/SkPath.h"
  21. #include "include/core/SkPicture.h"
  22. #include "include/core/SkPictureRecorder.h"
  23. #include "include/core/SkPoint.h"
  24. #include "include/core/SkRect.h"
  25. #include "include/core/SkRefCnt.h"
  26. #include "include/core/SkScalar.h"
  27. #include "include/core/SkShader.h"
  28. #include "include/core/SkString.h"
  29. #include "include/core/SkSurface.h"
  30. #include "include/core/SkTileMode.h"
  31. #include "include/core/SkTypes.h"
  32. #include "include/effects/SkBlurImageFilter.h"
  33. #include "include/effects/SkGradientShader.h"
  34. #include "include/effects/SkShaderMaskFilter.h"
  35. #include "include/utils/SkTextUtils.h"
  36. #include "src/core/SkBlendModePriv.h"
  37. #include "tools/Resources.h"
  38. #include "tools/ToolUtils.h"
  39. #include <initializer_list>
  40. static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y,
  41. const SkImage* mask, sk_sp<SkMaskFilter> outer, SkBlendMode mode) {
  42. SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(),
  43. SkIntToScalar(image->height() / mask->height()));
  44. // The geometry of the drawImage is also translated by (x,y) so make the mask filter's
  45. // coordinate system align with the rendered rectangle.
  46. matrix.postTranslate(x, y);
  47. SkPaint paint;
  48. auto mf = SkShaderMaskFilter::Make(mask->makeShader(&matrix));
  49. if (outer) {
  50. mf = SkMaskFilter::MakeCompose(outer->makeWithMatrix(matrix), mf);
  51. }
  52. paint.setMaskFilter(mf);
  53. paint.setAntiAlias(true);
  54. paint.setBlendMode(mode);
  55. canvas->drawImage(image, x, y, &paint);
  56. }
  57. static sk_sp<SkShader> make_shader(const SkRect& r) {
  58. const SkPoint pts[] = {
  59. { r.fLeft, r.fTop }, { r.fRight, r.fBottom },
  60. };
  61. const SkColor colors[] = { 0, SK_ColorWHITE };
  62. return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kRepeat);
  63. }
  64. DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) {
  65. SkRect r = { 0, 0, 100, 150 };
  66. auto shader = make_shader(r);
  67. auto mf = SkShaderMaskFilter::Make(shader);
  68. canvas->translate(20, 20);
  69. canvas->scale(2, 2);
  70. SkPaint paint;
  71. paint.setMaskFilter(mf);
  72. paint.setColor(SK_ColorRED);
  73. paint.setAntiAlias(true);
  74. canvas->drawOval(r, paint);
  75. }
  76. DEF_SIMPLE_GM_CAN_FAIL(shadermaskfilter_image, canvas, errorMsg, 560, 370) {
  77. canvas->scale(1.25f, 1.25f);
  78. auto image = GetResourceAsImage("images/mandrill_128.png");
  79. auto mask = GetResourceAsImage("images/color_wheel.png");
  80. if (!image || !mask) {
  81. *errorMsg = "Could not load images. Did you forget to set the resourcePath?";
  82. return skiagm::DrawResult::kFail;
  83. }
  84. auto blurmf = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5);
  85. auto gradmf = SkShaderMaskFilter::Make(make_shader(SkRect::MakeIWH(mask->width(),
  86. mask->height())));
  87. const sk_sp<SkMaskFilter> array[] = { nullptr , blurmf, gradmf };
  88. for (SkBlendMode mode : {SkBlendMode::kSrcOver, SkBlendMode::kSrcIn}) {
  89. canvas->save();
  90. for (sk_sp<SkMaskFilter> mf : array) {
  91. draw_masked_image(canvas, image.get(), 10, 10, mask.get(), mf, mode);
  92. canvas->translate(image->width() + 20.f, 0);
  93. }
  94. canvas->restore();
  95. canvas->translate(0, image->height() + 20.f);
  96. }
  97. return skiagm::DrawResult::kOk;
  98. }
  99. ///////////////////////////////////////////////////////////////////////////////////////////////////
  100. static sk_sp<SkMaskFilter> make_path_mf(const SkPath& path, unsigned alpha) {
  101. SkPaint paint;
  102. paint.setAntiAlias(true);
  103. paint.setAlpha(alpha);
  104. SkPictureRecorder recorder;
  105. recorder.beginRecording(1000, 1000)->drawPath(path, paint);
  106. auto shader = recorder.finishRecordingAsPicture()->makeShader(SkTileMode::kClamp,
  107. SkTileMode::kClamp);
  108. return SkShaderMaskFilter::Make(shader);
  109. }
  110. typedef void (*MakePathsProc)(const SkRect&, SkPath*, SkPath*);
  111. const char* gCoverageName[] = {
  112. "union", "sect", "diff", "rev-diff", "xor"
  113. };
  114. DEF_SIMPLE_GM(combinemaskfilter, canvas, 560, 510) {
  115. const SkRect r = { 0, 0, 100, 100 };
  116. SkPaint paint;
  117. paint.setColor(SK_ColorRED);
  118. SkFont font;
  119. font.setSize(20);
  120. const SkRect r2 = r.makeOutset(1.5f, 1.5f);
  121. SkPaint strokePaint;
  122. strokePaint.setStyle(SkPaint::kStroke_Style);
  123. auto proc0 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
  124. pathA->moveTo(r.fLeft, r.fBottom);
  125. pathA->lineTo(r.fRight, r.fTop);
  126. pathA->lineTo(r.fRight, r.fBottom);
  127. pathB->moveTo(r.fLeft, r.fTop);
  128. pathB->lineTo(r.fRight, r.fBottom);
  129. pathB->lineTo(r.fLeft, r.fBottom);
  130. };
  131. auto proc1 = [](const SkRect& r, SkPath* pathA, SkPath* pathB) {
  132. pathA->addCircle(r.width()*0.25f, r.height()*0.25f, r.width()*0.5f);
  133. pathB->addCircle(r.width()*0.75f, r.height()*0.75f, r.width()*0.5f);
  134. };
  135. MakePathsProc procs[] = { proc0, proc1 };
  136. sk_sp<SkMaskFilter> mfA[2], mfB[2];
  137. for (int i = 0; i < 2; ++i) {
  138. SkPath a, b;
  139. procs[i](r, &a, &b);
  140. mfA[i] = make_path_mf(a, 1 * 0xFF / 3);
  141. mfB[i] = make_path_mf(b, 2 * 0xFF / 3);
  142. }
  143. canvas->translate(10, 10 + 20);
  144. canvas->save();
  145. for (int i = 0; i < 5; ++i) {
  146. SkTextUtils::DrawString(canvas, gCoverageName[i], r.width()*0.5f, -10, font, SkPaint(),
  147. SkTextUtils::kCenter_Align);
  148. SkCoverageMode cmode = static_cast<SkCoverageMode>(i);
  149. canvas->save();
  150. // esp. on gpu side, its valuable to exercise modes that do and do-not convolve coverage
  151. // with alpha. SrcOver and SrcIn have these properties, but also happen to "look" the same
  152. // for this test.
  153. const SkBlendMode bmodes[] = { SkBlendMode::kSrcOver, SkBlendMode::kSrcIn };
  154. SkASSERT( SkBlendMode_SupportsCoverageAsAlpha(bmodes[0])); // test as-alpha
  155. SkASSERT(!SkBlendMode_SupportsCoverageAsAlpha(bmodes[1])); // test not-as-alpha
  156. for (auto bmode : bmodes) {
  157. paint.setBlendMode(bmode);
  158. for (int j = 0; j < 2; ++j) {
  159. paint.setMaskFilter(SkMaskFilter::MakeCombine(mfA[j], mfB[j], cmode));
  160. canvas->drawRect(r2, strokePaint);
  161. canvas->drawRect(r, paint);
  162. canvas->translate(0, r.height() + 10);
  163. }
  164. canvas->translate(0, 40);
  165. }
  166. canvas->restore();
  167. canvas->translate(r.width() + 10, 0);
  168. }
  169. canvas->restore();
  170. }
  171. static sk_sp<SkImage> make_circle_image(SkCanvas* canvas, SkScalar radius, int margin) {
  172. const int n = SkScalarCeilToInt(radius) * 2 + margin * 2;
  173. auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(n, n));
  174. SkPaint paint;
  175. paint.setAntiAlias(true);
  176. surf->getCanvas()->drawCircle(n * 0.5f, n * 0.5f, radius, paint);
  177. return surf->makeImageSnapshot();
  178. }
  179. DEF_SIMPLE_GM(savelayer_maskfilter, canvas, 450, 675) {
  180. auto layerImage = GetResourceAsImage("images/mandrill_128.png");
  181. auto maskImage = make_circle_image(canvas, 50, 1);
  182. SkRect r = SkRect::MakeWH(102, 102);
  183. SkPaint overlayPaint;
  184. overlayPaint.setStyle(SkPaint::kStroke_Style);
  185. // test that the maskfilter sees these changes to the ctm
  186. canvas->translate(10, 10);
  187. canvas->scale(2, 2);
  188. sk_sp<SkMaskFilter> mfs[] = {
  189. SkShaderMaskFilter::Make(maskImage->makeShader()),
  190. SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 3.5f),
  191. nullptr,
  192. };
  193. mfs[2] = SkMaskFilter::MakeCompose(mfs[1], mfs[0]);
  194. // Important that we test with and without an imagefilter attached to the layer,
  195. // as cpu and gpu backends treat these differently (w/ or w/o a SkSpecialImage)
  196. const sk_sp<SkImageFilter> imfs[] = {nullptr, SkBlurImageFilter::Make(3.5f, 3.5f, nullptr)};
  197. for (auto& mf : mfs) {
  198. SkPaint layerPaint;
  199. layerPaint.setMaskFilter(mf);
  200. canvas->save();
  201. for (auto& imf : imfs) {
  202. layerPaint.setImageFilter(imf);
  203. canvas->saveLayer(&r, &layerPaint);
  204. canvas->drawImage(layerImage, 0, 0, nullptr);
  205. canvas->restore();
  206. // now draw the (approximage) expected bounds of the mask
  207. canvas->drawRect(r.makeOutset(1, 1), overlayPaint);
  208. canvas->translate(r.width() + 10, 0);
  209. }
  210. canvas->restore();
  211. canvas->translate(0, r.height() + 10);
  212. }
  213. }
  214. static void draw_mask(SkCanvas* canvas) {
  215. SkPaint p;
  216. p.setAntiAlias(true);
  217. canvas->drawOval(SkRect::Make(canvas->imageInfo().bounds()), p);
  218. }
  219. DEF_SIMPLE_GM(shadermaskfilter_localmatrix, canvas, 1500, 1000) {
  220. static constexpr SkScalar kSize = 100;
  221. using ShaderMakerT = sk_sp<SkShader>(*)(SkCanvas*, const SkMatrix& lm);
  222. static const ShaderMakerT gShaderMakers[] = {
  223. [](SkCanvas* canvas, const SkMatrix& lm) -> sk_sp<SkShader> {
  224. auto surface =
  225. ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(kSize, kSize));
  226. draw_mask(surface->getCanvas());
  227. return surface->makeImageSnapshot()->makeShader(
  228. SkTileMode::kClamp, SkTileMode::kClamp, &lm);
  229. },
  230. [](SkCanvas*, const SkMatrix& lm) -> sk_sp<SkShader> {
  231. SkPictureRecorder recorder;
  232. draw_mask(recorder.beginRecording(kSize, kSize));
  233. return recorder.finishRecordingAsPicture()->makeShader(
  234. SkTileMode::kClamp,
  235. SkTileMode::kClamp,
  236. &lm,
  237. nullptr);
  238. },
  239. };
  240. struct Config {
  241. SkMatrix fCanvasMatrix,
  242. fMaskMatrix,
  243. fShaderMatrix;
  244. } gConfigs[] = {
  245. { SkMatrix::I(), SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10) },
  246. { SkMatrix::MakeScale(2, 2), SkMatrix::I(), SkMatrix::MakeTrans(10, 10) },
  247. { SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10), SkMatrix::I() },
  248. { SkMatrix::Concat(SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10)),
  249. SkMatrix::I(), SkMatrix::I() },
  250. { SkMatrix::I(),
  251. SkMatrix::Concat(SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10)),
  252. SkMatrix::I() },
  253. { SkMatrix::I(), SkMatrix::I(),
  254. SkMatrix::Concat(SkMatrix::MakeScale(2, 2), SkMatrix::MakeTrans(10, 10)) },
  255. };
  256. using DrawerT = void(*)(SkCanvas*, const SkRect&, const SkPaint&);
  257. static const DrawerT gDrawers[] = {
  258. [](SkCanvas* canvas, const SkRect& dest, const SkPaint& mask) {
  259. canvas->drawRect(dest, mask);
  260. },
  261. [](SkCanvas* canvas, const SkRect& dest, const SkPaint& mask) {
  262. canvas->saveLayer(&dest, &mask);
  263. SkPaint p = mask;
  264. p.setMaskFilter(nullptr);
  265. canvas->drawPaint(p);
  266. canvas->restore();
  267. },
  268. };
  269. SkPaint paint, rectPaint;
  270. paint.setColor(0xff00ff00);
  271. rectPaint.setStyle(SkPaint::kStroke_Style);
  272. rectPaint.setColor(0xffff0000);
  273. for (const auto& sm : gShaderMakers) {
  274. for (const auto& drawer : gDrawers) {
  275. {
  276. SkAutoCanvasRestore acr(canvas, true);
  277. for (const auto& cfg : gConfigs) {
  278. paint.setMaskFilter(SkShaderMaskFilter::Make(sm(canvas, cfg.fShaderMatrix))
  279. ->makeWithMatrix(cfg.fMaskMatrix));
  280. auto dest = SkRect::MakeWH(kSize, kSize);
  281. SkMatrix::Concat(cfg.fMaskMatrix, cfg.fShaderMatrix).mapRect(&dest);
  282. {
  283. SkAutoCanvasRestore acr(canvas, true);
  284. canvas->concat(cfg.fCanvasMatrix);
  285. drawer(canvas, dest, paint);
  286. canvas->drawRect(dest, rectPaint);
  287. }
  288. canvas->translate(kSize * 2.5f, 0);
  289. }
  290. }
  291. canvas->translate(0, kSize * 2.5f);
  292. }
  293. }
  294. }