1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkMaskFilter.h"
11#include "SkBlitter.h"
12#include "SkDraw.h"
13#include "SkCachedData.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#include "SkGrPixelRef.h"
22#endif
23
24SkMaskFilter::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
33bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
34                              SkIPoint*) const {
35    return false;
36}
37
38bool SkMaskFilter::asABlur(BlurRec*) const {
39    return false;
40}
41
42static 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
52static 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
60static 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
68static 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
79static 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
193static 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
210static 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
217bool SkMaskFilter::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
218                               const SkRasterClip& clip, SkBlitter* blitter,
219                               SkPaint::Style style) const {
220    // Attempt to speed up drawing by creating a nine patch. If a nine patch
221    // cannot be used, return false to allow our caller to recover and perform
222    // the drawing another way.
223    NinePatch patch;
224    patch.fMask.fImage = NULL;
225    if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
226                                                      clip.getBounds(),
227                                                      &patch)) {
228        SkASSERT(NULL == patch.fMask.fImage);
229        return false;
230    }
231    draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
232    return true;
233}
234
235bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
236                              const SkRasterClip& clip, SkBlitter* blitter,
237                              SkPaint::Style style) const {
238    SkRect rects[2];
239    int rectCount = 0;
240    if (SkPaint::kFill_Style == style) {
241        rectCount = countNestedRects(devPath, rects);
242    }
243    if (rectCount > 0) {
244        NinePatch patch;
245
246        switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
247            case kFalse_FilterReturn:
248                SkASSERT(NULL == patch.fMask.fImage);
249                return false;
250
251            case kTrue_FilterReturn:
252                draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
253                          blitter);
254                return true;
255
256            case kUnimplemented_FilterReturn:
257                SkASSERT(NULL == patch.fMask.fImage);
258                // fall through
259                break;
260        }
261    }
262
263    SkMask  srcM, dstM;
264
265    if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
266                            SkMask::kComputeBoundsAndRenderImage_CreateMode,
267                            style)) {
268        return false;
269    }
270    SkAutoMaskFreeImage autoSrc(srcM.fImage);
271
272    if (!this->filterMask(&dstM, srcM, matrix, NULL)) {
273        return false;
274    }
275    SkAutoMaskFreeImage autoDst(dstM.fImage);
276
277    // if we get here, we need to (possibly) resolve the clip and blitter
278    SkAAClipBlitterWrapper wrapper(clip, blitter);
279    blitter = wrapper.getBlitter();
280
281    SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
282
283    if (!clipper.done()) {
284        const SkIRect& cr = clipper.rect();
285        do {
286            blitter->blitMask(dstM, cr);
287            clipper.next();
288        } while (!clipper.done());
289    }
290
291    return true;
292}
293
294SkMaskFilter::FilterReturn
295SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&,
296                                const SkIRect& clipBounds, NinePatch*) const {
297    return kUnimplemented_FilterReturn;
298}
299
300SkMaskFilter::FilterReturn
301SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
302                                const SkIRect& clipBounds, NinePatch*) const {
303    return kUnimplemented_FilterReturn;
304}
305
306#if SK_SUPPORT_GPU
307bool SkMaskFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&) const {
308    return false;
309}
310
311bool SkMaskFilter::canFilterMaskGPU(const SkRect& devBounds,
312                                    const SkIRect& clipBounds,
313                                    const SkMatrix& ctm,
314                                    SkRect* maskRect) const {
315    return false;
316}
317
318 bool SkMaskFilter::directFilterMaskGPU(GrContext* context,
319                                        GrRenderTarget* rt,
320                                        GrPaint* grp,
321                                        const GrClip&,
322                                        const SkMatrix& viewMatrix,
323                                        const SkStrokeRec& strokeRec,
324                                        const SkPath& path) const {
325    return false;
326}
327
328
329bool SkMaskFilter::directFilterRRectMaskGPU(GrContext* context,
330                                            GrRenderTarget* rt,
331                                            GrPaint* grp,
332                                            const GrClip&,
333                                            const SkMatrix& viewMatrix,
334                                            const SkStrokeRec& strokeRec,
335                                            const SkRRect& rrect) const {
336    return false;
337}
338
339bool SkMaskFilter::filterMaskGPU(GrTexture* src,
340                                 const SkMatrix& ctm,
341                                 const SkRect& maskRect,
342                                 GrTexture** result,
343                                 bool canOverwriteSrc) const {
344    return false;
345}
346#endif
347
348void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
349    SkMask  srcM, dstM;
350
351    srcM.fImage = NULL;
352    srcM.fBounds = src.roundOut();
353    srcM.fRowBytes = 0;
354    srcM.fFormat = SkMask::kA8_Format;
355
356    SkIPoint margin;    // ignored
357    if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
358        dst->set(dstM.fBounds);
359    } else {
360        dst->set(srcM.fBounds);
361    }
362}
363