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