Coverage Report

Created: 2024-05-20 07:14

/src/skia/src/core/SkCanvasPriv.cpp
Line
Count
Source (jump to first uncovered line)
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
8
#include "src/core/SkCanvasPriv.h"
9
10
#include "include/core/SkBlendMode.h"
11
#include "include/core/SkColor.h"
12
#include "include/core/SkColorFilter.h"
13
#include "include/core/SkImageFilter.h"
14
#include "include/core/SkMaskFilter.h"
15
#include "include/core/SkMatrix.h"
16
#include "include/core/SkRect.h"
17
#include "include/core/SkRefCnt.h"
18
#include "include/core/SkShader.h"
19
#include "include/private/base/SkAlign.h"
20
#include "include/private/base/SkAssert.h"
21
#include "include/private/base/SkTo.h"
22
#include "src/base/SkAutoMalloc.h"
23
#include "src/core/SkMaskFilterBase.h"
24
#include "src/core/SkReadBuffer.h"
25
#include "src/core/SkWriteBuffer.h"
26
#include "src/core/SkWriter32.h"
27
28
#include <utility>
29
#include <cstdint>
30
31
SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
32
                                                 const SkPaint* paint, const SkRect& bounds)
33
        : fCanvas(canvas)
34
26.6k
        , fSaveCount(canvas->getSaveCount()) {
35
26.6k
    if (paint) {
36
1.60k
        SkRect newBounds = bounds;
37
1.60k
        if (matrix) {
38
178
            matrix->mapRect(&newBounds);
39
178
        }
40
1.60k
        canvas->saveLayer(&newBounds, paint);
41
25.0k
    } else if (matrix) {
42
332
        canvas->save();
43
332
    }
44
45
26.6k
    if (matrix) {
46
510
        canvas->concat(*matrix);
47
510
    }
48
26.6k
}
49
50
26.6k
SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
51
26.6k
    fCanvas->restoreToCount(fSaveCount);
52
26.6k
}
53
54
///////////////////////////////////////////////////////////////////////////////////////////////////
55
56
1.33k
bool SkCanvasPriv::ReadLattice(SkReadBuffer& buffer, SkCanvas::Lattice* lattice) {
57
1.33k
    lattice->fXCount = buffer.readInt();
58
1.33k
    lattice->fXDivs = buffer.skipT<int32_t>(lattice->fXCount);
59
1.33k
    lattice->fYCount = buffer.readInt();
60
1.33k
    lattice->fYDivs = buffer.skipT<int32_t>(lattice->fYCount);
61
1.33k
    int flagCount = buffer.readInt();
62
1.33k
    lattice->fRectTypes = nullptr;
63
1.33k
    lattice->fColors = nullptr;
64
1.33k
    if (flagCount) {
65
257
        lattice->fRectTypes = buffer.skipT<SkCanvas::Lattice::RectType>(flagCount);
66
257
        lattice->fColors = buffer.skipT<SkColor>(flagCount);
67
257
    }
68
1.33k
    lattice->fBounds = buffer.skipT<SkIRect>();
69
1.33k
    return buffer.isValid();
70
1.33k
}
71
72
0
size_t SkCanvasPriv::WriteLattice(void* buffer, const SkCanvas::Lattice& lattice) {
73
0
    int flagCount = lattice.fRectTypes ? (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0;
74
75
0
    const size_t size = (1 + lattice.fXCount + 1 + lattice.fYCount + 1) * sizeof(int32_t) +
76
0
                        SkAlign4(flagCount * sizeof(SkCanvas::Lattice::RectType)) +
77
0
                        SkAlign4(flagCount * sizeof(SkColor)) +
78
0
                        sizeof(SkIRect);
79
80
0
    if (buffer) {
81
0
        SkWriter32 writer(buffer, size);
82
0
        writer.write32(lattice.fXCount);
83
0
        writer.write(lattice.fXDivs, lattice.fXCount * sizeof(uint32_t));
84
0
        writer.write32(lattice.fYCount);
85
0
        writer.write(lattice.fYDivs, lattice.fYCount * sizeof(uint32_t));
86
0
        writer.write32(flagCount);
87
0
        writer.writePad(lattice.fRectTypes, flagCount * sizeof(uint8_t));
88
0
        writer.write(lattice.fColors, flagCount * sizeof(SkColor));
89
0
        SkASSERT(lattice.fBounds);
90
0
        writer.write(lattice.fBounds, sizeof(SkIRect));
91
0
        SkASSERT(writer.bytesWritten() == size);
92
0
    }
93
0
    return size;
94
0
}
Unexecuted instantiation: SkCanvasPriv::WriteLattice(void*, SkCanvas::Lattice const&)
Unexecuted instantiation: SkCanvasPriv::WriteLattice(void*, SkCanvas::Lattice const&)
95
96
0
void SkCanvasPriv::WriteLattice(SkWriteBuffer& buffer, const SkCanvas::Lattice& lattice) {
97
0
    const size_t size = WriteLattice(nullptr, lattice);
98
0
    SkAutoSMalloc<1024> storage(size);
99
0
    WriteLattice(storage.get(), lattice);
100
0
    buffer.writePad32(storage.get(), size);
101
0
}
102
103
void SkCanvasPriv::GetDstClipAndMatrixCounts(const SkCanvas::ImageSetEntry set[], int count,
104
603
                                             int* totalDstClipCount, int* totalMatrixCount) {
105
603
    int dstClipCount = 0;
106
603
    int maxMatrixIndex = -1;
107
705
    for (int i = 0; i < count; ++i) {
108
102
        dstClipCount += 4 * set[i].fHasClip;
109
102
        if (set[i].fMatrixIndex > maxMatrixIndex) {
110
19
            maxMatrixIndex = set[i].fMatrixIndex;
111
19
        }
112
102
    }
113
114
603
    *totalDstClipCount = dstClipCount;
115
603
    *totalMatrixCount = maxMatrixIndex + 1;
116
603
}
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.
121
11.2k
bool SkCanvasPriv::ImageToColorFilter(SkPaint* paint) {
122
11.2k
    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
11.2k
    if (paint->getMaskFilter()) {
141
1.08k
        return false;
142
1.08k
    }
143
144
10.1k
    SkColorFilter* imgCFPtr;
145
10.1k
    if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) {
146
10.1k
        return false;
147
10.1k
    }
148
6
    sk_sp<SkColorFilter> imgCF(imgCFPtr);
149
150
6
    SkColorFilter* paintCF = paint->getColorFilter();
151
6
    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
5
        imgCF = imgCF->makeComposed(sk_ref_sp(paintCF));
155
5
    }
156
157
6
    paint->setColorFilter(std::move(imgCF));
158
6
    paint->setImageFilter(nullptr);
159
6
    return true;
160
10.1k
}
161
162
AutoLayerForImageFilter::AutoLayerForImageFilter(SkCanvas* canvas,
163
                                                 const SkPaint& paint,
164
                                                 const SkRect* rawBounds,
165
                                                 bool skipMaskFilterLayer)
166
            : fPaint(paint)
167
            , fCanvas(canvas)
168
1.16M
            , fTempLayersForFilters(0) {
169
1.16M
    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
1.16M
    if (fPaint.getImageFilter() && !SkCanvasPriv::ImageToColorFilter(&fPaint)) {
178
22.4k
        this->addImageFilterLayer(rawBounds);
179
22.4k
    }
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
1.16M
    if (fPaint.getMaskFilter() && !skipMaskFilterLayer) {
187
0
        this->addMaskFilterLayer(rawBounds);
188
0
    }
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
1.16M
}
AutoLayerForImageFilter::AutoLayerForImageFilter(SkCanvas*, SkPaint const&, SkRect const*, bool)
Line
Count
Source
168
583k
            , fTempLayersForFilters(0) {
169
583k
    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
583k
    if (fPaint.getImageFilter() && !SkCanvasPriv::ImageToColorFilter(&fPaint)) {
178
11.2k
        this->addImageFilterLayer(rawBounds);
179
11.2k
    }
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
583k
    if (fPaint.getMaskFilter() && !skipMaskFilterLayer) {
187
0
        this->addMaskFilterLayer(rawBounds);
188
0
    }
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
583k
}
AutoLayerForImageFilter::AutoLayerForImageFilter(SkCanvas*, SkPaint const&, SkRect const*, bool)
Line
Count
Source
168
583k
            , fTempLayersForFilters(0) {
169
583k
    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
583k
    if (fPaint.getImageFilter() && !SkCanvasPriv::ImageToColorFilter(&fPaint)) {
178
11.2k
        this->addImageFilterLayer(rawBounds);
179
11.2k
    }
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
583k
    if (fPaint.getMaskFilter() && !skipMaskFilterLayer) {
187
0
        this->addMaskFilterLayer(rawBounds);
188
0
    }
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
583k
}
195
196
583k
AutoLayerForImageFilter::~AutoLayerForImageFilter() {
197
595k
    for (int i = 0; i < fTempLayersForFilters; ++i) {
198
11.2k
        fCanvas->fSaveCount -= 1;
199
11.2k
        fCanvas->internalRestore();
200
11.2k
    }
201
    // Negative save count occurs when this layer was moved.
202
583k
    SkASSERT(fSaveCount < 0 || fCanvas->getSaveCount() == fSaveCount);
203
583k
}
204
205
0
AutoLayerForImageFilter::AutoLayerForImageFilter(AutoLayerForImageFilter&& other) {
206
0
    *this = std::move(other);
207
0
}
208
209
0
AutoLayerForImageFilter& AutoLayerForImageFilter::operator=(AutoLayerForImageFilter&& other) {
210
0
    fPaint = std::move(other.fPaint);
211
0
    fCanvas = other.fCanvas;
212
0
    fTempLayersForFilters = other.fTempLayersForFilters;
213
0
    SkDEBUGCODE(fSaveCount = other.fSaveCount;)
214
215
0
    other.fTempLayersForFilters = 0;
216
0
    SkDEBUGCODE(other.fSaveCount = -1;)
217
218
0
    return *this;
219
0
}
Unexecuted instantiation: AutoLayerForImageFilter::operator=(AutoLayerForImageFilter&&)
Unexecuted instantiation: AutoLayerForImageFilter::operator=(AutoLayerForImageFilter&&)
220
221
11.2k
void AutoLayerForImageFilter::addImageFilterLayer(const SkRect* drawBounds) {
222
    // Shouldn't be adding a layer if there was no image filter to begin with.
223
11.2k
    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
11.2k
    SkPaint restorePaint;
229
11.2k
    restorePaint.setImageFilter(fPaint.refImageFilter());
230
11.2k
    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
11.2k
    fPaint.setImageFilter(nullptr);
236
11.2k
    fPaint.setBlendMode(SkBlendMode::kSrcOver);
237
238
11.2k
    this->addLayer(restorePaint, drawBounds, /*coverageOnly=*/false);
239
11.2k
}
240
241
0
void AutoLayerForImageFilter::addMaskFilterLayer(const SkRect* drawBounds) {
242
    // Shouldn't be adding a layer if there was no mask filter to begin with.
243
0
    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
0
    SkASSERT(!fPaint.getImageFilter());
248
249
    // TODO: Eventually all SkMaskFilters will implement this method so this can switch to an assert
250
0
    sk_sp<SkImageFilter> maskFilterAsImageFilter =
251
0
            as_MFB(fPaint.getMaskFilter())->asImageFilter(fCanvas->getTotalMatrix());
252
0
    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
0
        return;
257
0
    }
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
0
    SkPaint restorePaint;
263
0
    restorePaint.setColor4f(fPaint.getColor4f());
264
0
    restorePaint.setShader(fPaint.refShader());
265
0
    restorePaint.setColorFilter(fPaint.refColorFilter());
266
0
    restorePaint.setBlender(fPaint.refBlender());
267
0
    restorePaint.setDither(fPaint.isDither());
268
0
    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).
273
0
    fPaint.setColor4f(SkColors::kWhite);
274
0
    fPaint.setShader(nullptr);
275
0
    fPaint.setColorFilter(nullptr);
276
0
    fPaint.setMaskFilter(nullptr);
277
0
    fPaint.setDither(false);
278
0
    fPaint.setBlendMode(SkBlendMode::kSrcOver);
279
280
0
    this->addLayer(restorePaint, drawBounds, /*coverageOnly=*/true);
281
0
}
Unexecuted instantiation: AutoLayerForImageFilter::addMaskFilterLayer(SkRect const*)
Unexecuted instantiation: AutoLayerForImageFilter::addMaskFilterLayer(SkRect const*)
282
283
void AutoLayerForImageFilter::addLayer(const SkPaint& restorePaint,
284
                                       const SkRect* drawBounds,
285
11.2k
                                       bool coverageOnly) {
286
11.2k
    SkRect storage;
287
11.2k
    const SkRect* contentBounds = nullptr;
288
11.2k
    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
10.7k
        contentBounds = &fPaint.computeFastBounds(*drawBounds, &storage);
292
10.7k
    }
293
294
11.2k
    fCanvas->fSaveCount += 1;
295
11.2k
    fCanvas->internalSaveLayer(SkCanvas::SaveLayerRec(contentBounds, &restorePaint),
296
11.2k
                               SkCanvas::kFullLayer_SaveLayerStrategy,
297
11.2k
                               coverageOnly);
298
11.2k
    fTempLayersForFilters += 1;
299
11.2k
}