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