Flutter Engine
The Flutter Engine
SkCanvasPriv.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google Inc.
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
9
16#include "include/core/SkRect.h"
26#include "src/core/SkWriter32.h"
27
28#include <utility>
29#include <cstdint>
30
32 const SkPaint* paint, const SkRect& bounds)
33 : fCanvas(canvas)
34 , fSaveCount(canvas->getSaveCount()) {
35 if (paint) {
36 SkRect newBounds = bounds;
37 if (matrix) {
38 matrix->mapRect(&newBounds);
39 }
40 canvas->saveLayer(&newBounds, paint);
41 } else if (matrix) {
42 canvas->save();
43 }
44
45 if (matrix) {
46 canvas->concat(*matrix);
47 }
48}
49
51 fCanvas->restoreToCount(fSaveCount);
52}
53
54///////////////////////////////////////////////////////////////////////////////////////////////////
55
57 lattice->fXCount = buffer.readInt();
58 lattice->fXDivs = buffer.skipT<int32_t>(lattice->fXCount);
59 lattice->fYCount = buffer.readInt();
60 lattice->fYDivs = buffer.skipT<int32_t>(lattice->fYCount);
61 int flagCount = buffer.readInt();
62 lattice->fRectTypes = nullptr;
63 lattice->fColors = nullptr;
64 if (flagCount) {
66 lattice->fColors = buffer.skipT<SkColor>(flagCount);
67 }
68 lattice->fBounds = buffer.skipT<SkIRect>();
69 return buffer.isValid();
70}
71
73 int flagCount = lattice.fRectTypes ? (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0;
74
75 const size_t size = (1 + lattice.fXCount + 1 + lattice.fYCount + 1) * sizeof(int32_t) +
77 SkAlign4(flagCount * sizeof(SkColor)) +
78 sizeof(SkIRect);
79
80 if (buffer) {
81 SkWriter32 writer(buffer, size);
82 writer.write32(lattice.fXCount);
83 writer.write(lattice.fXDivs, lattice.fXCount * sizeof(uint32_t));
84 writer.write32(lattice.fYCount);
85 writer.write(lattice.fYDivs, lattice.fYCount * sizeof(uint32_t));
86 writer.write32(flagCount);
87 writer.writePad(lattice.fRectTypes, flagCount * sizeof(uint8_t));
88 writer.write(lattice.fColors, flagCount * sizeof(SkColor));
89 SkASSERT(lattice.fBounds);
90 writer.write(lattice.fBounds, sizeof(SkIRect));
91 SkASSERT(writer.bytesWritten() == size);
92 }
93 return size;
94}
95
97 const size_t size = WriteLattice(nullptr, lattice);
99 WriteLattice(storage.get(), lattice);
100 buffer.writePad32(storage.get(), size);
101}
102
104 int* totalDstClipCount, int* totalMatrixCount) {
105 int dstClipCount = 0;
106 int maxMatrixIndex = -1;
107 for (int i = 0; i < count; ++i) {
108 dstClipCount += 4 * set[i].fHasClip;
109 if (set[i].fMatrixIndex > maxMatrixIndex) {
110 maxMatrixIndex = set[i].fMatrixIndex;
111 }
112 }
113
114 *totalDstClipCount = dstClipCount;
115 *totalMatrixCount = maxMatrixIndex + 1;
116}
117
118// Attempts to convert an image filter to its equivalent color filter, which if possible, modifies
119// the paint to compose the image filter's color filter into the paint's color filter slot. Returns
120// true if the paint has been modified. Requires the paint to have an image filter.
122 SkASSERT(SkToBool(paint) && paint->getImageFilter());
123
124 // An image filter logically runs after any mask filter and the src-over blending against the
125 // layer's transparent black initial content. Moving the image filter (as a color filter) into
126 // the color filter slot causes it to run before the mask filter or blending.
127 //
128 // Src-over blending against transparent black is a no-op, so skipping the layer and drawing the
129 // output of the color filter-image filter with the original blender is valid.
130 //
131 // If there's also a mask filter on the paint, it will operate on an alpha-only layer that's
132 // then shaded with the paint's effects. Moving the CF-IF into the paint's color filter slot
133 // will mean that the CF-IF operates on the output of the original CF *before* it's combined
134 // with the coverage value. Under normal circumstances the CF-IF evaluates the color after
135 // coverage has been multiplied into the alpha channel.
136 //
137 // Some color filters may behave the same, e.g. cf(color)*coverage == cf(color*coverage), but
138 // that's hard to detect so we disable the optimization when both image filters and mask filters
139 // are present.
140 if (paint->getMaskFilter()) {
141 return false;
142 }
143
144 SkColorFilter* imgCFPtr;
145 if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) {
146 return false;
147 }
148 sk_sp<SkColorFilter> imgCF(imgCFPtr);
149
150 SkColorFilter* paintCF = paint->getColorFilter();
151 if (paintCF) {
152 // The paint has both a colorfilter(paintCF) and an imagefilter-that-is-a-colorfilter(imgCF)
153 // and we need to combine them into a single colorfilter.
154 imgCF = imgCF->makeComposed(sk_ref_sp(paintCF));
155 }
156
157 paint->setColorFilter(std::move(imgCF));
158 paint->setImageFilter(nullptr);
159 return true;
160}
161
163 const SkPaint& paint,
164 const SkRect* rawBounds,
165 bool skipMaskFilterLayer)
166 : fPaint(paint)
167 , fCanvas(canvas)
168 , fTempLayersForFilters(0) {
169 SkDEBUGCODE(fSaveCount = canvas->getSaveCount();)
170
171 // Depending on the original paint, this will add 0, 1, or 2 layers that apply the
172 // filter effects to a temporary layer that rasterized the remaining effects. Image filters
173 // are applied to the result of any mask filter, so its layer is added first in the stack.
174 //
175 // If present on the original paint, the image filter layer's restore paint steals the blender
176 // and the image filter so that the draw's paint will never have an image filter.
177 if (fPaint.getImageFilter() && !SkCanvasPriv::ImageToColorFilter(&fPaint)) {
178 this->addImageFilterLayer(rawBounds);
179 }
180
181 // If present on the original paint, the mask filter layer's restore paint steals all shading
182 // effects and the draw's paint shading is updated to draw a solid opaque color (thus encoding
183 // coverage into the alpha channel). The draw's paint preserves all geometric effects that have
184 // to be applied before the mask filter. The layer's restore paint adds an image filter
185 // representing the mask filter.
186 if (fPaint.getMaskFilter() && !skipMaskFilterLayer) {
187 this->addMaskFilterLayer(rawBounds);
188 }
189
190 // When the original paint has both an image filter and a mask filter, this will create two
191 // internal layers and perform two restores when finished. This actually creates one fewer
192 // offscreen passes compared to directly composing the mask filter's output with an
193 // SkImageFilters::Shader node and passing that into the rest of the image filter.
194}
195
197 for (int i = 0; i < fTempLayersForFilters; ++i) {
198 fCanvas->fSaveCount -= 1;
199 fCanvas->internalRestore();
200 }
201 // Negative save count occurs when this layer was moved.
202 SkASSERT(fSaveCount < 0 || fCanvas->getSaveCount() == fSaveCount);
203}
204
206 *this = std::move(other);
207}
208
210 fPaint = std::move(other.fPaint);
211 fCanvas = other.fCanvas;
212 fTempLayersForFilters = other.fTempLayersForFilters;
213 SkDEBUGCODE(fSaveCount = other.fSaveCount;)
214
215 other.fTempLayersForFilters = 0;
216 SkDEBUGCODE(other.fSaveCount = -1;)
217
218 return *this;
219}
220
221void AutoLayerForImageFilter::addImageFilterLayer(const SkRect* drawBounds) {
222 // Shouldn't be adding a layer if there was no image filter to begin with.
223 SkASSERT(fPaint.getImageFilter());
224
225 // The restore paint for an image filter layer simply takes the image filter and blending off
226 // the original paint. The blending is applied post image filter because otherwise it'd be
227 // applied with the new layer's transparent dst and not be very interesting.
228 SkPaint restorePaint;
229 restorePaint.setImageFilter(fPaint.refImageFilter());
230 restorePaint.setBlender(fPaint.refBlender());
231
232 // Remove the restorePaint fields from our "working" paint, leaving all other shading and
233 // geometry effects to be rendered into the layer. If there happens to be a mask filter, this
234 // paint will still trigger a second layer for that filter.
235 fPaint.setImageFilter(nullptr);
237
238 this->addLayer(restorePaint, drawBounds, /*coverageOnly=*/false);
239}
240
242 // Shouldn't be adding a layer if there was no mask filter to begin with.
243 SkASSERT(fPaint.getMaskFilter());
244
245 // Image filters are evaluated after mask filters so any filter should have been converted to
246 // a layer and removed from fPaint already.
247 SkASSERT(!fPaint.getImageFilter());
248
249 // TODO: Eventually all SkMaskFilters will implement this method so this can switch to an assert
250 sk_sp<SkImageFilter> maskFilterAsImageFilter =
251 as_MFB(fPaint.getMaskFilter())->asImageFilter(fCanvas->getTotalMatrix());
252 if (!maskFilterAsImageFilter) {
253 // This is a legacy mask filter that can be handled by raster and Ganesh directly, but will
254 // be ignored by Graphite. Return now, leaving the paint with the mask filter so that the
255 // underlying SkDevice can handle it if it will.
256 return;
257 }
258
259 // The restore paint for the coverage layer takes over all shading effects that had been on the
260 // original paint, which will be applied to the alpha-only output image from the mask filter
261 // converted to an image filter.
262 SkPaint restorePaint;
263 restorePaint.setColor4f(fPaint.getColor4f());
264 restorePaint.setShader(fPaint.refShader());
265 restorePaint.setColorFilter(fPaint.refColorFilter());
266 restorePaint.setBlender(fPaint.refBlender());
267 restorePaint.setDither(fPaint.isDither());
268 restorePaint.setImageFilter(maskFilterAsImageFilter);
269
270 // Remove all shading effects from the "working" paint so that the layer's alpha channel
271 // will correspond to the coverage. This leaves the original style and AA settings that
272 // contribute to coverage (including any path effect).
274 fPaint.setShader(nullptr);
275 fPaint.setColorFilter(nullptr);
276 fPaint.setMaskFilter(nullptr);
277 fPaint.setDither(false);
279
280 this->addLayer(restorePaint, drawBounds, /*coverageOnly=*/true);
281}
282
283void AutoLayerForImageFilter::addLayer(const SkPaint& restorePaint,
284 const SkRect* drawBounds,
285 bool coverageOnly) {
286 SkRect storage;
287 const SkRect* contentBounds = nullptr;
288 if (drawBounds && fPaint.canComputeFastBounds()) {
289 // The content bounds will include all paint outsets except for those that have been
290 // extracted into 'restorePaint' or a previously added layer.
291 contentBounds = &fPaint.computeFastBounds(*drawBounds, &storage);
292 }
293
294 fCanvas->fSaveCount += 1;
295 fCanvas->internalSaveLayer(SkCanvas::SaveLayerRec(contentBounds, &restorePaint),
297 coverageOnly);
298 fTempLayersForFilters += 1;
299}
int count
Definition: FontMgrTest.cpp:50
static constexpr T SkAlign4(T x)
Definition: SkAlign.h:16
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kSrcOver
r = s + (1-sa)*d
uint32_t SkColor
Definition: SkColor.h:37
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
void addMaskFilterLayer(const SkRect *drawBounds)
AutoLayerForImageFilter(SkCanvas *canvas, const SkPaint &paint, const SkRect *rawBounds, bool skipMaskFilterLayer)
AutoLayerForImageFilter & operator=(const AutoLayerForImageFilter &)=delete
SkAutoCanvasMatrixPaint(SkCanvas *, const SkMatrix *, const SkPaint *, const SkRect &bounds)
void * get() const
Definition: SkAutoMalloc.h:126
static void WriteLattice(SkWriteBuffer &, const SkCanvas::Lattice &)
static bool ReadLattice(SkReadBuffer &, SkCanvas::Lattice *)
static bool ImageToColorFilter(SkPaint *)
static void GetDstClipAndMatrixCounts(const SkCanvas::ImageSetEntry set[], int count, int *totalDstClipCount, int *totalMatrixCount)
int saveLayer(const SkRect *bounds, const SkPaint *paint)
Definition: SkCanvas.cpp:496
@ kFullLayer_SaveLayerStrategy
Definition: SkCanvas.h:2264
int getSaveCount() const
Definition: SkCanvas.cpp:431
void restoreToCount(int saveCount)
Definition: SkCanvas.cpp:478
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
int save()
Definition: SkCanvas.cpp:447
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
sk_sp< SkColorFilter > makeComposed(sk_sp< SkColorFilter > inner) const
virtual sk_sp< SkImageFilter > asImageFilter(const SkMatrix &ctm) const
sk_sp< SkShader > refShader() const
sk_sp< SkImageFilter > refImageFilter() const
void setDither(bool dither)
Definition: SkPaint.h:182
void setImageFilter(sk_sp< SkImageFilter > imageFilter)
const SkRect & computeFastBounds(const SkRect &orig, SkRect *storage) const
Definition: SkPaint.cpp:213
bool isDither() const
Definition: SkPaint.h:175
sk_sp< SkColorFilter > refColorFilter() const
void setColor4f(const SkColor4f &color, SkColorSpace *colorSpace=nullptr)
Definition: SkPaint.h:253
void setMaskFilter(sk_sp< SkMaskFilter > maskFilter)
SkColor4f getColor4f() const
Definition: SkPaint.h:232
SkMaskFilter * getMaskFilter() const
Definition: SkPaint.h:534
sk_sp< SkBlender > refBlender() const
void setShader(sk_sp< SkShader > shader)
void setBlendMode(SkBlendMode mode)
Definition: SkPaint.cpp:151
SkImageFilter * getImageFilter() const
Definition: SkPaint.h:564
void setColorFilter(sk_sp< SkColorFilter > colorFilter)
void setBlender(sk_sp< SkBlender > blender)
Definition: SkPaint.cpp:155
bool canComputeFastBounds() const
Definition: SkPaint.cpp:201
void write32(int32_t value)
Definition: SkWriter32.h:117
void write(const void *values, size_t size)
Definition: SkWriter32.h:170
void writePad(const void *src, size_t size)
Definition: SkWriter32.h:192
size_t bytesWritten() const
Definition: SkWriter32.h:48
const Paint & paint
Definition: color_source.cc:38
constexpr SkColor4f kWhite
Definition: SkColor.h:439
int flagCount
Definition: SkRecords.h:274
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
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
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
int fYCount
number of y-coordinates
Definition: SkCanvas.h:1617
const SkIRect * fBounds
source bounds to draw from
Definition: SkCanvas.h:1618
const int * fYDivs
y-axis values dividing bitmap
Definition: SkCanvas.h:1614
int fXCount
number of x-coordinates
Definition: SkCanvas.h:1616
const RectType * fRectTypes
array of fill types
Definition: SkCanvas.h:1615
const SkColor * fColors
array of colors
Definition: SkCanvas.h:1619
const int * fXDivs
x-axis values dividing bitmap
Definition: SkCanvas.h:1613
Definition: SkRect.h:32