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 
9 #include "SkMaskFilter.h"
10 #include "SkBlitter.h"
11 #include "SkDraw.h"
12 #include "SkCachedData.h"
13 #include "SkPath.h"
14 #include "SkRasterClip.h"
15 #include "SkRRect.h"
16 #include "SkTypes.h"
17 
18 #if SK_SUPPORT_GPU
19 #include "GrTexture.h"
20 #include "SkGr.h"
21 #endif
22 
~NinePatch()23 SkMaskFilter::NinePatch::~NinePatch() {
24     if (fCache) {
25         SkASSERT((const void*)fMask.fImage == fCache->data());
26         fCache->unref();
27     } else {
28         SkMask::FreeImage(fMask.fImage);
29     }
30 }
31 
filterMask(SkMask *,const SkMask &,const SkMatrix &,SkIPoint *) const32 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
33                               SkIPoint*) const {
34     return false;
35 }
36 
asABlur(BlurRec *) const37 bool SkMaskFilter::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.set(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.set(innerR.left(), outerR.top(), innerR.right(), innerR.top());
144     if (r.intersect(clipR)) {
145         int startY = SkMax32(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.set(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.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
170     if (r.intersect(clipR)) {
171         int startX = r.left() - outerR.left();
172         int stopX = startX + r.width();
173         int height = r.height();
174         for (int x = startX; x < stopX; ++x) {
175             blitter->blitV(outerR.left() + x, r.top(), height,
176                            *mask.getAddr8(mask.fBounds.left() + x, mask.fBounds.top() + cy));
177         }
178     }
179     // right
180     r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
181     if (r.intersect(clipR)) {
182         int startX = outerR.right() - r.right();
183         int stopX = startX + r.width();
184         int height = r.height();
185         for (int x = startX; x < stopX; ++x) {
186             blitter->blitV(outerR.right() - x - 1, r.top(), height,
187                            *mask.getAddr8(mask.fBounds.right() - x - 1, mask.fBounds.top() + cy));
188         }
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 (path.isNestedFillRects(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 SkMaskFilter::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 SkMaskFilter::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 through
257                 break;
258         }
259     }
260 
261     SkMask  srcM, dstM;
262 
263     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
264                             SkMask::kComputeBoundsAndRenderImage_CreateMode,
265                             style)) {
266         return false;
267     }
268     SkAutoMaskFreeImage autoSrc(srcM.fImage);
269 
270     if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
271         return false;
272     }
273     SkAutoMaskFreeImage autoDst(dstM.fImage);
274 
275     // if we get here, we need to (possibly) resolve the clip and blitter
276     SkAAClipBlitterWrapper wrapper(clip, blitter);
277     blitter = wrapper.getBlitter();
278 
279     SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
280 
281     if (!clipper.done()) {
282         const SkIRect& cr = clipper.rect();
283         do {
284             blitter->blitMask(dstM, cr);
285             clipper.next();
286         } while (!clipper.done());
287     }
288 
289     return true;
290 }
291 
292 SkMaskFilter::FilterReturn
filterRRectToNine(const SkRRect &,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const293 SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&,
294                                 const SkIRect& clipBounds, NinePatch*) const {
295     return kUnimplemented_FilterReturn;
296 }
297 
298 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect[],int count,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const299 SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
300                                 const SkIRect& clipBounds, NinePatch*) const {
301     return kUnimplemented_FilterReturn;
302 }
303 
304 #if SK_SUPPORT_GPU
asFragmentProcessor(GrFragmentProcessor **,GrTexture *,const SkMatrix &) const305 bool SkMaskFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&) const {
306     return false;
307 }
308 
canFilterMaskGPU(const SkRRect & devRRect,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const309 bool SkMaskFilter::canFilterMaskGPU(const SkRRect& devRRect,
310                                     const SkIRect& clipBounds,
311                                     const SkMatrix& ctm,
312                                     SkRect* maskRect) const {
313     return false;
314 }
315 
directFilterMaskGPU(GrTextureProvider * texProvider,GrDrawContext * drawContext,GrPaint * grp,const GrClip &,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkPath & path) const316  bool SkMaskFilter::directFilterMaskGPU(GrTextureProvider* texProvider,
317                                         GrDrawContext* drawContext,
318                                         GrPaint* grp,
319                                         const GrClip&,
320                                         const SkMatrix& viewMatrix,
321                                         const SkStrokeRec& strokeRec,
322                                         const SkPath& path) const {
323     return false;
324 }
325 
326 
directFilterRRectMaskGPU(GrContext *,GrDrawContext * drawContext,GrPaint * grp,const GrClip &,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkRRect & rrect,const SkRRect & devRRect) const327 bool SkMaskFilter::directFilterRRectMaskGPU(GrContext*,
328                                             GrDrawContext* drawContext,
329                                             GrPaint* grp,
330                                             const GrClip&,
331                                             const SkMatrix& viewMatrix,
332                                             const SkStrokeRec& strokeRec,
333                                             const SkRRect& rrect,
334                                             const SkRRect& devRRect) const {
335     return false;
336 }
337 
filterMaskGPU(GrTexture * src,const SkMatrix & ctm,const SkIRect & maskRect,GrTexture ** result) const338 bool SkMaskFilter::filterMaskGPU(GrTexture* src,
339                                  const SkMatrix& ctm,
340                                  const SkIRect& maskRect,
341                                  GrTexture** result) const {
342     return false;
343 }
344 #endif
345 
computeFastBounds(const SkRect & src,SkRect * dst) const346 void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
347     SkMask  srcM, dstM;
348 
349     srcM.fBounds = src.roundOut();
350     srcM.fRowBytes = 0;
351     srcM.fFormat = SkMask::kA8_Format;
352 
353     SkIPoint margin;    // ignored
354     if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
355         dst->set(dstM.fBounds);
356     } else {
357         dst->set(srcM.fBounds);
358     }
359 }
360