1 /*
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
8 #include "SkMaskFilterBase.h"
9
10 #include "SkAutoMalloc.h"
11 #include "SkBlitter.h"
12 #include "SkBlurPriv.h"
13 #include "SkCachedData.h"
14 #include "SkCoverageModePriv.h"
15 #include "SkDraw.h"
16 #include "SkPath.h"
17 #include "SkRRect.h"
18 #include "SkRasterClip.h"
19 #include "SkReadBuffer.h"
20 #include "SkWriteBuffer.h"
21
22 #if SK_SUPPORT_GPU
23 #include "GrTextureProxy.h"
24 #include "GrFragmentProcessor.h"
25 #include "effects/GrXfermodeFragmentProcessor.h"
26 #include "text/GrSDFMaskFilter.h"
27 #endif
28
~NinePatch()29 SkMaskFilterBase::NinePatch::~NinePatch() {
30 if (fCache) {
31 SkASSERT((const void*)fMask.fImage == fCache->data());
32 fCache->unref();
33 } else {
34 SkMask::FreeImage(fMask.fImage);
35 }
36 }
37
asABlur(BlurRec *) const38 bool SkMaskFilterBase::asABlur(BlurRec*) const {
39 return false;
40 }
41
extractMaskSubset(const SkMask & src,SkMask * dst)42 static 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
blitClippedMask(SkBlitter * blitter,const SkMask & mask,const SkIRect & bounds,const SkIRect & clipR)52 static 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
blitClippedRect(SkBlitter * blitter,const SkIRect & rect,const SkIRect & clipR)60 static 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
68 static 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
draw_nine_clipped(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkIRect & clipR,SkBlitter * blitter)79 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
80 const SkIPoint& center, bool fillCenter,
81 const SkIRect& clipR, SkBlitter* blitter) {
82 int cx = center.x();
83 int cy = center.y();
84 SkMask m;
85
86 // top-left
87 m.fBounds = mask.fBounds;
88 m.fBounds.fRight = cx;
89 m.fBounds.fBottom = cy;
90 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 }
95
96 // top-right
97 m.fBounds = mask.fBounds;
98 m.fBounds.fLeft = cx + 1;
99 m.fBounds.fBottom = cy;
100 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 }
105
106 // bottom-left
107 m.fBounds = mask.fBounds;
108 m.fBounds.fRight = cx;
109 m.fBounds.fTop = cy + 1;
110 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 }
115
116 // bottom-right
117 m.fBounds = mask.fBounds;
118 m.fBounds.fLeft = cx + 1;
119 m.fBounds.fTop = cy + 1;
120 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 }
126
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()));
132 if (fillCenter) {
133 blitClippedRect(blitter, innerR, clipR);
134 }
135
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)) {
172 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);
179 }
180 // right
181 r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
182 if (r.intersect(clipR)) {
183 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);
190 }
191 }
192
draw_nine(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkRasterClip & clip,SkBlitter * blitter)193 static void draw_nine(const SkMask& mask, const SkIRect& outerR, const SkIPoint& center,
194 bool fillCenter, const SkRasterClip& clip, SkBlitter* blitter) {
195 // if we get here, we need to (possibly) resolve the clip and blitter
196 SkAAClipBlitterWrapper wrapper(clip, blitter);
197 blitter = wrapper.getBlitter();
198
199 SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
200
201 if (!clipper.done()) {
202 const SkIRect& cr = clipper.rect();
203 do {
204 draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
205 clipper.next();
206 } while (!clipper.done());
207 }
208 }
209
countNestedRects(const SkPath & path,SkRect rects[2])210 static int countNestedRects(const SkPath& path, SkRect rects[2]) {
211 if (path.isNestedFillRects(rects)) {
212 return 2;
213 }
214 return path.isRect(&rects[0]);
215 }
216
filterRRect(const SkRRect & devRRect,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter) const217 bool SkMaskFilterBase::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
218 const SkRasterClip& clip, SkBlitter* blitter) const {
219 // 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;
223 patch.fMask.fImage = nullptr;
224 if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
225 clip.getBounds(),
226 &patch)) {
227 SkASSERT(nullptr == patch.fMask.fImage);
228 return false;
229 }
230 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
231 return true;
232 }
233
filterPath(const SkPath & devPath,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter,SkStrokeRec::InitStyle style) const234 bool SkMaskFilterBase::filterPath(const SkPath& devPath, const SkMatrix& matrix,
235 const SkRasterClip& clip, SkBlitter* blitter,
236 SkStrokeRec::InitStyle style) const {
237 SkRect rects[2];
238 int rectCount = 0;
239 if (SkStrokeRec::kFill_InitStyle == style) {
240 rectCount = countNestedRects(devPath, rects);
241 }
242 if (rectCount > 0) {
243 NinePatch patch;
244
245 switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
246 case kFalse_FilterReturn:
247 SkASSERT(nullptr == patch.fMask.fImage);
248 return false;
249
250 case kTrue_FilterReturn:
251 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
252 blitter);
253 return true;
254
255 case kUnimplemented_FilterReturn:
256 SkASSERT(nullptr == patch.fMask.fImage);
257 // fall through
258 break;
259 }
260 }
261
262 SkMask srcM, dstM;
263
264 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
265 SkMask::kComputeBoundsAndRenderImage_CreateMode,
266 style)) {
267 return false;
268 }
269 SkAutoMaskFreeImage autoSrc(srcM.fImage);
270
271 if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
272 return false;
273 }
274 SkAutoMaskFreeImage autoDst(dstM.fImage);
275
276 // 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);
281
282 if (!clipper.done()) {
283 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
293 SkMaskFilterBase::FilterReturn
filterRRectToNine(const SkRRect &,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const294 SkMaskFilterBase::filterRRectToNine(const SkRRect&, const SkMatrix&,
295 const SkIRect& clipBounds, NinePatch*) const {
296 return kUnimplemented_FilterReturn;
297 }
298
299 SkMaskFilterBase::FilterReturn
filterRectsToNine(const SkRect[],int count,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const300 SkMaskFilterBase::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
301 const SkIRect& clipBounds, NinePatch*) const {
302 return kUnimplemented_FilterReturn;
303 }
304
305 #if SK_SUPPORT_GPU
306 std::unique_ptr<GrFragmentProcessor>
asFragmentProcessor(const GrFPArgs & args) const307 SkMaskFilterBase::asFragmentProcessor(const GrFPArgs& args) const {
308 auto fp = this->onAsFragmentProcessor(args);
309 if (fp) {
310 SkASSERT(this->hasFragmentProcessor());
311 } else {
312 SkASSERT(!this->hasFragmentProcessor());
313 }
314 return fp;
315 }
hasFragmentProcessor() const316 bool SkMaskFilterBase::hasFragmentProcessor() const {
317 return this->onHasFragmentProcessor();
318 }
319
320 std::unique_ptr<GrFragmentProcessor>
onAsFragmentProcessor(const GrFPArgs &) const321 SkMaskFilterBase::onAsFragmentProcessor(const GrFPArgs&) const {
322 return nullptr;
323 }
onHasFragmentProcessor() const324 bool SkMaskFilterBase::onHasFragmentProcessor() const { return false; }
325
canFilterMaskGPU(const GrShape & shape,const SkIRect & devSpaceShapeBounds,const SkIRect & clipBounds,const SkMatrix & ctm,SkIRect * maskRect) const326 bool SkMaskFilterBase::canFilterMaskGPU(const GrShape& shape,
327 const SkIRect& devSpaceShapeBounds,
328 const SkIRect& clipBounds,
329 const SkMatrix& ctm,
330 SkIRect* maskRect) const {
331 return false;
332 }
333
directFilterMaskGPU(GrContext *,GrRenderTargetContext *,GrPaint &&,const GrClip &,const SkMatrix & viewMatrix,const GrShape &) const334 bool SkMaskFilterBase::directFilterMaskGPU(GrContext*,
335 GrRenderTargetContext*,
336 GrPaint&&,
337 const GrClip&,
338 const SkMatrix& viewMatrix,
339 const GrShape&) const {
340 return false;
341 }
342
filterMaskGPU(GrContext *,sk_sp<GrTextureProxy> srcProxy,const SkMatrix & ctm,const SkIRect & maskRect) const343 sk_sp<GrTextureProxy> SkMaskFilterBase::filterMaskGPU(GrContext*,
344 sk_sp<GrTextureProxy> srcProxy,
345 const SkMatrix& ctm,
346 const SkIRect& maskRect) const {
347 return nullptr;
348 }
349 #endif
350
computeFastBounds(const SkRect & src,SkRect * dst) const351 void SkMaskFilterBase::computeFastBounds(const SkRect& src, SkRect* dst) const {
352 SkMask srcM, dstM;
353
354 srcM.fBounds = src.roundOut();
355 srcM.fRowBytes = 0;
356 srcM.fFormat = SkMask::kA8_Format;
357
358 SkIPoint margin; // ignored
359 if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
360 dst->set(dstM.fBounds);
361 } else {
362 dst->set(srcM.fBounds);
363 }
364 }
365
366 ///////////////////////////////////////////////////////////////////////////////////////////////////
367
join(const T & a,const T & b)368 template <typename T> static inline T join(const T& a, const T& b) {
369 T r = a;
370 r.join(b);
371 return r;
372 }
sect(const T & a,const T & b)373 template <typename T> static inline T sect(const T& a, const T& b) {
374 T r = a;
375 return r.intersect(b) ? r : T::MakeEmpty();
376 }
377
378 class SkComposeMF : public SkMaskFilterBase {
379 public:
SkComposeMF(sk_sp<SkMaskFilter> outer,sk_sp<SkMaskFilter> inner)380 SkComposeMF(sk_sp<SkMaskFilter> outer, sk_sp<SkMaskFilter> inner)
381 : fOuter(std::move(outer))
382 , fInner(std::move(inner))
383 {
384 SkASSERT(as_MFB(fOuter)->getFormat() == SkMask::kA8_Format);
385 SkASSERT(as_MFB(fInner)->getFormat() == SkMask::kA8_Format);
386 }
387
388 bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint*) const override;
389
computeFastBounds(const SkRect & src,SkRect * dst) const390 void computeFastBounds(const SkRect& src, SkRect* dst) const override {
391 SkRect tmp;
392 as_MFB(fInner)->computeFastBounds(src, &tmp);
393 as_MFB(fOuter)->computeFastBounds(tmp, dst);
394 }
395
getFormat() const396 SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
397
398 protected:
399 #if SK_SUPPORT_GPU
onAsFragmentProcessor(const GrFPArgs & args) const400 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
401 std::unique_ptr<GrFragmentProcessor> array[2] = {
402 as_MFB(fInner)->asFragmentProcessor(args),
403 as_MFB(fOuter)->asFragmentProcessor(args),
404 };
405 if (!array[0] || !array[1]) {
406 return nullptr;
407 }
408 return GrFragmentProcessor::RunInSeries(array, 2);
409 }
410
onHasFragmentProcessor() const411 bool onHasFragmentProcessor() const override {
412 return as_MFB(fInner)->hasFragmentProcessor() && as_MFB(fOuter)->hasFragmentProcessor();
413 }
414 #endif
415
416 private:
417 SK_FLATTENABLE_HOOKS(SkComposeMF)
418
419 sk_sp<SkMaskFilter> fOuter;
420 sk_sp<SkMaskFilter> fInner;
421
422 void flatten(SkWriteBuffer&) const override;
423
424 friend class SkMaskFilter;
425
426 typedef SkMaskFilterBase INHERITED;
427 };
428
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & ctm,SkIPoint * margin) const429 bool SkComposeMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
430 SkIPoint* margin) const {
431 SkIPoint innerMargin;
432 SkMask innerMask;
433
434 if (!as_MFB(fInner)->filterMask(&innerMask, src, ctm, &innerMargin)) {
435 return false;
436 }
437 if (!as_MFB(fOuter)->filterMask(dst, innerMask, ctm, margin)) {
438 return false;
439 }
440 if (margin) {
441 margin->fX += innerMargin.fX;
442 margin->fY += innerMargin.fY;
443 }
444 sk_free(innerMask.fImage);
445 return true;
446 }
447
flatten(SkWriteBuffer & buffer) const448 void SkComposeMF::flatten(SkWriteBuffer & buffer) const {
449 buffer.writeFlattenable(fOuter.get());
450 buffer.writeFlattenable(fInner.get());
451 }
452
CreateProc(SkReadBuffer & buffer)453 sk_sp<SkFlattenable> SkComposeMF::CreateProc(SkReadBuffer& buffer) {
454 auto outer = buffer.readMaskFilter();
455 auto inner = buffer.readMaskFilter();
456 if (!buffer.validate(outer && inner)) {
457 return nullptr;
458 }
459 return SkMaskFilter::MakeCompose(std::move(outer), std::move(inner));
460 }
461
462 ///////////////////////////////////////////////////////////////////////////////////////////////////
463
464 class SkCombineMF : public SkMaskFilterBase {
465 public:
SkCombineMF(sk_sp<SkMaskFilter> dst,sk_sp<SkMaskFilter> src,SkCoverageMode mode)466 SkCombineMF(sk_sp<SkMaskFilter> dst, sk_sp<SkMaskFilter> src, SkCoverageMode mode)
467 : fDst(std::move(dst))
468 , fSrc(std::move(src))
469 , fMode(mode)
470 {
471 SkASSERT(as_MFB(fSrc)->getFormat() == SkMask::kA8_Format);
472 SkASSERT(as_MFB(fDst)->getFormat() == SkMask::kA8_Format);
473 }
474
475 bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint*) const override;
476
computeFastBounds(const SkRect & src,SkRect * dst) const477 void computeFastBounds(const SkRect& src, SkRect* dst) const override {
478 SkRect srcR, dstR;
479 as_MFB(fSrc)->computeFastBounds(src, &srcR);
480 as_MFB(fDst)->computeFastBounds(src, &dstR);
481 *dst = join(srcR, dstR);
482 }
483
getFormat() const484 SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
485
486 SK_FLATTENABLE_HOOKS(SkCombineMF)
487
488 protected:
489 #if SK_SUPPORT_GPU
onAsFragmentProcessor(const GrFPArgs & args) const490 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
491 auto src = as_MFB(fSrc)->asFragmentProcessor(args);
492 auto dst = as_MFB(fDst)->asFragmentProcessor(args);
493 if (!src || !dst) {
494 return nullptr;
495 }
496 return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(src), std::move(dst),
497 SkUncorrelatedCoverageModeToBlendMode(fMode));
498 }
499
onHasFragmentProcessor() const500 bool onHasFragmentProcessor() const override {
501 return as_MFB(fSrc)->hasFragmentProcessor() && as_MFB(fDst)->hasFragmentProcessor();
502 }
503 #endif
504
505 private:
506 sk_sp<SkMaskFilter> fDst;
507 sk_sp<SkMaskFilter> fSrc;
508 SkCoverageMode fMode;
509
510 void flatten(SkWriteBuffer&) const override;
511
512 friend class SkMaskFilter;
513
514 typedef SkMaskFilterBase INHERITED;
515 };
516
517 #include "SkSafeMath.h"
518
519 class DrawIntoMask : public SkDraw {
520 public:
521 // we ignore the offset of the mask->fBounds
DrawIntoMask(SkMask * mask)522 DrawIntoMask(SkMask* mask) {
523 int w = mask->fBounds.width();
524 int h = mask->fBounds.height();
525 size_t size = SkSafeMath::Mul(w, h);
526 mask->fFormat = SkMask::kA8_Format;
527 mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
528 mask->fRowBytes = w;
529
530 SkAssertResult(fDst.reset(*mask));
531
532 fMatrixStorage.reset();
533 fMatrix = &fMatrixStorage;
534
535 fRCStorage.setRect({ 0, 0, w, h });
536 fRC = &fRCStorage;
537 }
538
drawAsBitmap(const SkMask & m,const SkPaint & p)539 void drawAsBitmap(const SkMask& m, const SkPaint& p) {
540 SkBitmap b;
541 b.installMaskPixels(m);
542 this->drawSprite(b, m.fBounds.fLeft, m.fBounds.fTop, p);
543 }
544
545 private:
546 SkMatrix fMatrixStorage;
547 SkRasterClip fRCStorage;
548 };
549
join(const SkIRect & src,const SkIRect & dst,SkCoverageMode mode)550 static SkIRect join(const SkIRect& src, const SkIRect& dst, SkCoverageMode mode) {
551 switch (mode) {
552 case SkCoverageMode::kUnion: return join(src, dst);
553 case SkCoverageMode::kIntersect: return sect(src, dst);
554 case SkCoverageMode::kDifference: return src;
555 case SkCoverageMode::kReverseDifference: return dst;
556 case SkCoverageMode::kXor: return join(src, dst);
557 }
558 // not reached
559 return { 0, 0, 0, 0 };
560 }
561
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & ctm,SkIPoint * margin) const562 bool SkCombineMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
563 SkIPoint* margin) const {
564 SkIPoint srcP, dstP;
565 SkMask srcM, dstM;
566
567 if (!as_MFB(fSrc)->filterMask(&srcM, src, ctm, &srcP)) {
568 return false;
569 }
570 if (!as_MFB(fDst)->filterMask(&dstM, src, ctm, &dstP)) {
571 return false;
572 }
573
574 dst->fBounds = join(srcM.fBounds, dstM.fBounds, fMode);
575 dst->fFormat = SkMask::kA8_Format;
576 if (src.fImage == nullptr) {
577 dst->fImage = nullptr;
578 return true;
579 }
580
581 DrawIntoMask md(dst);
582 SkPaint p;
583
584 p.setBlendMode(SkBlendMode::kSrc);
585 dstM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop);
586 md.drawAsBitmap(dstM, p);
587 p.setBlendMode(SkUncorrelatedCoverageModeToBlendMode(fMode));
588 srcM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop);
589 md.drawAsBitmap(srcM, p);
590
591 sk_free(srcM.fImage);
592 sk_free(dstM.fImage);
593 return true;
594 }
595
flatten(SkWriteBuffer & buffer) const596 void SkCombineMF::flatten(SkWriteBuffer & buffer) const {
597 buffer.writeFlattenable(fDst.get());
598 buffer.writeFlattenable(fSrc.get());
599 buffer.write32(static_cast<uint32_t>(fMode));
600 }
601
CreateProc(SkReadBuffer & buffer)602 sk_sp<SkFlattenable> SkCombineMF::CreateProc(SkReadBuffer& buffer) {
603 auto dst = buffer.readMaskFilter();
604 auto src = buffer.readMaskFilter();
605 SkCoverageMode mode = buffer.read32LE(SkCoverageMode::kLast);
606 if (!buffer.validate(dst && src)) {
607 return nullptr;
608 }
609 return SkMaskFilter::MakeCombine(std::move(dst), std::move(src), mode);
610 }
611
612 ///////////////////////////////////////////////////////////////////////////////////////////////////
613
614 class SkMatrixMF : public SkMaskFilterBase {
615 public:
SkMatrixMF(sk_sp<SkMaskFilter> filter,const SkMatrix & lm)616 SkMatrixMF(sk_sp<SkMaskFilter> filter, const SkMatrix& lm)
617 : fFilter(std::move(filter))
618 , fLM(lm)
619 {}
620
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & ctm,SkIPoint * margin) const621 bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
622 SkIPoint* margin) const override {
623 return as_MFB(fFilter)->filterMask(dst, src, SkMatrix::Concat(ctm, fLM), margin);
624 }
625
computeFastBounds(const SkRect & src,SkRect * dst) const626 void computeFastBounds(const SkRect& src, SkRect* dst) const override {
627 *dst = src;
628 SkRect tmp;
629 fLM.mapRect(&tmp, src);
630 as_MFB(fFilter)->computeFastBounds(tmp, dst);
631 }
632
getFormat() const633 SkMask::Format getFormat() const override { return as_MFB(fFilter)->getFormat(); }
634
635 SK_FLATTENABLE_HOOKS(SkMatrixMF)
636
637 protected:
638 #if SK_SUPPORT_GPU
onAsFragmentProcessor(const GrFPArgs & args) const639 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
640 return as_MFB(fFilter)->asFragmentProcessor(GrFPArgs::WithPostLocalMatrix(args, fLM));
641 }
642
onHasFragmentProcessor() const643 bool onHasFragmentProcessor() const override {
644 return as_MFB(fFilter)->hasFragmentProcessor();
645 }
646 #endif
647
648 private:
649 sk_sp<SkMaskFilter> fFilter;
650 const SkMatrix fLM;
651
flatten(SkWriteBuffer & buffer) const652 void flatten(SkWriteBuffer& buffer) const override {
653 buffer.writeMatrix(fLM);
654 buffer.writeFlattenable(fFilter.get());
655 }
656
657 friend class SkMaskFilter;
658 typedef SkMaskFilterBase INHERITED;
659 };
660
CreateProc(SkReadBuffer & buffer)661 sk_sp<SkFlattenable> SkMatrixMF::CreateProc(SkReadBuffer& buffer) {
662 SkMatrix m;
663 buffer.readMatrix(&m);
664 auto filter = buffer.readMaskFilter();
665 return filter ? filter->makeWithMatrix(m) : nullptr;
666 }
667
668 ///////////////////////////////////////////////////////////////////////////////////////////////////
669
MakeCompose(sk_sp<SkMaskFilter> outer,sk_sp<SkMaskFilter> inner)670 sk_sp<SkMaskFilter> SkMaskFilter::MakeCompose(sk_sp<SkMaskFilter> outer,
671 sk_sp<SkMaskFilter> inner) {
672 if (!outer) {
673 return inner;
674 }
675 if (!inner) {
676 return outer;
677 }
678 if (as_MFB(inner)->getFormat() != SkMask::kA8_Format ||
679 as_MFB(outer)->getFormat() != SkMask::kA8_Format) {
680 return nullptr;
681 }
682 return sk_sp<SkMaskFilter>(new SkComposeMF(std::move(outer), std::move(inner)));
683 }
684
MakeCombine(sk_sp<SkMaskFilter> dst,sk_sp<SkMaskFilter> src,SkCoverageMode mode)685 sk_sp<SkMaskFilter> SkMaskFilter::MakeCombine(sk_sp<SkMaskFilter> dst, sk_sp<SkMaskFilter> src,
686 SkCoverageMode mode) {
687 if (!dst) {
688 return src;
689 }
690 if (!src) {
691 return dst;
692 }
693
694 if (as_MFB(dst)->getFormat() != SkMask::kA8_Format ||
695 as_MFB(src)->getFormat() != SkMask::kA8_Format) {
696 return nullptr;
697 }
698 return sk_sp<SkMaskFilter>(new SkCombineMF(std::move(dst), std::move(src), mode));
699 }
700
makeWithMatrix(const SkMatrix & lm) const701 sk_sp<SkMaskFilter> SkMaskFilter::makeWithMatrix(const SkMatrix& lm) const {
702 sk_sp<SkMaskFilter> me = sk_ref_sp(const_cast<SkMaskFilter*>(this));
703 if (lm.isIdentity()) {
704 return me;
705 }
706 return sk_sp<SkMaskFilter>(new SkMatrixMF(std::move(me), lm));
707 }
708
RegisterFlattenables()709 void SkMaskFilter::RegisterFlattenables() {
710 SK_REGISTER_FLATTENABLE(SkMatrixMF);
711 SK_REGISTER_FLATTENABLE(SkComposeMF);
712 SK_REGISTER_FLATTENABLE(SkCombineMF);
713 sk_register_blur_maskfilter_createproc();
714 #if SK_SUPPORT_GPU
715 gr_register_sdf_maskfilter_createproc();
716 #endif
717 }
718