Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkMaskFilter.cpp
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
23 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
24                               SkIPoint*) const {
25     return false;
26 }
27
28 bool SkMaskFilter::asABlur(BlurRec*) const {
29     return false;
30 }
31
32 static 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
42 static 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
50 static 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
58 static 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
69 static 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
183 static 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
200 static 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
207 bool 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
226 bool 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
288 SkMaskFilter::FilterReturn
289 SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&,
290                                 const SkIRect& clipBounds, NinePatch*) const {
291     return kUnimplemented_FilterReturn;
292 }
293
294 SkMaskFilter::FilterReturn
295 SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
296                                 const SkIRect& clipBounds, NinePatch*) const {
297     return kUnimplemented_FilterReturn;
298 }
299
300 #if SK_SUPPORT_GPU
301 bool SkMaskFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&) const {
302     return false;
303 }
304
305 bool 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
320 bool SkMaskFilter::directFilterRRectMaskGPU(GrContext* context,
321                                             GrPaint* grp,
322                                             const SkStrokeRec& strokeRec,
323                                             const SkRRect& rrect) const {
324     return false;
325 }
326
327 bool 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
336 void 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 }