Line data Source code
1 : /*
2 : * Copyright 2006 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 "SkBlitRow.h"
9 : #include "SkBlendModePriv.h"
10 : #include "SkColorFilter.h"
11 : #include "SkColorPriv.h"
12 : #include "SkArenaAlloc.h"
13 : #include "SkModeColorFilter.h"
14 : #include "SkPM4fPriv.h"
15 : #include "SkRasterPipeline.h"
16 : #include "SkReadBuffer.h"
17 : #include "SkWriteBuffer.h"
18 : #include "SkUtils.h"
19 : #include "SkRandom.h"
20 : #include "SkString.h"
21 : #include "SkValidationUtils.h"
22 : #include "SkPM4f.h"
23 :
24 : //////////////////////////////////////////////////////////////////////////////////////////////////
25 :
26 : #ifndef SK_IGNORE_TO_STRING
27 0 : void SkModeColorFilter::toString(SkString* str) const {
28 0 : str->append("SkModeColorFilter: color: 0x");
29 0 : str->appendHex(fColor);
30 0 : str->append(" mode: ");
31 0 : str->append(SkXfermode::ModeName(fMode));
32 0 : }
33 : #endif
34 :
35 0 : bool SkModeColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const {
36 0 : if (color) {
37 0 : *color = fColor;
38 : }
39 0 : if (mode) {
40 0 : *mode = fMode;
41 : }
42 0 : return true;
43 : }
44 :
45 0 : uint32_t SkModeColorFilter::getFlags() const {
46 0 : uint32_t flags = 0;
47 0 : switch (fMode) {
48 : case SkBlendMode::kDst: //!< [Da, Dc]
49 : case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc]
50 0 : flags |= kAlphaUnchanged_Flag;
51 : default:
52 0 : break;
53 : }
54 0 : return flags;
55 : }
56 :
57 0 : void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
58 0 : SkPMColor color = fPMColor;
59 0 : SkXfermodeProc proc = fProc;
60 :
61 0 : for (int i = 0; i < count; i++) {
62 0 : result[i] = proc(color, shader[i]);
63 : }
64 0 : }
65 :
66 0 : void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
67 0 : SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode);
68 0 : auto pm4f = SkColor4f::FromColor(fColor).premul();
69 0 : for (int i = 0; i < count; i++) {
70 0 : result[i] = proc(pm4f, shader[i]);
71 : }
72 0 : }
73 :
74 0 : void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
75 0 : buffer.writeColor(fColor);
76 0 : buffer.writeUInt((int)fMode);
77 0 : }
78 :
79 0 : void SkModeColorFilter::updateCache() {
80 0 : fPMColor = SkPreMultiplyColor(fColor);
81 0 : fProc = SkXfermode::GetProc(fMode);
82 0 : }
83 :
84 0 : sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
85 0 : SkColor color = buffer.readColor();
86 0 : SkBlendMode mode = (SkBlendMode)buffer.readUInt();
87 0 : return SkColorFilter::MakeModeFilter(color, mode);
88 : }
89 :
90 0 : bool SkModeColorFilter::onAppendStages(SkRasterPipeline* p,
91 : SkColorSpace* dst,
92 : SkArenaAlloc* scratch,
93 : bool shaderIsOpaque) const {
94 0 : auto color = scratch->make<SkPM4f>(SkPM4f_from_SkColor(fColor, dst));
95 :
96 0 : p->append(SkRasterPipeline::move_src_dst);
97 0 : p->append(SkRasterPipeline::constant_color, color);
98 0 : auto mode = (SkBlendMode)fMode;
99 0 : if (!SkBlendMode_AppendStages(mode, p)) {
100 0 : return false;
101 : }
102 0 : if (SkBlendMode_CanOverflow(mode)) { p->append(SkRasterPipeline::clamp_a); }
103 0 : return true;
104 : }
105 :
106 : ///////////////////////////////////////////////////////////////////////////////
107 : #if SK_SUPPORT_GPU
108 : #include "GrBlend.h"
109 : #include "effects/GrXfermodeFragmentProcessor.h"
110 : #include "effects/GrConstColorProcessor.h"
111 : #include "SkGr.h"
112 :
113 0 : sk_sp<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
114 : GrContext*, SkColorSpace* dstColorSpace) const {
115 0 : if (SkBlendMode::kDst == fMode) {
116 0 : return nullptr;
117 : }
118 :
119 : sk_sp<GrFragmentProcessor> constFP(
120 0 : GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpace),
121 0 : GrConstColorProcessor::kIgnore_InputMode));
122 : sk_sp<GrFragmentProcessor> fp(
123 0 : GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode));
124 0 : if (!fp) {
125 0 : return nullptr;
126 : }
127 : #ifdef SK_DEBUG
128 : // With a solid color input this should always be able to compute the blended color
129 : // (at least for coeff modes)
130 0 : if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) {
131 0 : SkASSERT(fp->hasConstantOutputForConstantInput());
132 : }
133 : #endif
134 0 : return fp;
135 : }
136 :
137 : #endif
138 :
139 : ///////////////////////////////////////////////////////////////////////////////
140 :
141 0 : class Src_SkModeColorFilter final : public SkModeColorFilter {
142 : public:
143 0 : Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrc) {}
144 :
145 0 : void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
146 0 : sk_memset32(result, this->getPMColor(), count);
147 0 : }
148 :
149 : private:
150 : typedef SkModeColorFilter INHERITED;
151 : };
152 :
153 0 : class SrcOver_SkModeColorFilter final : public SkModeColorFilter {
154 : public:
155 0 : SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkBlendMode::kSrcOver) { }
156 :
157 0 : void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
158 0 : SkBlitRow::Color32(result, shader, count, this->getPMColor());
159 0 : }
160 :
161 : private:
162 : typedef SkModeColorFilter INHERITED;
163 : };
164 :
165 : ///////////////////////////////////////////////////////////////////////////////
166 :
167 0 : sk_sp<SkColorFilter> SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) {
168 0 : if (!SkIsValidMode(mode)) {
169 0 : return nullptr;
170 : }
171 :
172 0 : unsigned alpha = SkColorGetA(color);
173 :
174 : // first collaps some modes if possible
175 :
176 0 : if (SkBlendMode::kClear == mode) {
177 0 : color = 0;
178 0 : mode = SkBlendMode::kSrc;
179 0 : } else if (SkBlendMode::kSrcOver == mode) {
180 0 : if (0 == alpha) {
181 0 : mode = SkBlendMode::kDst;
182 0 : } else if (255 == alpha) {
183 0 : mode = SkBlendMode::kSrc;
184 : }
185 : // else just stay srcover
186 : }
187 :
188 : // weed out combinations that are noops, and just return null
189 0 : if (SkBlendMode::kDst == mode ||
190 0 : (0 == alpha && (SkBlendMode::kSrcOver == mode ||
191 0 : SkBlendMode::kDstOver == mode ||
192 0 : SkBlendMode::kDstOut == mode ||
193 0 : SkBlendMode::kSrcATop == mode ||
194 0 : SkBlendMode::kXor == mode ||
195 0 : SkBlendMode::kDarken == mode)) ||
196 0 : (0xFF == alpha && SkBlendMode::kDstIn == mode)) {
197 0 : return nullptr;
198 : }
199 :
200 0 : switch (mode) {
201 : case SkBlendMode::kSrc:
202 0 : return sk_make_sp<Src_SkModeColorFilter>(color);
203 : case SkBlendMode::kSrcOver:
204 0 : return sk_make_sp<SrcOver_SkModeColorFilter>(color);
205 : default:
206 0 : return SkModeColorFilter::Make(color, mode);
207 : }
208 : }
|