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