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 "SkColorFilter.h"
10 #include "SkColorPriv.h"
11 #include "SkModeColorFilter.h"
12 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.h"
14 #include "SkUtils.h"
15 #include "SkString.h"
16 #include "SkValidationUtils.h"
17 #include "SkPM4f.h"
18
19 //////////////////////////////////////////////////////////////////////////////////////////////////
20
21 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const22 void SkModeColorFilter::toString(SkString* str) const {
23 str->append("SkModeColorFilter: color: 0x");
24 str->appendHex(fColor);
25 str->append(" mode: ");
26 str->append(SkXfermode::ModeName(fMode));
27 }
28 #endif
29
asColorMode(SkColor * color,SkXfermode::Mode * mode) const30 bool SkModeColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const {
31 if (color) {
32 *color = fColor;
33 }
34 if (mode) {
35 *mode = fMode;
36 }
37 return true;
38 }
39
getFlags() const40 uint32_t SkModeColorFilter::getFlags() const {
41 uint32_t flags = 0;
42 switch (fMode) {
43 case SkXfermode::kDst_Mode: //!< [Da, Dc]
44 case SkXfermode::kSrcATop_Mode: //!< [Da, Sc * Da + (1 - Sa) * Dc]
45 flags |= kAlphaUnchanged_Flag;
46 default:
47 break;
48 }
49 return flags;
50 }
51
filterSpan(const SkPMColor shader[],int count,SkPMColor result[]) const52 void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
53 SkPMColor color = fPMColor;
54 SkXfermodeProc proc = fProc;
55
56 for (int i = 0; i < count; i++) {
57 result[i] = proc(color, shader[i]);
58 }
59 }
60
filterSpan4f(const SkPM4f shader[],int count,SkPM4f result[]) const61 void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
62 SkPM4f color = SkPM4f::FromPMColor(fPMColor);
63 SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode);
64
65 for (int i = 0; i < count; i++) {
66 result[i] = proc(color, shader[i]);
67 }
68 }
69
flatten(SkWriteBuffer & buffer) const70 void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
71 buffer.writeColor(fColor);
72 buffer.writeUInt(fMode);
73 }
74
updateCache()75 void SkModeColorFilter::updateCache() {
76 fPMColor = SkPreMultiplyColor(fColor);
77 fProc = SkXfermode::GetProc(fMode);
78 }
79
CreateProc(SkReadBuffer & buffer)80 SkFlattenable* SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
81 SkColor color = buffer.readColor();
82 SkXfermode::Mode mode = (SkXfermode::Mode)buffer.readUInt();
83 return SkColorFilter::CreateModeFilter(color, mode);
84 }
85
86 ///////////////////////////////////////////////////////////////////////////////
87 #if SK_SUPPORT_GPU
88 #include "GrBlend.h"
89 #include "GrInvariantOutput.h"
90 #include "effects/GrXfermodeFragmentProcessor.h"
91 #include "effects/GrConstColorProcessor.h"
92 #include "SkGr.h"
93
asFragmentProcessor(GrContext *) const94 const GrFragmentProcessor* SkModeColorFilter::asFragmentProcessor(GrContext*) const {
95 if (SkXfermode::kDst_Mode == fMode) {
96 return nullptr;
97 }
98
99 SkAutoTUnref<const GrFragmentProcessor> constFP(
100 GrConstColorProcessor::Create(SkColorToPremulGrColor(fColor),
101 GrConstColorProcessor::kIgnore_InputMode));
102 const GrFragmentProcessor* fp =
103 GrXfermodeFragmentProcessor::CreateFromSrcProcessor(constFP, fMode);
104 if (!fp) {
105 return nullptr;
106 }
107 #ifdef SK_DEBUG
108 // With a solid color input this should always be able to compute the blended color
109 // (at least for coeff modes)
110 if (fMode <= SkXfermode::kLastCoeffMode) {
111 static SkRandom gRand;
112 GrInvariantOutput io(GrPremulColor(gRand.nextU()), kRGBA_GrColorComponentFlags,
113 false);
114 fp->computeInvariantOutput(&io);
115 SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags);
116 }
117 #endif
118 return fp;
119 }
120
121 #endif
122
123 ///////////////////////////////////////////////////////////////////////////////
124
125 class Src_SkModeColorFilter final : public SkModeColorFilter {
126 public:
Src_SkModeColorFilter(SkColor color)127 Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {}
128
filterSpan(const SkPMColor shader[],int count,SkPMColor result[]) const129 void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
130 sk_memset32(result, this->getPMColor(), count);
131 }
132
133 private:
134 typedef SkModeColorFilter INHERITED;
135 };
136
137 class SrcOver_SkModeColorFilter final : public SkModeColorFilter {
138 public:
SrcOver_SkModeColorFilter(SkColor color)139 SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrcOver_Mode) { }
140
filterSpan(const SkPMColor shader[],int count,SkPMColor result[]) const141 void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
142 SkBlitRow::Color32(result, shader, count, this->getPMColor());
143 }
144
145 private:
146 typedef SkModeColorFilter INHERITED;
147 };
148
149 ///////////////////////////////////////////////////////////////////////////////
150
CreateModeFilter(SkColor color,SkXfermode::Mode mode)151 SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color, SkXfermode::Mode mode) {
152 if (!SkIsValidMode(mode)) {
153 return nullptr;
154 }
155
156 unsigned alpha = SkColorGetA(color);
157
158 // first collaps some modes if possible
159
160 if (SkXfermode::kClear_Mode == mode) {
161 color = 0;
162 mode = SkXfermode::kSrc_Mode;
163 } else if (SkXfermode::kSrcOver_Mode == mode) {
164 if (0 == alpha) {
165 mode = SkXfermode::kDst_Mode;
166 } else if (255 == alpha) {
167 mode = SkXfermode::kSrc_Mode;
168 }
169 // else just stay srcover
170 }
171
172 // weed out combinations that are noops, and just return null
173 if (SkXfermode::kDst_Mode == mode ||
174 (0 == alpha && (SkXfermode::kSrcOver_Mode == mode ||
175 SkXfermode::kDstOver_Mode == mode ||
176 SkXfermode::kDstOut_Mode == mode ||
177 SkXfermode::kSrcATop_Mode == mode ||
178 SkXfermode::kXor_Mode == mode ||
179 SkXfermode::kDarken_Mode == mode)) ||
180 (0xFF == alpha && SkXfermode::kDstIn_Mode == mode)) {
181 return nullptr;
182 }
183
184 switch (mode) {
185 case SkXfermode::kSrc_Mode:
186 return new Src_SkModeColorFilter(color);
187 case SkXfermode::kSrcOver_Mode:
188 return new SrcOver_SkModeColorFilter(color);
189 default:
190 return SkModeColorFilter::Create(color, mode);
191 }
192 }
193