Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
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) {
65 lattice->fRectTypes = buffer.skipT<SkCanvas::Lattice::RectType>(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) +
76 SkAlign4(flagCount * sizeof(SkCanvas::Lattice::RectType)) +
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);
98 SkAutoSMalloc<1024> storage(size);
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
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
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
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
SkMaskFilterBase * as_MFB(SkMaskFilter *mf)
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
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
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:500
@ kFullLayer_SaveLayerStrategy
Definition SkCanvas.h:2264
int getSaveCount() const
Definition SkCanvas.cpp:435
void restoreToCount(int saveCount)
Definition SkCanvas.cpp:482
SkMatrix getTotalMatrix() const
int save()
Definition SkCanvas.cpp:451
void concat(const SkMatrix &matrix)
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
static const uint8_t buffer[]
constexpr SkColor4f kWhite
Definition SkColor.h:439
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