/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 | } |