Flutter Engine
The Flutter Engine
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();
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]) {
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;
320 return dst;
321}
322
323void SkMaskFilter::RegisterFlattenables() {
325}
326
328 const SkDeserialProcs* procs) {
329 return sk_sp<SkMaskFilter>(static_cast<SkMaskFilter*>(
331 kSkMaskFilter_Type, data, size, procs).release()));
332}
int count
Definition: FontMgrTest.cpp:50
#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:3892
static SkScalar center(float pos0, float pos1)
const SkRegion & getRgn() const
Definition: SkRasterClip.h:175
SkBlitter * getBlitter()
Definition: SkRasterClip.h:179
void * get() const
Definition: SkAutoMalloc.h:126
virtual void blitMask(const SkMask &, const SkIRect &clip)
Definition: SkBlitter.cpp:201
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.
Definition: SkBlitter.cpp:133
void unref() const
Definition: SkCachedData.h:31
const void * data() const
Definition: SkCachedData.h:26
static bool DrawToMask(const SkPath &devPath, const SkIRect &clipBounds, const SkMaskFilter *, const SkMatrix *filterMatrix, SkMaskBuilder *dst, SkMaskBuilder::CreateMode mode, SkStrokeRec::InitStyle style)
Definition: SkDrawBase.cpp:559
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()
Definition: SkMatrix.cpp:1544
static bool IsNestedFillRects(const SkPath &, SkRect rect[2], SkPathDirection dirs[2]=nullptr)
Definition: SkPath.cpp:3780
Definition: SkPath.h:59
int countPoints() const
Definition: SkPath.cpp:535
const SkRect & getBounds() const
Definition: SkPath.cpp:430
int countVerbs() const
Definition: SkPath.cpp:556
const SkIRect & rect() const
Definition: SkRegion.h:551
bool isValid() const
Definition: SkTLazy.h:77
static float max(float r, float g, float b)
Definition: hsl.cpp:49
double y
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
int32_t width
Definition: SkRect.h:32
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
Definition: SkMask.h:25
@ 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
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63