SkMaskFilter.cpp revision d729b3e504ae547ee0978e8f7156bd8dd8124172
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 "SkBounder.h"
13#include "SkDraw.h"
14#include "SkRasterClip.h"
15
16#ifdef SK_IGNORE_FAST_BLURRECT
17#if (SK_IGNORE_FAST_BLURRECT != 0 && SK_IGNORE_FAST_BLURRECT != 1)
18    #error "SK_IGNORE_FAST_BLURRECT must be 0 or 1 or undefined"
19#endif
20#else
21    #define SK_IGNORE_FAST_BLURRECT   0
22#endif
23
24SK_DEFINE_INST_COUNT(SkMaskFilter)
25
26bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
27                              SkIPoint*) {
28    return false;
29}
30
31static void extractMaskSubset(const SkMask& src, SkMask* dst) {
32    SkASSERT(src.fBounds.contains(dst->fBounds));
33
34    const int dx = dst->fBounds.left() - src.fBounds.left();
35    const int dy = dst->fBounds.top() - src.fBounds.top();
36    dst->fImage = src.fImage + dy * src.fRowBytes + dx;
37    dst->fRowBytes = src.fRowBytes;
38    dst->fFormat = src.fFormat;
39}
40
41static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
42                            const SkIRect& bounds, const SkIRect& clipR) {
43    SkIRect r;
44    if (r.intersect(bounds, clipR)) {
45        blitter->blitMask(mask, r);
46    }
47}
48
49static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
50    SkIRect r;
51    if (r.intersect(rect, clipR)) {
52        blitter->blitRect(r.left(), r.top(), r.width(), r.height());
53    }
54}
55
56#if 0
57static void dump(const SkMask& mask) {
58    for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) {
59        for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) {
60            SkDebugf("%02X", *mask.getAddr8(x, y));
61        }
62        SkDebugf("\n");
63    }
64    SkDebugf("\n");
65}
66#endif
67
68static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
69                              const SkIRect& clipR, SkBlitter* blitter) {
70    int cx = mask.fBounds.left() + mask.fBounds.right() >> 1;
71    int cy = mask.fBounds.top() + mask.fBounds.bottom() >> 1;
72    SkMask m;
73
74    // top-left
75    m.fBounds = mask.fBounds;
76    m.fBounds.fRight = cx;
77    m.fBounds.fBottom = cy;
78    extractMaskSubset(mask, &m);
79    m.fBounds.offsetTo(outerR.left(), outerR.top());
80    blitClippedMask(blitter, m, m.fBounds, clipR);
81
82    // top-right
83    m.fBounds = mask.fBounds;
84    m.fBounds.fLeft = cx + 1;
85    m.fBounds.fBottom = cy;
86    extractMaskSubset(mask, &m);
87    m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top());
88    blitClippedMask(blitter, m, m.fBounds, clipR);
89
90    // bottom-left
91    m.fBounds = mask.fBounds;
92    m.fBounds.fRight = cx;
93    m.fBounds.fTop = cy + 1;
94    extractMaskSubset(mask, &m);
95    m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height());
96    blitClippedMask(blitter, m, m.fBounds, clipR);
97
98    // bottom-right
99    m.fBounds = mask.fBounds;
100    m.fBounds.fLeft = cx + 1;
101    m.fBounds.fTop = cy + 1;
102    extractMaskSubset(mask, &m);
103    m.fBounds.offsetTo(outerR.right() - m.fBounds.width(),
104                       outerR.bottom() - m.fBounds.height());
105    blitClippedMask(blitter, m, m.fBounds, clipR);
106
107    SkIRect innerR;
108    innerR.set(outerR.left() + cx - mask.fBounds.left(),
109               outerR.top() + cy - mask.fBounds.top(),
110               outerR.right() + (cx + 1 - mask.fBounds.right()),
111               outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
112    blitClippedRect(blitter, innerR, clipR);
113
114    const int innerW = innerR.width();
115    size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
116    SkAutoSMalloc<4*1024> storage(storageSize);
117    int16_t* runs = (int16_t*)storage.get();
118    uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
119
120    SkIRect r;
121    // top
122    r.set(innerR.left(), outerR.top(), innerR.right(), innerR.top());
123    if (r.intersect(clipR)) {
124        int startY = SkMax32(0, r.top() - outerR.top());
125        int stopY = startY + r.height();
126        int width = r.width();
127        for (int y = startY; y < stopY; ++y) {
128            runs[0] = width;
129            runs[width] = 0;
130            alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
131            blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
132        }
133    }
134    // bottom
135    r.set(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
136    if (r.intersect(clipR)) {
137        int startY = outerR.bottom() - r.bottom();
138        int stopY = startY + r.height();
139        int width = r.width();
140        for (int y = startY; y < stopY; ++y) {
141            runs[0] = width;
142            runs[width] = 0;
143            alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
144            blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
145        }
146    }
147    // left
148    r.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
149    if (r.intersect(clipR)) {
150        int startX = r.left() - outerR.left();
151        int stopX = startX + r.width();
152        int height = r.height();
153        for (int x = startX; x < stopX; ++x) {
154            blitter->blitV(outerR.left() + x, r.top(), height,
155                           *mask.getAddr8(mask.fBounds.left() + x, mask.fBounds.top() + cy));
156        }
157    }
158    // right
159    r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
160    if (r.intersect(clipR)) {
161        int startX = outerR.right() - r.right();
162        int stopX = startX + r.width();
163        int height = r.height();
164        for (int x = startX; x < stopX; ++x) {
165            blitter->blitV(outerR.right() - x - 1, r.top(), height,
166                           *mask.getAddr8(mask.fBounds.right() - x - 1, mask.fBounds.top() + cy));
167        }
168    }
169}
170
171static void draw_nine(const SkMask& mask, const SkIRect& outerR,
172                      const SkRasterClip& clip, SkBounder* bounder,
173                      SkBlitter* blitter) {
174    // if we get here, we need to (possibly) resolve the clip and blitter
175    SkAAClipBlitterWrapper wrapper(clip, blitter);
176    blitter = wrapper.getBlitter();
177
178    SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
179
180    if (!clipper.done() && (!bounder || bounder->doIRect(outerR))) {
181        const SkIRect& cr = clipper.rect();
182        do {
183            draw_nine_clipped(mask, outerR, cr, blitter);
184            clipper.next();
185        } while (!clipper.done());
186    }
187}
188
189bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
190                              const SkRasterClip& clip, SkBounder* bounder,
191                              SkBlitter* blitter, SkPaint::Style style) {
192    SkRect rect;
193    if (!SK_IGNORE_FAST_BLURRECT &&
194                devPath.isRect(&rect) && SkPaint::kFill_Style == style) {
195        SkMask  mask;
196        SkIRect outerBounds;
197
198        mask.fImage = NULL;
199        switch (this->filterRectToNine(rect, matrix, clip.getBounds(), &mask,
200                                       &outerBounds)) {
201            case kFalse_FilterReturn:
202                SkASSERT(!mask.fImage);
203                return false;
204            case kTrue_FilterReturn:
205                draw_nine(mask, outerBounds, clip, bounder, blitter);
206                SkMask::FreeImage(mask.fImage);
207                return true;
208            case kUnimplemented_FilterReturn:
209                SkASSERT(!mask.fImage);
210                // fall through
211                break;
212        }
213    }
214
215    SkMask  srcM, dstM;
216
217    if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
218                            SkMask::kComputeBoundsAndRenderImage_CreateMode,
219                            style)) {
220        return false;
221    }
222    SkAutoMaskFreeImage autoSrc(srcM.fImage);
223
224    if (!this->filterMask(&dstM, srcM, matrix, NULL)) {
225        return false;
226    }
227    SkAutoMaskFreeImage autoDst(dstM.fImage);
228
229    // if we get here, we need to (possibly) resolve the clip and blitter
230    SkAAClipBlitterWrapper wrapper(clip, blitter);
231    blitter = wrapper.getBlitter();
232
233    SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
234
235    if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) {
236        const SkIRect& cr = clipper.rect();
237        do {
238            blitter->blitMask(dstM, cr);
239            clipper.next();
240        } while (!clipper.done());
241    }
242
243    return true;
244}
245
246SkMaskFilter::FilterReturn
247SkMaskFilter::filterRectToNine(const SkRect&, const SkMatrix&,
248                               const SkIRect& clipBounds,
249                               SkMask* ninePatchMask,
250                               SkIRect* outerRect) {
251    return kUnimplemented_FilterReturn;
252}
253
254SkMaskFilter::BlurType SkMaskFilter::asABlur(BlurInfo*) const {
255    return kNone_BlurType;
256}
257
258void SkMaskFilter::setAsABlur(const BlurInfo& ) {
259}
260
261void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) {
262    SkMask  srcM, dstM;
263
264    srcM.fImage = NULL;
265    src.roundOut(&srcM.fBounds);
266    srcM.fRowBytes = 0;
267    srcM.fFormat = SkMask::kA8_Format;
268
269    SkIPoint margin;    // ignored
270    if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
271        dst->set(dstM.fBounds);
272    } else {
273        dst->set(srcM.fBounds);
274    }
275}
276
277
278