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 "SkArenaAlloc.h"
9 #include "SkBlendModePriv.h"
10 #include "SkBlitRow.h"
11 #include "SkColorFilter.h"
12 #include "SkColorPriv.h"
13 #include "SkColorSpaceXformer.h"
14 #include "SkModeColorFilter.h"
15 #include "SkPM4f.h"
16 #include "SkPM4fPriv.h"
17 #include "SkRandom.h"
18 #include "SkRasterPipeline.h"
19 #include "SkReadBuffer.h"
20 #include "SkString.h"
21 #include "SkUtils.h"
22 #include "SkValidationUtils.h"
23 #include "SkWriteBuffer.h"
24
25 //////////////////////////////////////////////////////////////////////////////////////////////////
26
SkModeColorFilter(SkColor color,SkBlendMode mode)27 SkModeColorFilter::SkModeColorFilter(SkColor color, SkBlendMode mode) {
28 fColor = color;
29 fMode = mode;
30 // cache
31 fPMColor = SkPreMultiplyColor(fColor);
32 }
33
34 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const35 void SkModeColorFilter::toString(SkString* str) const {
36 str->append("SkModeColorFilter: color: 0x");
37 str->appendHex(fColor);
38 str->append(" mode: ");
39 str->append(SkBlendMode_Name(fMode));
40 }
41 #endif
42
asColorMode(SkColor * color,SkBlendMode * mode) const43 bool SkModeColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const {
44 if (color) {
45 *color = fColor;
46 }
47 if (mode) {
48 *mode = fMode;
49 }
50 return true;
51 }
52
getFlags() const53 uint32_t SkModeColorFilter::getFlags() const {
54 uint32_t flags = 0;
55 switch (fMode) {
56 case SkBlendMode::kDst: //!< [Da, Dc]
57 case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc]
58 flags |= kAlphaUnchanged_Flag;
59 default:
60 break;
61 }
62 return flags;
63 }
64
flatten(SkWriteBuffer & buffer) const65 void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
66 buffer.writeColor(fColor);
67 buffer.writeUInt((int)fMode);
68 }
69
CreateProc(SkReadBuffer & buffer)70 sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
71 SkColor color = buffer.readColor();
72 SkBlendMode mode = (SkBlendMode)buffer.readUInt();
73 return SkColorFilter::MakeModeFilter(color, mode);
74 }
75
onAppendStages(SkRasterPipeline * p,SkColorSpace * dst,SkArenaAlloc * scratch,bool shaderIsOpaque) const76 void SkModeColorFilter::onAppendStages(SkRasterPipeline* p,
77 SkColorSpace* dst,
78 SkArenaAlloc* scratch,
79 bool shaderIsOpaque) const {
80 p->append(SkRasterPipeline::move_src_dst);
81 p->append_uniform_color(scratch, SkPM4f_from_SkColor(fColor, dst));
82 SkBlendMode_AppendStages(fMode, p);
83 }
84
onMakeColorSpace(SkColorSpaceXformer * xformer) const85 sk_sp<SkColorFilter> SkModeColorFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
86 SkColor color = xformer->apply(fColor);
87 if (color != fColor) {
88 return SkColorFilter::MakeModeFilter(color, fMode);
89 }
90 return this->INHERITED::onMakeColorSpace(xformer);
91 }
92
93 ///////////////////////////////////////////////////////////////////////////////
94 #if SK_SUPPORT_GPU
95 #include "GrBlend.h"
96 #include "effects/GrXfermodeFragmentProcessor.h"
97 #include "effects/GrConstColorProcessor.h"
98 #include "SkGr.h"
99
asFragmentProcessor(GrContext *,SkColorSpace * dstColorSpace) const100 sk_sp<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
101 GrContext*, SkColorSpace* dstColorSpace) const {
102 if (SkBlendMode::kDst == fMode) {
103 return nullptr;
104 }
105
106 sk_sp<GrFragmentProcessor> constFP(
107 GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpace),
108 GrConstColorProcessor::kIgnore_InputMode));
109 sk_sp<GrFragmentProcessor> fp(
110 GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode));
111 if (!fp) {
112 return nullptr;
113 }
114 #ifdef SK_DEBUG
115 // With a solid color input this should always be able to compute the blended color
116 // (at least for coeff modes)
117 if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) {
118 SkASSERT(fp->hasConstantOutputForConstantInput());
119 }
120 #endif
121 return fp;
122 }
123
124 #endif
125
126 ///////////////////////////////////////////////////////////////////////////////
127
MakeModeFilter(SkColor color,SkBlendMode mode)128 sk_sp<SkColorFilter> SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) {
129 if (!SkIsValidMode(mode)) {
130 return nullptr;
131 }
132
133 unsigned alpha = SkColorGetA(color);
134
135 // first collaps some modes if possible
136
137 if (SkBlendMode::kClear == mode) {
138 color = 0;
139 mode = SkBlendMode::kSrc;
140 } else if (SkBlendMode::kSrcOver == mode) {
141 if (0 == alpha) {
142 mode = SkBlendMode::kDst;
143 } else if (255 == alpha) {
144 mode = SkBlendMode::kSrc;
145 }
146 // else just stay srcover
147 }
148
149 // weed out combinations that are noops, and just return null
150 if (SkBlendMode::kDst == mode ||
151 (0 == alpha && (SkBlendMode::kSrcOver == mode ||
152 SkBlendMode::kDstOver == mode ||
153 SkBlendMode::kDstOut == mode ||
154 SkBlendMode::kSrcATop == mode ||
155 SkBlendMode::kXor == mode ||
156 SkBlendMode::kDarken == mode)) ||
157 (0xFF == alpha && SkBlendMode::kDstIn == mode)) {
158 return nullptr;
159 }
160
161 return SkModeColorFilter::Make(color, mode);
162 }
163