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