blob: 0c5af3e303fbf1ee5636cd4396cd9901d8058276 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
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
Mike Reed80747ef2018-01-23 15:29:32 -05008#include "SkMaskFilterBase.h"
Hal Canary95e3c052017-01-11 12:44:43 -05009
10#include "SkAutoMalloc.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkBlitter.h"
Mike Reed18e75562018-03-12 14:03:47 -040012#include "SkBlurPriv.h"
Kevin Lubickc456b732017-01-11 17:21:57 +000013#include "SkCachedData.h"
Mike Reed1bd556a2018-01-26 11:42:38 -050014#include "SkCoverageModePriv.h"
Hal Canary95e3c052017-01-11 12:44:43 -050015#include "SkDraw.h"
bungemand3ebb482015-08-05 13:57:49 -070016#include "SkPath.h"
Kevin Lubickc456b732017-01-11 17:21:57 +000017#include "SkRRect.h"
Hal Canary95e3c052017-01-11 12:44:43 -050018#include "SkRasterClip.h"
Mike Reed20dc6722018-01-24 16:34:02 -050019#include "SkReadBuffer.h"
Mike Reed20dc6722018-01-24 16:34:02 -050020#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
robertphillips@google.com0b828522013-07-03 15:49:05 +000022#if SK_SUPPORT_GPU
Robert Phillips4a24da52016-12-14 09:00:07 -050023#include "GrTextureProxy.h"
Mike Reedbfadcf02018-01-20 22:24:21 +000024#include "GrFragmentProcessor.h"
Mike Reed547c8592018-02-05 15:59:23 -050025#include "effects/GrXfermodeFragmentProcessor.h"
Jim Van Verthd401da62018-05-03 10:40:30 -040026#include "text/GrSDFMaskFilter.h"
robertphillips@google.com0b828522013-07-03 15:49:05 +000027#endif
reed@google.comd729b3e2012-11-09 14:30:48 +000028
Mike Reed80747ef2018-01-23 15:29:32 -050029SkMaskFilterBase::NinePatch::~NinePatch() {
reedb0df8be2015-02-04 09:07:17 -080030 if (fCache) {
31 SkASSERT((const void*)fMask.fImage == fCache->data());
32 fCache->unref();
33 } else {
34 SkMask::FreeImage(fMask.fImage);
35 }
36}
37
Mike Reed80747ef2018-01-23 15:29:32 -050038bool SkMaskFilterBase::asABlur(BlurRec*) const {
reed@google.comdaaafa62014-04-29 15:20:16 +000039 return false;
40}
41
reed@google.comd729b3e2012-11-09 14:30:48 +000042static void extractMaskSubset(const SkMask& src, SkMask* dst) {
43 SkASSERT(src.fBounds.contains(dst->fBounds));
44
45 const int dx = dst->fBounds.left() - src.fBounds.left();
46 const int dy = dst->fBounds.top() - src.fBounds.top();
47 dst->fImage = src.fImage + dy * src.fRowBytes + dx;
48 dst->fRowBytes = src.fRowBytes;
49 dst->fFormat = src.fFormat;
50}
51
52static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
53 const SkIRect& bounds, const SkIRect& clipR) {
54 SkIRect r;
55 if (r.intersect(bounds, clipR)) {
56 blitter->blitMask(mask, r);
57 }
58}
59
60static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
61 SkIRect r;
62 if (r.intersect(rect, clipR)) {
63 blitter->blitRect(r.left(), r.top(), r.width(), r.height());
64 }
65}
66
67#if 0
68static void dump(const SkMask& mask) {
69 for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) {
70 for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) {
71 SkDebugf("%02X", *mask.getAddr8(x, y));
72 }
73 SkDebugf("\n");
74 }
75 SkDebugf("\n");
76}
77#endif
78
79static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
reed@google.comdab9b4f2012-11-19 16:45:14 +000080 const SkIPoint& center, bool fillCenter,
reed@google.comd729b3e2012-11-09 14:30:48 +000081 const SkIRect& clipR, SkBlitter* blitter) {
reed@google.comdab9b4f2012-11-19 16:45:14 +000082 int cx = center.x();
83 int cy = center.y();
reed@google.comd729b3e2012-11-09 14:30:48 +000084 SkMask m;
skia.committer@gmail.com453995e2012-11-10 02:01:26 +000085
reed@google.comd729b3e2012-11-09 14:30:48 +000086 // top-left
87 m.fBounds = mask.fBounds;
88 m.fBounds.fRight = cx;
89 m.fBounds.fBottom = cy;
tomhudson@google.com3c0ecc52013-04-25 16:56:40 +000090 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
91 extractMaskSubset(mask, &m);
92 m.fBounds.offsetTo(outerR.left(), outerR.top());
93 blitClippedMask(blitter, m, m.fBounds, clipR);
94 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +000095
reed@google.comd729b3e2012-11-09 14:30:48 +000096 // top-right
97 m.fBounds = mask.fBounds;
98 m.fBounds.fLeft = cx + 1;
99 m.fBounds.fBottom = cy;
tomhudson@google.com3c0ecc52013-04-25 16:56:40 +0000100 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
101 extractMaskSubset(mask, &m);
102 m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top());
103 blitClippedMask(blitter, m, m.fBounds, clipR);
104 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000105
reed@google.comd729b3e2012-11-09 14:30:48 +0000106 // bottom-left
107 m.fBounds = mask.fBounds;
108 m.fBounds.fRight = cx;
109 m.fBounds.fTop = cy + 1;
tomhudson@google.com3c0ecc52013-04-25 16:56:40 +0000110 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
111 extractMaskSubset(mask, &m);
112 m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height());
113 blitClippedMask(blitter, m, m.fBounds, clipR);
114 }
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000115
reed@google.comd729b3e2012-11-09 14:30:48 +0000116 // bottom-right
117 m.fBounds = mask.fBounds;
118 m.fBounds.fLeft = cx + 1;
119 m.fBounds.fTop = cy + 1;
tomhudson@google.com3c0ecc52013-04-25 16:56:40 +0000120 if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
121 extractMaskSubset(mask, &m);
122 m.fBounds.offsetTo(outerR.right() - m.fBounds.width(),
123 outerR.bottom() - m.fBounds.height());
124 blitClippedMask(blitter, m, m.fBounds, clipR);
125 }
reed@google.comd729b3e2012-11-09 14:30:48 +0000126
127 SkIRect innerR;
128 innerR.set(outerR.left() + cx - mask.fBounds.left(),
129 outerR.top() + cy - mask.fBounds.top(),
130 outerR.right() + (cx + 1 - mask.fBounds.right()),
131 outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
reed@google.comdab9b4f2012-11-19 16:45:14 +0000132 if (fillCenter) {
133 blitClippedRect(blitter, innerR, clipR);
134 }
reed@google.comd729b3e2012-11-09 14:30:48 +0000135
136 const int innerW = innerR.width();
137 size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
138 SkAutoSMalloc<4*1024> storage(storageSize);
139 int16_t* runs = (int16_t*)storage.get();
140 uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
141
142 SkIRect r;
143 // top
144 r.set(innerR.left(), outerR.top(), innerR.right(), innerR.top());
145 if (r.intersect(clipR)) {
146 int startY = SkMax32(0, r.top() - outerR.top());
147 int stopY = startY + r.height();
148 int width = r.width();
149 for (int y = startY; y < stopY; ++y) {
150 runs[0] = width;
151 runs[width] = 0;
152 alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
153 blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
154 }
155 }
156 // bottom
157 r.set(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
158 if (r.intersect(clipR)) {
159 int startY = outerR.bottom() - r.bottom();
160 int stopY = startY + r.height();
161 int width = r.width();
162 for (int y = startY; y < stopY; ++y) {
163 runs[0] = width;
164 runs[width] = 0;
165 alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
166 blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
167 }
168 }
169 // left
170 r.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
171 if (r.intersect(clipR)) {
Mike Reedbb3bf142017-06-29 08:43:43 -0400172 SkMask m;
173 m.fImage = mask.getAddr8(mask.fBounds.left() + r.left() - outerR.left(),
174 mask.fBounds.top() + cy);
175 m.fBounds = r;
176 m.fRowBytes = 0; // so we repeat the scanline for our height
177 m.fFormat = SkMask::kA8_Format;
178 blitter->blitMask(m, r);
reed@google.comd729b3e2012-11-09 14:30:48 +0000179 }
180 // right
181 r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
182 if (r.intersect(clipR)) {
Mike Reedbb3bf142017-06-29 08:43:43 -0400183 SkMask m;
184 m.fImage = mask.getAddr8(mask.fBounds.right() - outerR.right() + r.left(),
185 mask.fBounds.top() + cy);
186 m.fBounds = r;
187 m.fRowBytes = 0; // so we repeat the scanline for our height
188 m.fFormat = SkMask::kA8_Format;
189 blitter->blitMask(m, r);
reed@google.comd729b3e2012-11-09 14:30:48 +0000190 }
191}
192
reed868074b2014-06-03 10:53:59 -0700193static void draw_nine(const SkMask& mask, const SkIRect& outerR, const SkIPoint& center,
194 bool fillCenter, const SkRasterClip& clip, SkBlitter* blitter) {
reed@google.comd729b3e2012-11-09 14:30:48 +0000195 // if we get here, we need to (possibly) resolve the clip and blitter
196 SkAAClipBlitterWrapper wrapper(clip, blitter);
197 blitter = wrapper.getBlitter();
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000198
reed@google.comd729b3e2012-11-09 14:30:48 +0000199 SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
skia.committer@gmail.com453995e2012-11-10 02:01:26 +0000200
reed868074b2014-06-03 10:53:59 -0700201 if (!clipper.done()) {
reed@google.comd729b3e2012-11-09 14:30:48 +0000202 const SkIRect& cr = clipper.rect();
203 do {
reed@google.comdab9b4f2012-11-19 16:45:14 +0000204 draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
reed@google.comd729b3e2012-11-09 14:30:48 +0000205 clipper.next();
206 } while (!clipper.done());
207 }
208}
209
reed@google.comdab9b4f2012-11-19 16:45:14 +0000210static int countNestedRects(const SkPath& path, SkRect rects[2]) {
caryclark95bc5f32015-04-08 08:34:15 -0700211 if (path.isNestedFillRects(rects)) {
reed@google.comdab9b4f2012-11-19 16:45:14 +0000212 return 2;
213 }
214 return path.isRect(&rects[0]);
215}
216
Mike Reed80747ef2018-01-23 15:29:32 -0500217bool SkMaskFilterBase::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
218 const SkRasterClip& clip, SkBlitter* blitter) const {
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000219 // Attempt to speed up drawing by creating a nine patch. If a nine patch
220 // cannot be used, return false to allow our caller to recover and perform
221 // the drawing another way.
222 NinePatch patch;
halcanary96fcdcc2015-08-27 07:41:13 -0700223 patch.fMask.fImage = nullptr;
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000224 if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
225 clip.getBounds(),
226 &patch)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700227 SkASSERT(nullptr == patch.fMask.fImage);
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000228 return false;
229 }
reed868074b2014-06-03 10:53:59 -0700230 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000231 return true;
232}
233
Mike Reed80747ef2018-01-23 15:29:32 -0500234bool SkMaskFilterBase::filterPath(const SkPath& devPath, const SkMatrix& matrix,
235 const SkRasterClip& clip, SkBlitter* blitter,
236 SkStrokeRec::InitStyle style) const {
reed@google.comdab9b4f2012-11-19 16:45:14 +0000237 SkRect rects[2];
238 int rectCount = 0;
bsalomon055e1922016-05-06 07:22:58 -0700239 if (SkStrokeRec::kFill_InitStyle == style) {
reed@google.comdab9b4f2012-11-19 16:45:14 +0000240 rectCount = countNestedRects(devPath, rects);
241 }
242 if (rectCount > 0) {
243 NinePatch patch;
reed@google.comd729b3e2012-11-09 14:30:48 +0000244
reedb0df8be2015-02-04 09:07:17 -0800245 switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
reed@google.comd729b3e2012-11-09 14:30:48 +0000246 case kFalse_FilterReturn:
halcanary96fcdcc2015-08-27 07:41:13 -0700247 SkASSERT(nullptr == patch.fMask.fImage);
reed@google.comd729b3e2012-11-09 14:30:48 +0000248 return false;
reed@google.comdab9b4f2012-11-19 16:45:14 +0000249
reed@google.comd729b3e2012-11-09 14:30:48 +0000250 case kTrue_FilterReturn:
reed868074b2014-06-03 10:53:59 -0700251 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
252 blitter);
reed@google.comd729b3e2012-11-09 14:30:48 +0000253 return true;
reed@google.comdab9b4f2012-11-19 16:45:14 +0000254
reed@google.comd729b3e2012-11-09 14:30:48 +0000255 case kUnimplemented_FilterReturn:
halcanary96fcdcc2015-08-27 07:41:13 -0700256 SkASSERT(nullptr == patch.fMask.fImage);
reed@google.comd729b3e2012-11-09 14:30:48 +0000257 // fall through
258 break;
259 }
260 }
261
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 SkMask srcM, dstM;
263
264 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
junov@chromium.org2ac4ef52012-04-04 15:16:51 +0000265 SkMask::kComputeBoundsAndRenderImage_CreateMode,
266 style)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 return false;
268 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000269 SkAutoMaskFreeImage autoSrc(srcM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270
halcanary96fcdcc2015-08-27 07:41:13 -0700271 if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
qiankun.miaoeabd0d72015-01-07 19:20:49 -0800272 return false;
reed@google.comfeb8cc82011-04-19 20:11:25 +0000273 }
bungeman@google.com02f55842011-10-04 21:25:00 +0000274 SkAutoMaskFreeImage autoDst(dstM.fImage);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275
reed@google.com045e62d2011-10-24 12:19:46 +0000276 // if we get here, we need to (possibly) resolve the clip and blitter
277 SkAAClipBlitterWrapper wrapper(clip, blitter);
278 blitter = wrapper.getBlitter();
279
280 SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281
reed868074b2014-06-03 10:53:59 -0700282 if (!clipper.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 const SkIRect& cr = clipper.rect();
284 do {
285 blitter->blitMask(dstM, cr);
286 clipper.next();
287 } while (!clipper.done());
288 }
289
290 return true;
291}
292
Mike Reed80747ef2018-01-23 15:29:32 -0500293SkMaskFilterBase::FilterReturn
294SkMaskFilterBase::filterRRectToNine(const SkRRect&, const SkMatrix&,
295 const SkIRect& clipBounds, NinePatch*) const {
scroggo@google.coma8e33a92013-11-08 18:02:53 +0000296 return kUnimplemented_FilterReturn;
297}
298
Mike Reed80747ef2018-01-23 15:29:32 -0500299SkMaskFilterBase::FilterReturn
300SkMaskFilterBase::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
301 const SkIRect& clipBounds, NinePatch*) const {
reed@google.comd729b3e2012-11-09 14:30:48 +0000302 return kUnimplemented_FilterReturn;
303}
304
robertphillips@google.com0b828522013-07-03 15:49:05 +0000305#if SK_SUPPORT_GPU
Mike Reed80747ef2018-01-23 15:29:32 -0500306std::unique_ptr<GrFragmentProcessor>
307SkMaskFilterBase::asFragmentProcessor(const GrFPArgs& args) const {
Mike Reedbfadcf02018-01-20 22:24:21 +0000308 auto fp = this->onAsFragmentProcessor(args);
309 if (fp) {
310 SkASSERT(this->hasFragmentProcessor());
311 } else {
312 SkASSERT(!this->hasFragmentProcessor());
313 }
314 return fp;
315}
Mike Reed80747ef2018-01-23 15:29:32 -0500316bool SkMaskFilterBase::hasFragmentProcessor() const {
Mike Reedbfadcf02018-01-20 22:24:21 +0000317 return this->onHasFragmentProcessor();
318}
319
Mike Reed80747ef2018-01-23 15:29:32 -0500320std::unique_ptr<GrFragmentProcessor>
321SkMaskFilterBase::onAsFragmentProcessor(const GrFPArgs&) const {
Mike Reedbfadcf02018-01-20 22:24:21 +0000322 return nullptr;
323}
Mike Reed80747ef2018-01-23 15:29:32 -0500324bool SkMaskFilterBase::onHasFragmentProcessor() const { return false; }
Mike Reedbfadcf02018-01-20 22:24:21 +0000325
Robert Phillips27927a52018-08-20 13:18:12 -0400326bool SkMaskFilterBase::canFilterMaskGPU(const GrShape& shape,
327 const SkRect& devSpaceShapeBounds,
Mike Reed80747ef2018-01-23 15:29:32 -0500328 const SkIRect& clipBounds,
329 const SkMatrix& ctm,
330 SkRect* maskRect) const {
robertphillips@google.com49149312013-07-03 15:34:35 +0000331 return false;
332}
333
Mike Reed80747ef2018-01-23 15:29:32 -0500334bool SkMaskFilterBase::directFilterMaskGPU(GrContext*,
Robert Phillips20390c32018-08-17 11:01:03 -0400335 GrRenderTargetContext*,
Mike Reed80747ef2018-01-23 15:29:32 -0500336 GrPaint&&,
337 const GrClip&,
338 const SkMatrix& viewMatrix,
Robert Phillips27927a52018-08-20 13:18:12 -0400339 const GrShape&) const {
commit-bot@chromium.orgcf34bc02014-01-30 15:34:43 +0000340 return false;
341}
342
Mike Reed80747ef2018-01-23 15:29:32 -0500343bool SkMaskFilterBase::directFilterRRectMaskGPU(GrContext*,
Robert Phillips20390c32018-08-17 11:01:03 -0400344 GrRenderTargetContext*,
Mike Reed80747ef2018-01-23 15:29:32 -0500345 GrPaint&&,
346 const GrClip&,
347 const SkMatrix& viewMatrix,
Robert Phillips20390c32018-08-17 11:01:03 -0400348 const SkStrokeRec&,
Mike Reed80747ef2018-01-23 15:29:32 -0500349 const SkRRect& rrect,
350 const SkRRect& devRRect) const {
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000351 return false;
352}
353
Mike Reed80747ef2018-01-23 15:29:32 -0500354sk_sp<GrTextureProxy> SkMaskFilterBase::filterMaskGPU(GrContext*,
355 sk_sp<GrTextureProxy> srcProxy,
356 const SkMatrix& ctm,
357 const SkIRect& maskRect) const {
Robert Phillips4a24da52016-12-14 09:00:07 -0500358 return nullptr;
reed@google.com2b75f422011-07-07 13:43:38 +0000359}
robertphillips@google.com0b828522013-07-03 15:49:05 +0000360#endif
reed@google.com2b75f422011-07-07 13:43:38 +0000361
Mike Reed80747ef2018-01-23 15:29:32 -0500362void SkMaskFilterBase::computeFastBounds(const SkRect& src, SkRect* dst) const {
reed@google.com9efd9a02012-01-30 15:41:43 +0000363 SkMask srcM, dstM;
364
reedb07a94f2014-11-19 05:03:18 -0800365 srcM.fBounds = src.roundOut();
reed@google.com9efd9a02012-01-30 15:41:43 +0000366 srcM.fRowBytes = 0;
367 srcM.fFormat = SkMask::kA8_Format;
368
369 SkIPoint margin; // ignored
370 if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
371 dst->set(dstM.fBounds);
372 } else {
373 dst->set(srcM.fBounds);
374 }
375}
Mike Reed20dc6722018-01-24 16:34:02 -0500376
377///////////////////////////////////////////////////////////////////////////////////////////////////
378
379template <typename T> static inline T join(const T& a, const T& b) {
380 T r = a;
381 r.join(b);
382 return r;
383}
Mike Reed1bd556a2018-01-26 11:42:38 -0500384template <typename T> static inline T sect(const T& a, const T& b) {
385 T r = a;
386 return r.intersect(b) ? r : T::MakeEmpty();
387}
Mike Reed20dc6722018-01-24 16:34:02 -0500388
389class SkComposeMF : public SkMaskFilterBase {
390public:
391 SkComposeMF(sk_sp<SkMaskFilter> outer, sk_sp<SkMaskFilter> inner)
392 : fOuter(std::move(outer))
393 , fInner(std::move(inner))
394 {
395 SkASSERT(as_MFB(fOuter)->getFormat() == SkMask::kA8_Format);
396 SkASSERT(as_MFB(fInner)->getFormat() == SkMask::kA8_Format);
397 }
398
399 bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint*) const override;
400
401 void computeFastBounds(const SkRect& src, SkRect* dst) const override {
402 SkRect tmp;
403 as_MFB(fInner)->computeFastBounds(src, &tmp);
404 as_MFB(fOuter)->computeFastBounds(tmp, dst);
405 }
406
407 SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
Mike Reed20dc6722018-01-24 16:34:02 -0500408 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeMF)
409
Mike Reed547c8592018-02-05 15:59:23 -0500410protected:
411#if SK_SUPPORT_GPU
412 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
413 std::unique_ptr<GrFragmentProcessor> array[2] = {
414 as_MFB(fInner)->asFragmentProcessor(args),
415 as_MFB(fOuter)->asFragmentProcessor(args),
416 };
417 if (!array[0] || !array[1]) {
418 return nullptr;
419 }
420 return GrFragmentProcessor::RunInSeries(array, 2);
421 }
422
423 bool onHasFragmentProcessor() const override {
424 return as_MFB(fInner)->hasFragmentProcessor() && as_MFB(fOuter)->hasFragmentProcessor();
425 }
426#endif
427
Mike Reed20dc6722018-01-24 16:34:02 -0500428private:
429 sk_sp<SkMaskFilter> fOuter;
430 sk_sp<SkMaskFilter> fInner;
431
432 void flatten(SkWriteBuffer&) const override;
433
434 friend class SkMaskFilter;
435
436 typedef SkMaskFilterBase INHERITED;
437};
438
439bool SkComposeMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
440 SkIPoint* margin) const {
441 SkIPoint innerMargin;
442 SkMask innerMask;
443
444 if (!as_MFB(fInner)->filterMask(&innerMask, src, ctm, &innerMargin)) {
445 return false;
446 }
447 if (!as_MFB(fOuter)->filterMask(dst, innerMask, ctm, margin)) {
448 return false;
449 }
450 if (margin) {
451 margin->fX += innerMargin.fX;
452 margin->fY += innerMargin.fY;
453 }
454 sk_free(innerMask.fImage);
455 return true;
456}
457
458void SkComposeMF::flatten(SkWriteBuffer & buffer) const {
459 buffer.writeFlattenable(fOuter.get());
460 buffer.writeFlattenable(fInner.get());
461}
462
463sk_sp<SkFlattenable> SkComposeMF::CreateProc(SkReadBuffer& buffer) {
464 auto outer = buffer.readMaskFilter();
465 auto inner = buffer.readMaskFilter();
466 if (!buffer.validate(outer && inner)) {
467 return nullptr;
468 }
469 return SkMaskFilter::MakeCompose(std::move(outer), std::move(inner));
470}
471
Mike Reed20dc6722018-01-24 16:34:02 -0500472///////////////////////////////////////////////////////////////////////////////////////////////////
473
474class SkCombineMF : public SkMaskFilterBase {
475public:
Mike Reed1bd556a2018-01-26 11:42:38 -0500476 SkCombineMF(sk_sp<SkMaskFilter> dst, sk_sp<SkMaskFilter> src, SkCoverageMode mode)
Mike Reed20dc6722018-01-24 16:34:02 -0500477 : fDst(std::move(dst))
478 , fSrc(std::move(src))
479 , fMode(mode)
480 {
481 SkASSERT(as_MFB(fSrc)->getFormat() == SkMask::kA8_Format);
482 SkASSERT(as_MFB(fDst)->getFormat() == SkMask::kA8_Format);
483 }
484
485 bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint*) const override;
486
487 void computeFastBounds(const SkRect& src, SkRect* dst) const override {
488 SkRect srcR, dstR;
489 as_MFB(fSrc)->computeFastBounds(src, &srcR);
490 as_MFB(fDst)->computeFastBounds(src, &dstR);
491 *dst = join(srcR, dstR);
492 }
493
494 SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
Mike Reed1bd556a2018-01-26 11:42:38 -0500495
Mike Reed20dc6722018-01-24 16:34:02 -0500496 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkCombineMF)
497
Mike Reed547c8592018-02-05 15:59:23 -0500498protected:
499#if SK_SUPPORT_GPU
500 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
501 auto src = as_MFB(fSrc)->asFragmentProcessor(args);
502 auto dst = as_MFB(fDst)->asFragmentProcessor(args);
503 if (!src || !dst) {
504 return nullptr;
505 }
506 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(src), std::move(dst),
507 SkUncorrelatedCoverageModeToBlendMode(fMode));
508 }
509
510 bool onHasFragmentProcessor() const override {
511 return as_MFB(fSrc)->hasFragmentProcessor() && as_MFB(fDst)->hasFragmentProcessor();
512 }
513#endif
514
Mike Reed20dc6722018-01-24 16:34:02 -0500515private:
516 sk_sp<SkMaskFilter> fDst;
517 sk_sp<SkMaskFilter> fSrc;
Mike Reed1bd556a2018-01-26 11:42:38 -0500518 SkCoverageMode fMode;
Mike Reed20dc6722018-01-24 16:34:02 -0500519
520 void flatten(SkWriteBuffer&) const override;
521
522 friend class SkMaskFilter;
523
524 typedef SkMaskFilterBase INHERITED;
525};
526
527#include "SkSafeMath.h"
528
529class DrawIntoMask : public SkDraw {
Mike Reed20dc6722018-01-24 16:34:02 -0500530public:
Mike Reed1bd556a2018-01-26 11:42:38 -0500531 // we ignore the offset of the mask->fBounds
Mike Reed20dc6722018-01-24 16:34:02 -0500532 DrawIntoMask(SkMask* mask) {
533 int w = mask->fBounds.width();
534 int h = mask->fBounds.height();
535 size_t size = SkSafeMath::Mul(w, h);
536 mask->fFormat = SkMask::kA8_Format;
537 mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
538 mask->fRowBytes = w;
539
540 SkAssertResult(fDst.reset(*mask));
541
542 fMatrixStorage.reset();
543 fMatrix = &fMatrixStorage;
544
545 fRCStorage.setRect({ 0, 0, w, h });
546 fRC = &fRCStorage;
Mike Reed20dc6722018-01-24 16:34:02 -0500547 }
548
Mike Reed1bd556a2018-01-26 11:42:38 -0500549 void drawAsBitmap(const SkMask& m, const SkPaint& p) {
550 SkBitmap b;
551 b.installMaskPixels(m);
552 this->drawSprite(b, m.fBounds.fLeft, m.fBounds.fTop, p);
Mike Reed20dc6722018-01-24 16:34:02 -0500553 }
Mike Reed1bd556a2018-01-26 11:42:38 -0500554
555private:
556 SkMatrix fMatrixStorage;
557 SkRasterClip fRCStorage;
Mike Reed20dc6722018-01-24 16:34:02 -0500558};
559
Mike Reed1bd556a2018-01-26 11:42:38 -0500560static SkIRect join(const SkIRect& src, const SkIRect& dst, SkCoverageMode mode) {
561 switch (mode) {
562 case SkCoverageMode::kUnion: return join(src, dst);
563 case SkCoverageMode::kIntersect: return sect(src, dst);
564 case SkCoverageMode::kDifference: return src;
565 case SkCoverageMode::kReverseDifference: return dst;
566 case SkCoverageMode::kXor: return join(src, dst);
567 }
568 // not reached
569 return { 0, 0, 0, 0 };
570}
571
Mike Reed20dc6722018-01-24 16:34:02 -0500572bool SkCombineMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
573 SkIPoint* margin) const {
574 SkIPoint srcP, dstP;
575 SkMask srcM, dstM;
576
577 if (!as_MFB(fSrc)->filterMask(&srcM, src, ctm, &srcP)) {
578 return false;
579 }
580 if (!as_MFB(fDst)->filterMask(&dstM, src, ctm, &dstP)) {
581 return false;
582 }
583
Mike Reed1bd556a2018-01-26 11:42:38 -0500584 dst->fBounds = join(srcM.fBounds, dstM.fBounds, fMode);
Mike Reed20dc6722018-01-24 16:34:02 -0500585 dst->fFormat = SkMask::kA8_Format;
586 if (src.fImage == nullptr) {
587 dst->fImage = nullptr;
588 return true;
589 }
590
591 DrawIntoMask md(dst);
592 SkPaint p;
593
594 p.setBlendMode(SkBlendMode::kSrc);
Mike Reed1bd556a2018-01-26 11:42:38 -0500595 dstM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop);
596 md.drawAsBitmap(dstM, p);
Mike Reed547c8592018-02-05 15:59:23 -0500597 p.setBlendMode(SkUncorrelatedCoverageModeToBlendMode(fMode));
Mike Reed1bd556a2018-01-26 11:42:38 -0500598 srcM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop);
599 md.drawAsBitmap(srcM, p);
Mike Reed20dc6722018-01-24 16:34:02 -0500600
601 sk_free(srcM.fImage);
602 sk_free(dstM.fImage);
603 return true;
604}
605
606void SkCombineMF::flatten(SkWriteBuffer & buffer) const {
607 buffer.writeFlattenable(fDst.get());
608 buffer.writeFlattenable(fSrc.get());
609 buffer.write32(static_cast<uint32_t>(fMode));
610}
611
612sk_sp<SkFlattenable> SkCombineMF::CreateProc(SkReadBuffer& buffer) {
Mike Reed20dc6722018-01-24 16:34:02 -0500613 auto dst = buffer.readMaskFilter();
614 auto src = buffer.readMaskFilter();
Mike Reedde5c5022018-01-26 14:59:12 -0500615 SkCoverageMode mode = buffer.read32LE(SkCoverageMode::kLast);
616 if (!buffer.validate(dst && src)) {
Mike Reed20dc6722018-01-24 16:34:02 -0500617 return nullptr;
618 }
619 return SkMaskFilter::MakeCombine(std::move(dst), std::move(src), mode);
620}
621
Mike Reedbe33bab2018-02-06 16:07:51 -0500622///////////////////////////////////////////////////////////////////////////////////////////////////
623
Florin Malitac6c5ead2018-04-11 15:33:40 -0400624class SkMatrixMF : public SkMaskFilterBase {
Mike Reedbe33bab2018-02-06 16:07:51 -0500625public:
Florin Malitac6c5ead2018-04-11 15:33:40 -0400626 SkMatrixMF(sk_sp<SkMaskFilter> filter, const SkMatrix& lm)
Mike Reedbe33bab2018-02-06 16:07:51 -0500627 : fFilter(std::move(filter))
628 , fLM(lm)
629 {}
630
631 bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
632 SkIPoint* margin) const override {
633 return as_MFB(fFilter)->filterMask(dst, src, SkMatrix::Concat(ctm, fLM), margin);
634 }
635
636 void computeFastBounds(const SkRect& src, SkRect* dst) const override {
637 *dst = src;
638 SkRect tmp;
639 fLM.mapRect(&tmp, src);
640 as_MFB(fFilter)->computeFastBounds(tmp, dst);
641 }
642
643 SkMask::Format getFormat() const override { return as_MFB(fFilter)->getFormat(); }
644
Mike Reedbe33bab2018-02-06 16:07:51 -0500645 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLocalMatrixMF)
646
647protected:
648#if SK_SUPPORT_GPU
649 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
Florin Malitac6c5ead2018-04-11 15:33:40 -0400650 return as_MFB(fFilter)->asFragmentProcessor(GrFPArgs::WithPostLocalMatrix(args, fLM));
Mike Reedbe33bab2018-02-06 16:07:51 -0500651 }
652
653 bool onHasFragmentProcessor() const override {
654 return as_MFB(fFilter)->hasFragmentProcessor();
655 }
656#endif
657
658private:
659 sk_sp<SkMaskFilter> fFilter;
660 const SkMatrix fLM;
661
662 void flatten(SkWriteBuffer& buffer) const override {
663 buffer.writeMatrix(fLM);
664 buffer.writeFlattenable(fFilter.get());
665 }
666
667 friend class SkMaskFilter;
668 typedef SkMaskFilterBase INHERITED;
669};
670
Florin Malitac6c5ead2018-04-11 15:33:40 -0400671sk_sp<SkFlattenable> SkMatrixMF::CreateProc(SkReadBuffer& buffer) {
672 SkMatrix m;
673 buffer.readMatrix(&m);
Mike Reedbe33bab2018-02-06 16:07:51 -0500674 auto filter = buffer.readMaskFilter();
Florin Malitac6c5ead2018-04-11 15:33:40 -0400675 return filter ? filter->makeWithMatrix(m) : nullptr;
Mike Reedbe33bab2018-02-06 16:07:51 -0500676}
677
678///////////////////////////////////////////////////////////////////////////////////////////////////
Mike Reed20dc6722018-01-24 16:34:02 -0500679
Mike Reed1bd556a2018-01-26 11:42:38 -0500680sk_sp<SkMaskFilter> SkMaskFilter::MakeCompose(sk_sp<SkMaskFilter> outer,
681 sk_sp<SkMaskFilter> inner) {
Mike Reed20dc6722018-01-24 16:34:02 -0500682 if (!outer) {
683 return inner;
684 }
685 if (!inner) {
686 return outer;
687 }
688 if (as_MFB(inner)->getFormat() != SkMask::kA8_Format ||
689 as_MFB(outer)->getFormat() != SkMask::kA8_Format) {
690 return nullptr;
691 }
692 return sk_sp<SkMaskFilter>(new SkComposeMF(std::move(outer), std::move(inner)));
693}
694
695sk_sp<SkMaskFilter> SkMaskFilter::MakeCombine(sk_sp<SkMaskFilter> dst, sk_sp<SkMaskFilter> src,
Mike Reed1bd556a2018-01-26 11:42:38 -0500696 SkCoverageMode mode) {
697 if (!dst) {
Mike Reed20dc6722018-01-24 16:34:02 -0500698 return src;
699 }
Mike Reed1bd556a2018-01-26 11:42:38 -0500700 if (!src) {
Mike Reed20dc6722018-01-24 16:34:02 -0500701 return dst;
702 }
Mike Reed20dc6722018-01-24 16:34:02 -0500703
704 if (as_MFB(dst)->getFormat() != SkMask::kA8_Format ||
705 as_MFB(src)->getFormat() != SkMask::kA8_Format) {
706 return nullptr;
707 }
708 return sk_sp<SkMaskFilter>(new SkCombineMF(std::move(dst), std::move(src), mode));
709}
710
Florin Malitac6c5ead2018-04-11 15:33:40 -0400711sk_sp<SkMaskFilter> SkMaskFilter::makeWithMatrix(const SkMatrix& lm) const {
Mike Reedbe33bab2018-02-06 16:07:51 -0500712 sk_sp<SkMaskFilter> me = sk_ref_sp(const_cast<SkMaskFilter*>(this));
713 if (lm.isIdentity()) {
714 return me;
715 }
Florin Malitac6c5ead2018-04-11 15:33:40 -0400716 return sk_sp<SkMaskFilter>(new SkMatrixMF(std::move(me), lm));
Mike Reedbe33bab2018-02-06 16:07:51 -0500717}
718
Mike Reed20dc6722018-01-24 16:34:02 -0500719void SkMaskFilter::InitializeFlattenables() {
Florin Malitac6c5ead2018-04-11 15:33:40 -0400720 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixMF)
Mike Reed20dc6722018-01-24 16:34:02 -0500721 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeMF)
722 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkCombineMF)
Mike Reed18e75562018-03-12 14:03:47 -0400723 sk_register_blur_maskfilter_createproc();
Jim Van Verthd401da62018-05-03 10:40:30 -0400724#if SK_SUPPORT_GPU
725 gr_register_sdf_maskfilter_createproc();
726#endif
Mike Reed20dc6722018-01-24 16:34:02 -0500727}