• 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 "SkMaskFilter.h"
9 
10 #include "SkAutoMalloc.h"
11 #include "SkBlitter.h"
12 #include "SkCachedData.h"
13 #include "SkDraw.h"
14 #include "SkPath.h"
15 #include "SkRRect.h"
16 #include "SkRasterClip.h"
17 
18 #if SK_SUPPORT_GPU
19 #include "GrTexture.h"
20 #include "GrTextureProxy.h"
21 #include "SkGr.h"
22 #endif
23 
~NinePatch()24 SkMaskFilter::NinePatch::~NinePatch() {
25     if (fCache) {
26         SkASSERT((const void*)fMask.fImage == fCache->data());
27         fCache->unref();
28     } else {
29         SkMask::FreeImage(fMask.fImage);
30     }
31 }
32 
filterMask(SkMask *,const SkMask &,const SkMatrix &,SkIPoint *) const33 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
34                               SkIPoint*) const {
35     return false;
36 }
37 
asABlur(BlurRec *) const38 bool SkMaskFilter::asABlur(BlurRec*) const {
39     return false;
40 }
41 
extractMaskSubset(const SkMask & src,SkMask * dst)42 static void extractMaskSubset(const SkMask& src, SkMask* dst) {
43     SkASSERT(src.fBounds.contains(dst->fBounds));
44 
45     const int dx = dst->fBounds.left() - src.fBounds.left();
46     const int dy = dst->fBounds.top() - src.fBounds.top();
47     dst->fImage = src.fImage + dy * src.fRowBytes + dx;
48     dst->fRowBytes = src.fRowBytes;
49     dst->fFormat = src.fFormat;
50 }
51 
blitClippedMask(SkBlitter * blitter,const SkMask & mask,const SkIRect & bounds,const SkIRect & clipR)52 static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
53                             const SkIRect& bounds, const SkIRect& clipR) {
54     SkIRect r;
55     if (r.intersect(bounds, clipR)) {
56         blitter->blitMask(mask, r);
57     }
58 }
59 
blitClippedRect(SkBlitter * blitter,const SkIRect & rect,const SkIRect & clipR)60 static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
61     SkIRect r;
62     if (r.intersect(rect, clipR)) {
63         blitter->blitRect(r.left(), r.top(), r.width(), r.height());
64     }
65 }
66 
67 #if 0
68 static void dump(const SkMask& mask) {
69     for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) {
70         for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) {
71             SkDebugf("%02X", *mask.getAddr8(x, y));
72         }
73         SkDebugf("\n");
74     }
75     SkDebugf("\n");
76 }
77 #endif
78 
draw_nine_clipped(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkIRect & clipR,SkBlitter * blitter)79 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
80                               const SkIPoint& center, bool fillCenter,
81                               const SkIRect& clipR, SkBlitter* blitter) {
82     int cx = center.x();
83     int cy = center.y();
84     SkMask m;
85 
86     // top-left
87     m.fBounds = mask.fBounds;
88     m.fBounds.fRight = cx;
89     m.fBounds.fBottom = cy;
90     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
91         extractMaskSubset(mask, &m);
92         m.fBounds.offsetTo(outerR.left(), outerR.top());
93         blitClippedMask(blitter, m, m.fBounds, clipR);
94     }
95 
96     // top-right
97     m.fBounds = mask.fBounds;
98     m.fBounds.fLeft = cx + 1;
99     m.fBounds.fBottom = cy;
100     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
101         extractMaskSubset(mask, &m);
102         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top());
103         blitClippedMask(blitter, m, m.fBounds, clipR);
104     }
105 
106     // bottom-left
107     m.fBounds = mask.fBounds;
108     m.fBounds.fRight = cx;
109     m.fBounds.fTop = cy + 1;
110     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
111         extractMaskSubset(mask, &m);
112         m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height());
113         blitClippedMask(blitter, m, m.fBounds, clipR);
114     }
115 
116     // bottom-right
117     m.fBounds = mask.fBounds;
118     m.fBounds.fLeft = cx + 1;
119     m.fBounds.fTop = cy + 1;
120     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
121         extractMaskSubset(mask, &m);
122         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(),
123                            outerR.bottom() - m.fBounds.height());
124         blitClippedMask(blitter, m, m.fBounds, clipR);
125     }
126 
127     SkIRect innerR;
128     innerR.set(outerR.left() + cx - mask.fBounds.left(),
129                outerR.top() + cy - mask.fBounds.top(),
130                outerR.right() + (cx + 1 - mask.fBounds.right()),
131                outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
132     if (fillCenter) {
133         blitClippedRect(blitter, innerR, clipR);
134     }
135 
136     const int innerW = innerR.width();
137     size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
138     SkAutoSMalloc<4*1024> storage(storageSize);
139     int16_t* runs = (int16_t*)storage.get();
140     uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
141 
142     SkIRect r;
143     // top
144     r.set(innerR.left(), outerR.top(), innerR.right(), innerR.top());
145     if (r.intersect(clipR)) {
146         int startY = SkMax32(0, r.top() - outerR.top());
147         int stopY = startY + r.height();
148         int width = r.width();
149         for (int y = startY; y < stopY; ++y) {
150             runs[0] = width;
151             runs[width] = 0;
152             alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
153             blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
154         }
155     }
156     // bottom
157     r.set(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
158     if (r.intersect(clipR)) {
159         int startY = outerR.bottom() - r.bottom();
160         int stopY = startY + r.height();
161         int width = r.width();
162         for (int y = startY; y < stopY; ++y) {
163             runs[0] = width;
164             runs[width] = 0;
165             alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
166             blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
167         }
168     }
169     // left
170     r.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
171     if (r.intersect(clipR)) {
172         int startX = r.left() - outerR.left();
173         int stopX = startX + r.width();
174         int height = r.height();
175         for (int x = startX; x < stopX; ++x) {
176             blitter->blitV(outerR.left() + x, r.top(), height,
177                            *mask.getAddr8(mask.fBounds.left() + x, mask.fBounds.top() + cy));
178         }
179     }
180     // right
181     r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
182     if (r.intersect(clipR)) {
183         int startX = outerR.right() - r.right();
184         int stopX = startX + r.width();
185         int height = r.height();
186         for (int x = startX; x < stopX; ++x) {
187             blitter->blitV(outerR.right() - x - 1, r.top(), height,
188                            *mask.getAddr8(mask.fBounds.right() - x - 1, mask.fBounds.top() + cy));
189         }
190     }
191 }
192 
draw_nine(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkRasterClip & clip,SkBlitter * blitter)193 static void draw_nine(const SkMask& mask, const SkIRect& outerR, const SkIPoint& center,
194                       bool fillCenter, const SkRasterClip& clip, SkBlitter* blitter) {
195     // if we get here, we need to (possibly) resolve the clip and blitter
196     SkAAClipBlitterWrapper wrapper(clip, blitter);
197     blitter = wrapper.getBlitter();
198 
199     SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
200 
201     if (!clipper.done()) {
202         const SkIRect& cr = clipper.rect();
203         do {
204             draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
205             clipper.next();
206         } while (!clipper.done());
207     }
208 }
209 
countNestedRects(const SkPath & path,SkRect rects[2])210 static int countNestedRects(const SkPath& path, SkRect rects[2]) {
211     if (path.isNestedFillRects(rects)) {
212         return 2;
213     }
214     return path.isRect(&rects[0]);
215 }
216 
filterRRect(const SkRRect & devRRect,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter) const217 bool SkMaskFilter::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
218                                const SkRasterClip& clip, SkBlitter* blitter) const {
219     // Attempt to speed up drawing by creating a nine patch. If a nine patch
220     // cannot be used, return false to allow our caller to recover and perform
221     // the drawing another way.
222     NinePatch patch;
223     patch.fMask.fImage = nullptr;
224     if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
225                                                       clip.getBounds(),
226                                                       &patch)) {
227         SkASSERT(nullptr == patch.fMask.fImage);
228         return false;
229     }
230     draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
231     return true;
232 }
233 
filterPath(const SkPath & devPath,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter,SkStrokeRec::InitStyle style) const234 bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
235                               const SkRasterClip& clip, SkBlitter* blitter,
236                               SkStrokeRec::InitStyle style) const {
237     SkRect rects[2];
238     int rectCount = 0;
239     if (SkStrokeRec::kFill_InitStyle == style) {
240         rectCount = countNestedRects(devPath, rects);
241     }
242     if (rectCount > 0) {
243         NinePatch patch;
244 
245         switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
246             case kFalse_FilterReturn:
247                 SkASSERT(nullptr == patch.fMask.fImage);
248                 return false;
249 
250             case kTrue_FilterReturn:
251                 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
252                           blitter);
253                 return true;
254 
255             case kUnimplemented_FilterReturn:
256                 SkASSERT(nullptr == patch.fMask.fImage);
257                 // fall through
258                 break;
259         }
260     }
261 
262     SkMask  srcM, dstM;
263 
264     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
265                             SkMask::kComputeBoundsAndRenderImage_CreateMode,
266                             style)) {
267         return false;
268     }
269     SkAutoMaskFreeImage autoSrc(srcM.fImage);
270 
271     if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
272         return false;
273     }
274     SkAutoMaskFreeImage autoDst(dstM.fImage);
275 
276     // if we get here, we need to (possibly) resolve the clip and blitter
277     SkAAClipBlitterWrapper wrapper(clip, blitter);
278     blitter = wrapper.getBlitter();
279 
280     SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
281 
282     if (!clipper.done()) {
283         const SkIRect& cr = clipper.rect();
284         do {
285             blitter->blitMask(dstM, cr);
286             clipper.next();
287         } while (!clipper.done());
288     }
289 
290     return true;
291 }
292 
293 SkMaskFilter::FilterReturn
filterRRectToNine(const SkRRect &,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const294 SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&,
295                                 const SkIRect& clipBounds, NinePatch*) const {
296     return kUnimplemented_FilterReturn;
297 }
298 
299 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect[],int count,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const300 SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
301                                 const SkIRect& clipBounds, NinePatch*) const {
302     return kUnimplemented_FilterReturn;
303 }
304 
305 #if SK_SUPPORT_GPU
asFragmentProcessor(GrFragmentProcessor **,GrTexture *,const SkMatrix &) const306 bool SkMaskFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&) const {
307     return false;
308 }
309 
canFilterMaskGPU(const SkRRect & devRRect,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const310 bool SkMaskFilter::canFilterMaskGPU(const SkRRect& devRRect,
311                                     const SkIRect& clipBounds,
312                                     const SkMatrix& ctm,
313                                     SkRect* maskRect) const {
314     return false;
315 }
316 
directFilterMaskGPU(GrContext *,GrRenderTargetContext * renderTargetContext,GrPaint &&,const GrClip &,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkPath & path) const317 bool SkMaskFilter::directFilterMaskGPU(GrContext*,
318                                        GrRenderTargetContext* renderTargetContext,
319                                        GrPaint&&,
320                                        const GrClip&,
321                                        const SkMatrix& viewMatrix,
322                                        const SkStrokeRec& strokeRec,
323                                        const SkPath& path) const {
324     return false;
325 }
326 
directFilterRRectMaskGPU(GrContext *,GrRenderTargetContext * renderTargetContext,GrPaint &&,const GrClip &,const SkMatrix & viewMatrix,const SkStrokeRec & strokeRec,const SkRRect & rrect,const SkRRect & devRRect) const327 bool SkMaskFilter::directFilterRRectMaskGPU(GrContext*,
328                                             GrRenderTargetContext* renderTargetContext,
329                                             GrPaint&&,
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(GrContext *,sk_sp<GrTextureProxy> srcProxy,const SkMatrix & ctm,const SkIRect & maskRect) const338 sk_sp<GrTextureProxy> SkMaskFilter::filterMaskGPU(GrContext*,
339                                                   sk_sp<GrTextureProxy> srcProxy,
340                                                   const SkMatrix& ctm,
341                                                   const SkIRect& maskRect) const {
342     return nullptr;
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