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