Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/effects/imagefilters/SkColorFilterImageFilter.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2012 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
 */
7
8
#include "include/core/SkCanvas.h"
9
#include "include/core/SkColorFilter.h"
10
#include "include/effects/SkImageFilters.h"
11
#include "src/core/SkColorFilterBase.h"
12
#include "src/core/SkImageFilter_Base.h"
13
#include "src/core/SkReadBuffer.h"
14
#include "src/core/SkSpecialImage.h"
15
#include "src/core/SkSpecialSurface.h"
16
#include "src/core/SkWriteBuffer.h"
17
18
namespace {
19
20
class SkColorFilterImageFilter final : public SkImageFilter_Base {
21
public:
22
    SkColorFilterImageFilter(sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input,
23
                             const SkRect* cropRect)
24
            : INHERITED(&input, 1, cropRect)
25
90.1k
            , fColorFilter(std::move(cf)) {}
26
27
protected:
28
    void flatten(SkWriteBuffer&) const override;
29
    sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
30
    bool onIsColorFilterNode(SkColorFilter**) const override;
31
46.0k
    MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
32
    bool onAffectsTransparentBlack() const override;
33
34
private:
35
    friend void ::SkRegisterColorFilterImageFilterFlattenable();
36
    SK_FLATTENABLE_HOOKS(SkColorFilterImageFilter)
37
38
    sk_sp<SkColorFilter> fColorFilter;
39
40
    using INHERITED = SkImageFilter_Base;
41
};
42
43
} // end namespace
44
45
sk_sp<SkImageFilter> SkImageFilters::ColorFilter(
46
96.5k
        sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input, const CropRect& cropRect) {
47
96.5k
    if (!cf) {
48
6.41k
        return nullptr;
49
6.41k
    }
50
51
90.1k
    SkColorFilter* inputCF;
52
90.1k
    if (input && input->isColorFilterNode(&inputCF)) {
53
        // This is an optimization, as it collapses the hierarchy by just combining the two
54
        // colorfilters into a single one, which the new imagefilter will wrap.
55
42.7k
        sk_sp<SkColorFilter> newCF = cf->makeComposed(sk_sp<SkColorFilter>(inputCF));
56
42.7k
        if (newCF) {
57
42.7k
            return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(
58
42.7k
                    std::move(newCF), sk_ref_sp(input->getInput(0)), cropRect));
59
42.7k
        }
60
47.3k
    }
61
62
47.3k
    return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(
63
47.3k
            std::move(cf), std::move(input), cropRect));
64
47.3k
}
65
66
3
void SkRegisterColorFilterImageFilterFlattenable() {
67
3
    SK_REGISTER_FLATTENABLE(SkColorFilterImageFilter);
68
    // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
69
3
    SkFlattenable::Register("SkColorFilterImageFilterImpl", SkColorFilterImageFilter::CreateProc);
70
3
}
71
72
73
26
sk_sp<SkFlattenable> SkColorFilterImageFilter::CreateProc(SkReadBuffer& buffer) {
74
26
    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
75
5
    sk_sp<SkColorFilter> cf(buffer.readColorFilter());
76
5
    return SkImageFilters::ColorFilter(std::move(cf), common.getInput(0), common.cropRect());
77
26
}
78
79
0
void SkColorFilterImageFilter::flatten(SkWriteBuffer& buffer) const {
80
0
    this->INHERITED::flatten(buffer);
81
0
    buffer.writeFlattenable(fColorFilter.get());
82
0
}
83
84
///////////////////////////////////////////////////////////////////////////////////////////////////
85
86
sk_sp<SkSpecialImage> SkColorFilterImageFilter::onFilterImage(const Context& ctx,
87
4.92k
                                                              SkIPoint* offset) const {
88
4.92k
    SkIPoint inputOffset = SkIPoint::Make(0, 0);
89
4.92k
    sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));
90
91
4.92k
    SkIRect inputBounds;
92
4.92k
    if (as_CFB(fColorFilter)->affectsTransparentBlack()) {
93
        // If the color filter affects transparent black, the bounds are the entire clip.
94
15
        inputBounds = ctx.clipBounds();
95
4.91k
    } else if (!input) {
96
7
        return nullptr;
97
4.90k
    } else {
98
4.90k
        inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
99
4.90k
                                        input->width(), input->height());
100
4.90k
    }
101
102
4.91k
    SkIRect bounds;
103
4.91k
    if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
104
1
        return nullptr;
105
1
    }
106
107
4.91k
    sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size()));
108
4.91k
    if (!surf) {
109
0
        return nullptr;
110
0
    }
111
112
4.91k
    SkCanvas* canvas = surf->getCanvas();
113
4.91k
    SkASSERT(canvas);
114
115
4.91k
    SkPaint paint;
116
117
4.91k
    paint.setBlendMode(SkBlendMode::kSrc);
118
4.91k
    paint.setColorFilter(fColorFilter);
119
120
    // TODO: it may not be necessary to clear or drawPaint inside the input bounds
121
    // (see skbug.com/5075)
122
4.91k
    if (as_CFB(fColorFilter)->affectsTransparentBlack()) {
123
        // The subsequent input->draw() call may not fill the entire canvas. For filters which
124
        // affect transparent black, ensure that the filter is applied everywhere.
125
15
        paint.setColor(SK_ColorTRANSPARENT);
126
15
        canvas->drawPaint(paint);
127
15
        paint.setColor(SK_ColorBLACK);
128
4.90k
    } else {
129
4.90k
        canvas->clear(0x0);
130
4.90k
    }
131
132
4.91k
    if (input) {
133
4.91k
        input->draw(canvas,
134
4.91k
                    SkIntToScalar(inputOffset.fX - bounds.fLeft),
135
4.91k
                    SkIntToScalar(inputOffset.fY - bounds.fTop),
136
4.91k
                    SkSamplingOptions(), &paint);
137
4.91k
    }
138
139
4.91k
    offset->fX = bounds.fLeft;
140
4.91k
    offset->fY = bounds.fTop;
141
4.91k
    return surf->makeImageSnapshot();
142
4.91k
}
143
144
68.9k
bool SkColorFilterImageFilter::onIsColorFilterNode(SkColorFilter** filter) const {
145
68.9k
    SkASSERT(1 == this->countInputs());
146
68.9k
    if (!this->cropRectIsSet()) {
147
59.8k
        if (filter) {
148
59.8k
            *filter = SkRef(fColorFilter.get());
149
59.8k
        }
150
59.8k
        return true;
151
59.8k
    }
152
9.08k
    return false;
153
9.08k
}
154
155
37.7k
bool SkColorFilterImageFilter::onAffectsTransparentBlack() const {
156
37.7k
    return as_CFB(fColorFilter)->affectsTransparentBlack();
157
37.7k
}