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