3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkMaskFilter.h"
11 #include "SkBlitter.h"
13 #include "SkRasterClip.h"
18 #include "GrTexture.h"
20 #include "SkGrPixelRef.h"
23 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
28 bool SkMaskFilter::asABlur(BlurRec*) const {
32 static void extractMaskSubset(const SkMask& src, SkMask* dst) {
33 SkASSERT(src.fBounds.contains(dst->fBounds));
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;
42 static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
43 const SkIRect& bounds, const SkIRect& clipR) {
45 if (r.intersect(bounds, clipR)) {
46 blitter->blitMask(mask, r);
50 static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
52 if (r.intersect(rect, clipR)) {
53 blitter->blitRect(r.left(), r.top(), r.width(), r.height());
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));
69 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
70 const SkIPoint& center, bool fillCenter,
71 const SkIRect& clipR, SkBlitter* blitter) {
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);
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);
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);
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);
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()));
123 blitClippedRect(blitter, innerR, clipR);
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);
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) {
142 alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
143 blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
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) {
155 alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
156 blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
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));
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));
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();
189 SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
191 if (!clipper.done()) {
192 const SkIRect& cr = clipper.rect();
194 draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
196 } while (!clipper.done());
200 static int countNestedRects(const SkPath& path, SkRect rects[2]) {
201 if (path.isNestedRects(rects)) {
204 return path.isRect(&rects[0]);
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.
214 patch.fMask.fImage = NULL;
215 if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
218 SkASSERT(NULL == patch.fMask.fImage);
221 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
222 SkMask::FreeImage(patch.fMask.fImage);
226 bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
227 const SkRasterClip& clip, SkBlitter* blitter,
228 SkPaint::Style style) const {
231 if (SkPaint::kFill_Style == style) {
232 rectCount = countNestedRects(devPath, rects);
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);
244 case kTrue_FilterReturn:
245 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
247 SkMask::FreeImage(patch.fMask.fImage);
250 case kUnimplemented_FilterReturn:
251 SkASSERT(NULL == patch.fMask.fImage);
259 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
260 SkMask::kComputeBoundsAndRenderImage_CreateMode,
264 SkAutoMaskFreeImage autoSrc(srcM.fImage);
266 if (!this->filterMask(&dstM, srcM, matrix, NULL)) {
269 SkAutoMaskFreeImage autoDst(dstM.fImage);
271 // if we get here, we need to (possibly) resolve the clip and blitter
272 SkAAClipBlitterWrapper wrapper(clip, blitter);
273 blitter = wrapper.getBlitter();
275 SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
277 if (!clipper.done()) {
278 const SkIRect& cr = clipper.rect();
280 blitter->blitMask(dstM, cr);
282 } while (!clipper.done());
288 SkMaskFilter::FilterReturn
289 SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&,
290 const SkIRect& clipBounds, NinePatch*) const {
291 return kUnimplemented_FilterReturn;
294 SkMaskFilter::FilterReturn
295 SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
296 const SkIRect& clipBounds, NinePatch*) const {
297 return kUnimplemented_FilterReturn;
301 bool SkMaskFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&) const {
305 bool SkMaskFilter::canFilterMaskGPU(const SkRect& devBounds,
306 const SkIRect& clipBounds,
308 SkRect* maskRect) const {
312 bool SkMaskFilter::directFilterMaskGPU(GrContext* context,
314 const SkStrokeRec& strokeRec,
315 const SkPath& path) const {
320 bool SkMaskFilter::directFilterRRectMaskGPU(GrContext* context,
322 const SkStrokeRec& strokeRec,
323 const SkRRect& rrect) const {
327 bool SkMaskFilter::filterMaskGPU(GrTexture* src,
329 const SkRect& maskRect,
331 bool canOverwriteSrc) const {
336 void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
340 src.roundOut(&srcM.fBounds);
342 srcM.fFormat = SkMask::kA8_Format;
344 SkIPoint margin; // ignored
345 if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
346 dst->set(dstM.fBounds);
348 dst->set(srcM.fBounds);