• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/SkMaskFilterBase.h"
9 
10 #include "include/core/SkPath.h"
11 #include "include/core/SkRRect.h"
12 #include "src/core/SkAutoMalloc.h"
13 #include "src/core/SkBlitter.h"
14 #include "src/core/SkCachedData.h"
15 #include "src/core/SkDraw.h"
16 #include "src/core/SkPathPriv.h"
17 #include "src/core/SkRasterClip.h"
18 #include "src/core/SkReadBuffer.h"
19 #include "src/core/SkWriteBuffer.h"
20 
21 #if SK_SUPPORT_GPU
22 #include "src/gpu/GrFragmentProcessor.h"
23 #include "src/gpu/GrSurfaceProxyView.h"
24 #include "src/gpu/GrTextureProxy.h"
25 #include "src/gpu/text/GrSDFMaskFilter.h"
26 #endif
27 
~NinePatch()28 SkMaskFilterBase::NinePatch::~NinePatch() {
29     if (fCache) {
30         SkASSERT((const void*)fMask.fImage == fCache->data());
31         fCache->unref();
32     } else {
33         SkMask::FreeImage(fMask.fImage);
34     }
35 }
36 
asABlur(BlurRec *) const37 bool SkMaskFilterBase::asABlur(BlurRec*) const {
38     return false;
39 }
40 
extractMaskSubset(const SkMask & src,SkMask * dst)41 static void extractMaskSubset(const SkMask& src, SkMask* dst) {
42     SkASSERT(src.fBounds.contains(dst->fBounds));
43 
44     const int dx = dst->fBounds.left() - src.fBounds.left();
45     const int dy = dst->fBounds.top() - src.fBounds.top();
46     dst->fImage = src.fImage + dy * src.fRowBytes + dx;
47     dst->fRowBytes = src.fRowBytes;
48     dst->fFormat = src.fFormat;
49 }
50 
blitClippedMask(SkBlitter * blitter,const SkMask & mask,const SkIRect & bounds,const SkIRect & clipR)51 static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
52                             const SkIRect& bounds, const SkIRect& clipR) {
53     SkIRect r;
54     if (r.intersect(bounds, clipR)) {
55         blitter->blitMask(mask, r);
56     }
57 }
58 
blitClippedRect(SkBlitter * blitter,const SkIRect & rect,const SkIRect & clipR)59 static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
60     SkIRect r;
61     if (r.intersect(rect, clipR)) {
62         blitter->blitRect(r.left(), r.top(), r.width(), r.height());
63     }
64 }
65 
66 #if 0
67 static void dump(const SkMask& mask) {
68     for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) {
69         for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) {
70             SkDebugf("%02X", *mask.getAddr8(x, y));
71         }
72         SkDebugf("\n");
73     }
74     SkDebugf("\n");
75 }
76 #endif
77 
draw_nine_clipped(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkIRect & clipR,SkBlitter * blitter)78 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
79                               const SkIPoint& center, bool fillCenter,
80                               const SkIRect& clipR, SkBlitter* blitter) {
81     int cx = center.x();
82     int cy = center.y();
83     SkMask m;
84 
85     // top-left
86     m.fBounds = mask.fBounds;
87     m.fBounds.fRight = cx;
88     m.fBounds.fBottom = cy;
89     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
90         extractMaskSubset(mask, &m);
91         m.fBounds.offsetTo(outerR.left(), outerR.top());
92         blitClippedMask(blitter, m, m.fBounds, clipR);
93     }
94 
95     // top-right
96     m.fBounds = mask.fBounds;
97     m.fBounds.fLeft = cx + 1;
98     m.fBounds.fBottom = cy;
99     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
100         extractMaskSubset(mask, &m);
101         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top());
102         blitClippedMask(blitter, m, m.fBounds, clipR);
103     }
104 
105     // bottom-left
106     m.fBounds = mask.fBounds;
107     m.fBounds.fRight = cx;
108     m.fBounds.fTop = cy + 1;
109     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
110         extractMaskSubset(mask, &m);
111         m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height());
112         blitClippedMask(blitter, m, m.fBounds, clipR);
113     }
114 
115     // bottom-right
116     m.fBounds = mask.fBounds;
117     m.fBounds.fLeft = cx + 1;
118     m.fBounds.fTop = cy + 1;
119     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
120         extractMaskSubset(mask, &m);
121         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(),
122                            outerR.bottom() - m.fBounds.height());
123         blitClippedMask(blitter, m, m.fBounds, clipR);
124     }
125 
126     SkIRect innerR;
127     innerR.setLTRB(outerR.left() + cx - mask.fBounds.left(),
128                    outerR.top() + cy - mask.fBounds.top(),
129                    outerR.right() + (cx + 1 - mask.fBounds.right()),
130                    outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
131     if (fillCenter) {
132         blitClippedRect(blitter, innerR, clipR);
133     }
134 
135     const int innerW = innerR.width();
136     size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
137     SkAutoSMalloc<4*1024> storage(storageSize);
138     int16_t* runs = (int16_t*)storage.get();
139     uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
140 
141     SkIRect r;
142     // top
143     r.setLTRB(innerR.left(), outerR.top(), innerR.right(), innerR.top());
144     if (r.intersect(clipR)) {
145         int startY = std::max(0, r.top() - outerR.top());
146         int stopY = startY + r.height();
147         int width = r.width();
148         for (int y = startY; y < stopY; ++y) {
149             runs[0] = width;
150             runs[width] = 0;
151             alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
152             blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
153         }
154     }
155     // bottom
156     r.setLTRB(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
157     if (r.intersect(clipR)) {
158         int startY = outerR.bottom() - r.bottom();
159         int stopY = startY + r.height();
160         int width = r.width();
161         for (int y = startY; y < stopY; ++y) {
162             runs[0] = width;
163             runs[width] = 0;
164             alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
165             blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
166         }
167     }
168     // left
169     r.setLTRB(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
170     if (r.intersect(clipR)) {
171         SkMask leftMask;
172         leftMask.fImage = mask.getAddr8(mask.fBounds.left() + r.left() - outerR.left(),
173                                         mask.fBounds.top() + cy);
174         leftMask.fBounds = r;
175         leftMask.fRowBytes = 0;    // so we repeat the scanline for our height
176         leftMask.fFormat = SkMask::kA8_Format;
177         blitter->blitMask(leftMask, r);
178     }
179     // right
180     r.setLTRB(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
181     if (r.intersect(clipR)) {
182         SkMask rightMask;
183         rightMask.fImage = mask.getAddr8(mask.fBounds.right() - outerR.right() + r.left(),
184                                          mask.fBounds.top() + cy);
185         rightMask.fBounds = r;
186         rightMask.fRowBytes = 0;    // so we repeat the scanline for our height
187         rightMask.fFormat = SkMask::kA8_Format;
188         blitter->blitMask(rightMask, r);
189     }
190 }
191 
draw_nine(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkRasterClip & clip,SkBlitter * blitter)192 static void draw_nine(const SkMask& mask, const SkIRect& outerR, const SkIPoint& center,
193                       bool fillCenter, const SkRasterClip& clip, SkBlitter* blitter) {
194     // if we get here, we need to (possibly) resolve the clip and blitter
195     SkAAClipBlitterWrapper wrapper(clip, blitter);
196     blitter = wrapper.getBlitter();
197 
198     SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
199 
200     if (!clipper.done()) {
201         const SkIRect& cr = clipper.rect();
202         do {
203             draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
204             clipper.next();
205         } while (!clipper.done());
206     }
207 }
208 
countNestedRects(const SkPath & path,SkRect rects[2])209 static int countNestedRects(const SkPath& path, SkRect rects[2]) {
210     if (SkPathPriv::IsNestedFillRects(path, rects)) {
211         return 2;
212     }
213     return path.isRect(&rects[0]);
214 }
215 
filterRRect(const SkRRect & devRRect,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter) const216 bool SkMaskFilterBase::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
217                                    const SkRasterClip& clip, SkBlitter* blitter) const {
218     // Attempt to speed up drawing by creating a nine patch. If a nine patch
219     // cannot be used, return false to allow our caller to recover and perform
220     // the drawing another way.
221     NinePatch patch;
222     patch.fMask.fImage = nullptr;
223     if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
224                                                       clip.getBounds(),
225                                                       &patch)) {
226         SkASSERT(nullptr == patch.fMask.fImage);
227         return false;
228     }
229     draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
230     return true;
231 }
232 
filterPath(const SkPath & devPath,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter,SkStrokeRec::InitStyle style) const233 bool SkMaskFilterBase::filterPath(const SkPath& devPath, const SkMatrix& matrix,
234                                   const SkRasterClip& clip, SkBlitter* blitter,
235                                   SkStrokeRec::InitStyle style) const {
236     SkRect rects[2];
237     int rectCount = 0;
238     if (SkStrokeRec::kFill_InitStyle == style) {
239         rectCount = countNestedRects(devPath, rects);
240     }
241     if (rectCount > 0) {
242         NinePatch patch;
243 
244         switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
245             case kFalse_FilterReturn:
246                 SkASSERT(nullptr == patch.fMask.fImage);
247                 return false;
248 
249             case kTrue_FilterReturn:
250                 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
251                           blitter);
252                 return true;
253 
254             case kUnimplemented_FilterReturn:
255                 SkASSERT(nullptr == patch.fMask.fImage);
256                 // fall out
257                 break;
258         }
259     }
260 
261     SkMask  srcM, dstM;
262 
263 #if defined(SK_BUILD_FOR_FUZZER)
264     if (devPath.countVerbs() > 1000 || devPath.countPoints() > 1000) {
265         return false;
266     }
267 #endif
268     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
269                             SkMask::kComputeBoundsAndRenderImage_CreateMode,
270                             style)) {
271         return false;
272     }
273     SkAutoMaskFreeImage autoSrc(srcM.fImage);
274 
275     if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
276         return false;
277     }
278     SkAutoMaskFreeImage autoDst(dstM.fImage);
279 
280     // if we get here, we need to (possibly) resolve the clip and blitter
281     SkAAClipBlitterWrapper wrapper(clip, blitter);
282     blitter = wrapper.getBlitter();
283 
284     SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
285 
286     if (!clipper.done()) {
287         const SkIRect& cr = clipper.rect();
288         do {
289             blitter->blitMask(dstM, cr);
290             clipper.next();
291         } while (!clipper.done());
292     }
293 
294     return true;
295 }
296 
297 SkMaskFilterBase::FilterReturn
filterRRectToNine(const SkRRect &,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const298 SkMaskFilterBase::filterRRectToNine(const SkRRect&, const SkMatrix&,
299                                     const SkIRect& clipBounds, NinePatch*) const {
300     return kUnimplemented_FilterReturn;
301 }
302 
303 SkMaskFilterBase::FilterReturn
filterRectsToNine(const SkRect[],int count,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const304 SkMaskFilterBase::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
305                                     const SkIRect& clipBounds, NinePatch*) const {
306     return kUnimplemented_FilterReturn;
307 }
308 
309 #if SK_SUPPORT_GPU
310 std::unique_ptr<GrFragmentProcessor>
asFragmentProcessor(const GrFPArgs & args) const311 SkMaskFilterBase::asFragmentProcessor(const GrFPArgs& args) const {
312     auto fp = this->onAsFragmentProcessor(args);
313     if (fp) {
314         SkASSERT(this->hasFragmentProcessor());
315     } else {
316         SkASSERT(!this->hasFragmentProcessor());
317     }
318     return fp;
319 }
hasFragmentProcessor() const320 bool SkMaskFilterBase::hasFragmentProcessor() const {
321     return this->onHasFragmentProcessor();
322 }
323 
324 std::unique_ptr<GrFragmentProcessor>
onAsFragmentProcessor(const GrFPArgs &) const325 SkMaskFilterBase::onAsFragmentProcessor(const GrFPArgs&) const {
326     return nullptr;
327 }
onHasFragmentProcessor() const328 bool SkMaskFilterBase::onHasFragmentProcessor() const { return false; }
329 
canFilterMaskGPU(const GrStyledShape & shape,const SkIRect & devSpaceShapeBounds,const SkIRect & clipBounds,const SkMatrix & ctm,SkIRect * maskRect) const330 bool SkMaskFilterBase::canFilterMaskGPU(const GrStyledShape& shape,
331                                         const SkIRect& devSpaceShapeBounds,
332                                         const SkIRect& clipBounds,
333                                         const SkMatrix& ctm,
334                                         SkIRect* maskRect) const {
335     return false;
336 }
337 
directFilterMaskGPU(GrRecordingContext *,skgpu::v1::SurfaceDrawContext *,GrPaint &&,const GrClip *,const SkMatrix & viewMatrix,const GrStyledShape &) const338 bool SkMaskFilterBase::directFilterMaskGPU(GrRecordingContext*,
339                                            skgpu::v1::SurfaceDrawContext*,
340                                            GrPaint&&,
341                                            const GrClip*,
342                                            const SkMatrix& viewMatrix,
343                                            const GrStyledShape&) const {
344     return false;
345 }
346 
filterMaskGPU(GrRecordingContext *,GrSurfaceProxyView view,GrColorType srcColorType,SkAlphaType srcAlphaType,const SkMatrix & ctm,const SkIRect & maskRect) const347 GrSurfaceProxyView SkMaskFilterBase::filterMaskGPU(GrRecordingContext*,
348                                                    GrSurfaceProxyView view,
349                                                    GrColorType srcColorType,
350                                                    SkAlphaType srcAlphaType,
351                                                    const SkMatrix& ctm,
352                                                    const SkIRect& maskRect) const {
353     return {};
354 }
355 #endif
356 
computeFastBounds(const SkRect & src,SkRect * dst) const357 void SkMaskFilterBase::computeFastBounds(const SkRect& src, SkRect* dst) const {
358     SkMask  srcM, dstM;
359 
360     srcM.fBounds = src.roundOut();
361     srcM.fRowBytes = 0;
362     srcM.fFormat = SkMask::kA8_Format;
363 
364     SkIPoint margin;    // ignored
365     if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
366         dst->set(dstM.fBounds);
367     } else {
368         dst->set(srcM.fBounds);
369     }
370 }
371 
approximateFilteredBounds(const SkRect & src) const372 SkRect SkMaskFilter::approximateFilteredBounds(const SkRect& src) const {
373     SkRect dst;
374     as_MFB(this)->computeFastBounds(src, &dst);
375     return dst;
376 }
377 
RegisterFlattenables()378 void SkMaskFilter::RegisterFlattenables() {
379     sk_register_blur_maskfilter_createproc();
380 #if SK_SUPPORT_GPU
381     gr_register_sdf_maskfilter_createproc();
382 #endif
383 }
384 
Deserialize(const void * data,size_t size,const SkDeserialProcs * procs)385 sk_sp<SkMaskFilter> SkMaskFilter::Deserialize(const void* data, size_t size,
386                                               const SkDeserialProcs* procs) {
387     return sk_sp<SkMaskFilter>(static_cast<SkMaskFilter*>(
388                                SkFlattenable::Deserialize(
389                                kSkMaskFilter_Type, data, size, procs).release()));
390 }
391