Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkMaskFilter.cpp
Go to the documentation of this file.
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 */
8
12#include "include/core/SkPath.h"
14#include "include/core/SkRect.h"
21#include "src/base/SkTLazy.h"
22#include "src/core/SkBlitter.h"
24#include "src/core/SkDraw.h"
25#include "src/core/SkMask.h"
27#include "src/core/SkPathPriv.h"
29
30#include <algorithm>
31#include <cstdint>
32
33class SkRRect;
34struct SkDeserialProcs;
35
37 if (fCache) {
38 SkASSERT((const void*)fMask.fImage == fCache->data());
39 fCache->unref();
40 } else {
41 // fMask is about to be destroyed and "owns" its fImage.
42 SkMaskBuilder::FreeImage(const_cast<uint8_t*>(fMask.fImage));
43 }
44}
45
47 return false;
48}
49
51 return nullptr;
52}
53
54static SkMask extractMaskSubset(const SkMask& src, SkIRect bounds, int32_t newX, int32_t newY) {
55 SkASSERT(src.fBounds.contains(bounds));
56
57 const int dx = bounds.left() - src.fBounds.left();
58 const int dy = bounds.top() - src.fBounds.top();
59 bounds.offsetTo(newX, newY);
60 return SkMask(src.fImage + dy * src.fRowBytes + dx,
61 bounds,
62 src.fRowBytes,
63 src.fFormat);
64}
65
66static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
67 const SkIRect& bounds, const SkIRect& clipR) {
68 SkIRect r;
69 if (r.intersect(bounds, clipR)) {
70 blitter->blitMask(mask, r);
71 }
72}
73
74static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
75 SkIRect r;
76 if (r.intersect(rect, clipR)) {
77 blitter->blitRect(r.left(), r.top(), r.width(), r.height());
78 }
79}
80
81static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
82 const SkIPoint& center, bool fillCenter,
83 const SkIRect& clipR, SkBlitter* blitter) {
84 int cx = center.x();
85 int cy = center.y();
86 SkIRect bounds;
87
88 // top-left
89 bounds = mask.fBounds;
90 bounds.fRight = cx;
91 bounds.fBottom = cy;
92 if (bounds.width() > 0 && bounds.height() > 0) {
93 SkMask m = extractMaskSubset(mask, bounds, outerR.left(), outerR.top());
94 blitClippedMask(blitter, m, m.fBounds, clipR);
95 }
96
97 // top-right
98 bounds = mask.fBounds;
99 bounds.fLeft = cx + 1;
100 bounds.fBottom = cy;
101 if (bounds.width() > 0 && bounds.height() > 0) {
102 SkMask m = extractMaskSubset(mask, bounds, outerR.right() - bounds.width(), outerR.top());
103 blitClippedMask(blitter, m, m.fBounds, clipR);
104 }
105
106 // bottom-left
107 bounds = mask.fBounds;
108 bounds.fRight = cx;
109 bounds.fTop = cy + 1;
110 if (bounds.width() > 0 && bounds.height() > 0) {
111 SkMask m = extractMaskSubset(mask, bounds, outerR.left(), outerR.bottom() - bounds.height());
112 blitClippedMask(blitter, m, m.fBounds, clipR);
113 }
114
115 // bottom-right
116 bounds = mask.fBounds;
117 bounds.fLeft = cx + 1;
118 bounds.fTop = cy + 1;
119 if (bounds.width() > 0 && bounds.height() > 0) {
120 SkMask m = extractMaskSubset(mask, bounds, outerR.right() - bounds.width(),
121 outerR.bottom() - bounds.height());
122 blitClippedMask(blitter, m, m.fBounds, clipR);
123 }
124
125 SkIRect innerR;
126 innerR.setLTRB(outerR.left() + cx - mask.fBounds.left(),
127 outerR.top() + cy - mask.fBounds.top(),
128 outerR.right() + (cx + 1 - mask.fBounds.right()),
129 outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
130 if (fillCenter) {
131 blitClippedRect(blitter, innerR, clipR);
132 }
133
134 const int innerW = innerR.width();
135 size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
136 SkAutoSMalloc<4*1024> storage(storageSize);
137 int16_t* runs = (int16_t*)storage.get();
138 uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
139
140 SkIRect r;
141 // top
142 r.setLTRB(innerR.left(), outerR.top(), innerR.right(), innerR.top());
143 if (r.intersect(clipR)) {
144 int startY = std::max(0, r.top() - outerR.top());
145 int stopY = startY + r.height();
146 int width = r.width();
147 for (int y = startY; y < stopY; ++y) {
148 runs[0] = width;
149 runs[width] = 0;
150 alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
151 blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
152 }
153 }
154 // bottom
155 r.setLTRB(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
156 if (r.intersect(clipR)) {
157 int startY = outerR.bottom() - r.bottom();
158 int stopY = startY + r.height();
159 int width = r.width();
160 for (int y = startY; y < stopY; ++y) {
161 runs[0] = width;
162 runs[width] = 0;
163 alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
164 blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
165 }
166 }
167 // left
168 r.setLTRB(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
169 if (r.intersect(clipR)) {
170 SkMask leftMask(mask.getAddr8(mask.fBounds.left() + r.left() - outerR.left(),
171 mask.fBounds.top() + cy),
172 r,
173 0, // so we repeat the scanline for our height
175 blitter->blitMask(leftMask, r);
176 }
177 // right
178 r.setLTRB(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
179 if (r.intersect(clipR)) {
180 SkMask rightMask(mask.getAddr8(mask.fBounds.right() - outerR.right() + r.left(),
181 mask.fBounds.top() + cy),
182 r,
183 0, // so we repeat the scanline for our height
185 blitter->blitMask(rightMask, r);
186 }
187}
188
189static void draw_nine(const SkMask& mask, const SkIRect& outerR, const SkIPoint& center,
190 bool fillCenter, const SkRasterClip& clip, SkBlitter* blitter) {
191 // if we get here, we need to (possibly) resolve the clip and blitter
192 SkAAClipBlitterWrapper wrapper(clip, blitter);
193 blitter = wrapper.getBlitter();
194
195 SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
196
197 if (!clipper.done()) {
198 const SkIRect& cr = clipper.rect();
199 do {
200 draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
201 clipper.next();
202 } while (!clipper.done());
203 }
204}
205
206static int countNestedRects(const SkPath& path, SkRect rects[2]) {
207 if (SkPathPriv::IsNestedFillRects(path, rects)) {
208 return 2;
209 }
210 return path.isRect(&rects[0]);
211}
212
213bool SkMaskFilterBase::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
214 const SkRasterClip& clip, SkBlitter* blitter) const {
215 // Attempt to speed up drawing by creating a nine patch. If a nine patch
216 // cannot be used, return false to allow our caller to recover and perform
217 // the drawing another way.
218 SkTLazy<NinePatch> patch;
219 if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
220 clip.getBounds(),
221 &patch)) {
222 SkASSERT(!patch.isValid());
223 return false;
224 }
225 draw_nine(patch->fMask, patch->fOuterRect, patch->fCenter, true, clip, blitter);
226 return true;
227}
228
229bool SkMaskFilterBase::filterPath(const SkPath& devPath, const SkMatrix& matrix,
230 const SkRasterClip& clip, SkBlitter* blitter,
231 SkStrokeRec::InitStyle style) const {
232 SkRect rects[2];
233 int rectCount = 0;
234 if (SkStrokeRec::kFill_InitStyle == style) {
235 rectCount = countNestedRects(devPath, rects);
236 }
237 if (rectCount > 0) {
238 SkTLazy<NinePatch> patch;
239
240 switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
242 SkASSERT(!patch.isValid());
243 return false;
244
246 draw_nine(patch->fMask, patch->fOuterRect, patch->fCenter, 1 == rectCount, clip,
247 blitter);
248 return true;
249
251 SkASSERT(!patch.isValid());
252 // fall out
253 break;
254 }
255 }
256
257 SkMaskBuilder srcM, dstM;
258
259#if defined(SK_BUILD_FOR_FUZZER)
260 if (devPath.countVerbs() > 1000 || devPath.countPoints() > 1000) {
261 return false;
262 }
263#endif
264 if (!SkDraw::DrawToMask(devPath, clip.getBounds(), this, &matrix, &srcM,
266 style)) {
267 return false;
268 }
269 SkAutoMaskFreeImage autoSrc(srcM.image());
270
271 if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
272 return false;
273 }
274 SkAutoMaskFreeImage autoDst(dstM.image());
275
276 // if we get here, we need to (possibly) resolve the clip and blitter
277 SkAAClipBlitterWrapper wrapper(clip, blitter);
278 blitter = wrapper.getBlitter();
279
280 SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
281
282 if (!clipper.done()) {
283 const SkIRect& cr = clipper.rect();
284 do {
285 blitter->blitMask(dstM, cr);
286 clipper.next();
287 } while (!clipper.done());
288 }
289
290 return true;
291}
292
295 const SkIRect& clipBounds, SkTLazy<NinePatch>*) const {
297}
298
301 const SkIRect& clipBounds, SkTLazy<NinePatch>*) const {
303}
304
306 SkMask srcM(nullptr, src.roundOut(), 0, SkMask::kA8_Format);
307 SkMaskBuilder dstM;
308
309 SkIPoint margin; // ignored
310 if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
311 dst->set(dstM.fBounds);
312 } else {
313 dst->set(srcM.fBounds);
314 }
315}
316
318 SkRect dst;
319 as_MFB(this)->computeFastBounds(src, &dst);
320 return dst;
321}
322
323void SkMaskFilter::RegisterFlattenables() {
325}
326
327sk_sp<SkMaskFilter> SkMaskFilter::Deserialize(const void* data, size_t size,
328 const SkDeserialProcs* procs) {
329 return sk_sp<SkMaskFilter>(static_cast<SkMaskFilter*>(
331 kSkMaskFilter_Type, data, size, procs).release()));
332}
int count
#define SkASSERT(cond)
Definition SkAssert.h:116
void sk_register_blur_maskfilter_createproc()
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
static void draw_nine(const SkMask &mask, const SkIRect &outerR, const SkIPoint &center, bool fillCenter, const SkRasterClip &clip, SkBlitter *blitter)
static SkMask extractMaskSubset(const SkMask &src, SkIRect bounds, int32_t newX, int32_t newY)
static void draw_nine_clipped(const SkMask &mask, const SkIRect &outerR, const SkIPoint &center, bool fillCenter, const SkIRect &clipR, SkBlitter *blitter)
static void blitClippedRect(SkBlitter *blitter, const SkIRect &rect, const SkIRect &clipR)
static void blitClippedMask(SkBlitter *blitter, const SkMask &mask, const SkIRect &bounds, const SkIRect &clipR)
static int countNestedRects(const SkPath &path, SkRect rects[2])
std::unique_ptr< uint8_t, SkFunctionObject< SkMaskBuilder::FreeImage > > SkAutoMaskFreeImage
Definition SkMask.h:316
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static SkScalar center(float pos0, float pos1)
const SkRegion & getRgn() const
SkBlitter * getBlitter()
void * get() const
virtual void blitMask(const SkMask &, const SkIRect &clip)
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])=0
virtual void blitRect(int x, int y, int width, int height)
Blit a solid rectangle one or more pixels wide.
void unref() const
const void * data() const
static bool DrawToMask(const SkPath &devPath, const SkIRect &clipBounds, const SkMaskFilter *, const SkMatrix *filterMatrix, SkMaskBuilder *dst, SkMaskBuilder::CreateMode mode, SkStrokeRec::InitStyle style)
static sk_sp< SkFlattenable > Deserialize(Type, const void *data, size_t length, const SkDeserialProcs *procs=nullptr)
virtual sk_sp< SkImageFilter > asImageFilter(const SkMatrix &ctm) const
virtual bool filterMask(SkMaskBuilder *dst, const SkMask &src, const SkMatrix &, SkIPoint *margin) const =0
virtual bool asABlur(BlurRec *) const
virtual FilterReturn filterRRectToNine(const SkRRect &, const SkMatrix &, const SkIRect &clipBounds, SkTLazy< NinePatch > *) const
virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix &, const SkIRect &clipBounds, SkTLazy< NinePatch > *) const
virtual void computeFastBounds(const SkRect &src, SkRect *dest) const
static sk_sp< SkMaskFilter > Deserialize(const void *data, size_t size, const SkDeserialProcs *procs=nullptr)
SkRect approximateFilteredBounds(const SkRect &src) const
static const SkMatrix & I()
static bool IsNestedFillRects(const SkPath &, SkRect rect[2], SkPathDirection dirs[2]=nullptr)
Definition SkPath.cpp:3712
int countPoints() const
Definition SkPath.cpp:525
const SkRect & getBounds() const
Definition SkPath.cpp:420
int countVerbs() const
Definition SkPath.cpp:546
const SkIRect & rect() const
Definition SkRegion.h:551
bool isValid() const
Definition SkTLazy.h:77
double y
int32_t width
bool intersect(const SkIRect &r)
Definition SkRect.h:513
constexpr int32_t top() const
Definition SkRect.h:120
constexpr int32_t bottom() const
Definition SkRect.h:134
constexpr int32_t height() const
Definition SkRect.h:165
constexpr int32_t right() const
Definition SkRect.h:127
constexpr int32_t width() const
Definition SkRect.h:158
constexpr int32_t left() const
Definition SkRect.h:113
void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom)
Definition SkRect.h:253
static void FreeImage(void *image)
Definition SkMask.cpp:57
@ kComputeBoundsAndRenderImage_CreateMode
compute bounds, alloc image and render into it
Definition SkMask.h:301
uint8_t *& image()
Definition SkMask.h:236
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
Definition SkMask.h:28
const uint8_t * getAddr8(int x, int y) const
Definition SkMask.h:79
uint8_t const *const fImage
Definition SkMask.h:41
const SkIRect fBounds
Definition SkMask.h:42