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