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