blob: 43df21555b00fbca279d91fa3f1fc3d4b8670862 [file] [log] [blame]
reed@android.com845fdac2009-06-23 03:01:32 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com845fdac2009-06-23 03:01:32 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com845fdac2009-06-23 03:01:32 +00006 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00007
reed@android.comc4cae852009-09-23 15:06:10 +00008#include "SkBlitRow.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkColorFilter.h"
10#include "SkColorPriv.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkUtils.h"
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000014#include "SkString.h"
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +000015#include "SkValidationUtils.h"
reed@google.com31b30442014-02-06 20:59:47 +000016#include "SkColorMatrixFilter.h"
17
reed@google.com43c50c82011-04-14 15:50:52 +000018#define ILLEGAL_XFERMODE_MODE ((SkXfermode::Mode)-1)
19
20// baseclass for filters that store a color and mode
21class SkModeColorFilter : public SkColorFilter {
22public:
23 SkModeColorFilter(SkColor color) {
24 fColor = color;
25 fMode = ILLEGAL_XFERMODE_MODE;
reed@google.com8b0d0f62012-06-04 18:10:33 +000026 this->updateCache();
reed@google.com43c50c82011-04-14 15:50:52 +000027 }
28
29 SkModeColorFilter(SkColor color, SkXfermode::Mode mode) {
30 fColor = color;
31 fMode = mode;
reed@google.com8b0d0f62012-06-04 18:10:33 +000032 this->updateCache();
reed@google.com43c50c82011-04-14 15:50:52 +000033 };
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000034
reed@google.com8b0d0f62012-06-04 18:10:33 +000035 SkColor getColor() const { return fColor; }
36 SkXfermode::Mode getMode() const { return fMode; }
37 bool isModeValid() const { return ILLEGAL_XFERMODE_MODE != fMode; }
38 SkPMColor getPMColor() const { return fPMColor; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000039
reed@google.combada6442012-12-17 20:21:44 +000040 virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode) const SK_OVERRIDE {
reed@google.com43c50c82011-04-14 15:50:52 +000041 if (ILLEGAL_XFERMODE_MODE == fMode) {
42 return false;
43 }
44
45 if (color) {
46 *color = fColor;
47 }
48 if (mode) {
49 *mode = fMode;
50 }
51 return true;
52 }
53
reed@google.combada6442012-12-17 20:21:44 +000054 virtual uint32_t getFlags() const SK_OVERRIDE {
reed@google.com8b0d0f62012-06-04 18:10:33 +000055 return fProc16 ? (kAlphaUnchanged_Flag | kHasFilter16_Flag) : 0;
56 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000057
reed@google.com8b0d0f62012-06-04 18:10:33 +000058 virtual void filterSpan(const SkPMColor shader[], int count,
reed@google.combada6442012-12-17 20:21:44 +000059 SkPMColor result[]) const SK_OVERRIDE {
reed@google.com8b0d0f62012-06-04 18:10:33 +000060 SkPMColor color = fPMColor;
61 SkXfermodeProc proc = fProc;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000062
reed@google.com8b0d0f62012-06-04 18:10:33 +000063 for (int i = 0; i < count; i++) {
64 result[i] = proc(color, shader[i]);
65 }
66 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000067
reed@google.com8b0d0f62012-06-04 18:10:33 +000068 virtual void filterSpan16(const uint16_t shader[], int count,
reed@google.combada6442012-12-17 20:21:44 +000069 uint16_t result[]) const SK_OVERRIDE {
reed@google.com8b0d0f62012-06-04 18:10:33 +000070 SkASSERT(this->getFlags() & kHasFilter16_Flag);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000071
reed@google.com8b0d0f62012-06-04 18:10:33 +000072 SkPMColor color = fPMColor;
73 SkXfermodeProc16 proc16 = fProc16;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000074
reed@google.com8b0d0f62012-06-04 18:10:33 +000075 for (int i = 0; i < count; i++) {
76 result[i] = proc16(color, shader[i]);
77 }
78 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000079
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +000080#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000081 virtual void toString(SkString* str) const SK_OVERRIDE {
82 str->append("SkModeColorFilter: color: 0x");
83 str->appendHex(fColor);
84 str->append(" mode: ");
85 str->append(SkXfermode::ModeName(fMode));
86 }
87#endif
88
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000089#if SK_SUPPORT_GPU
bsalomon97b9ab72014-07-08 06:52:35 -070090 virtual GrEffect* asNewEffect(GrContext*) const SK_OVERRIDE;
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000091#endif
reed@google.com8b0d0f62012-06-04 18:10:33 +000092 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter)
reed@google.com43c50c82011-04-14 15:50:52 +000093
reed@android.com8a1c16f2008-12-17 15:59:43 +000094protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000095 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000096 this->INHERITED::flatten(buffer);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000097 buffer.writeColor(fColor);
98 buffer.writeUInt(fMode);
reed@google.com43c50c82011-04-14 15:50:52 +000099 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000100
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000101 SkModeColorFilter(SkReadBuffer& buffer) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000102 fColor = buffer.readColor();
103 fMode = (SkXfermode::Mode)buffer.readUInt();
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +0000104 if (buffer.isValid()) {
105 this->updateCache();
106 buffer.validate(SkIsValidMode(fMode));
107 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 }
reed@android.com845fdac2009-06-23 03:01:32 +0000109
reed@google.com43c50c82011-04-14 15:50:52 +0000110private:
111 SkColor fColor;
112 SkXfermode::Mode fMode;
reed@google.com8b0d0f62012-06-04 18:10:33 +0000113 // cache
114 SkPMColor fPMColor;
115 SkXfermodeProc fProc;
116 SkXfermodeProc16 fProc16;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000117
reed@google.com8b0d0f62012-06-04 18:10:33 +0000118 void updateCache() {
119 fPMColor = SkPreMultiplyColor(fColor);
120 fProc = SkXfermode::GetProc(fMode);
121 fProc16 = SkXfermode::GetProc16(fMode, fColor);
122 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000123
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000124 typedef SkColorFilter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125};
126
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000127///////////////////////////////////////////////////////////////////////////////
128#if SK_SUPPORT_GPU
129#include "GrBlend.h"
130#include "GrEffect.h"
131#include "GrEffectUnitTest.h"
132#include "GrTBackendEffectFactory.h"
133#include "gl/GrGLEffect.h"
bsalomon848faf02014-07-11 10:01:02 -0700134#include "gl/GrGLShaderBuilder.h"
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000135#include "SkGr.h"
136
137namespace {
138/**
139 * A definition of blend equation for one coefficient. Generates a
140 * blend_coeff * value "expression".
141 */
142template<typename ColorExpr>
143static inline ColorExpr blend_term(SkXfermode::Coeff coeff,
144 const ColorExpr& src,
145 const ColorExpr& dst,
146 const ColorExpr& value) {
147 switch (coeff) {
148 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000149 SkFAIL("Unexpected xfer coeff.");
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000150 case SkXfermode::kZero_Coeff: /** 0 */
151 return ColorExpr(0);
152 case SkXfermode::kOne_Coeff: /** 1 */
153 return value;
154 case SkXfermode::kSC_Coeff:
155 return src * value;
156 case SkXfermode::kISC_Coeff:
157 return (ColorExpr(1) - src) * dst;
158 case SkXfermode::kDC_Coeff:
159 return dst * value;
160 case SkXfermode::kIDC_Coeff:
161 return (ColorExpr(1) - dst) * value;
162 case SkXfermode::kSA_Coeff: /** src alpha */
163 return src.a() * value;
164 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
165 return (typename ColorExpr::AExpr(1) - src.a()) * value;
166 case SkXfermode::kDA_Coeff: /** dst alpha */
167 return dst.a() * value;
168 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
169 return (typename ColorExpr::AExpr(1) - dst.a()) * value;
170 }
171}
172/**
173 * Creates a color filter expression which modifies the color by
174 * the specified color filter.
175 */
176template <typename ColorExpr>
177static inline ColorExpr color_filter_expression(const SkXfermode::Mode& mode,
178 const ColorExpr& filterColor,
179 const ColorExpr& inColor) {
180 SkXfermode::Coeff colorCoeff;
181 SkXfermode::Coeff filterColorCoeff;
182 SkAssertResult(SkXfermode::ModeAsCoeff(mode, &filterColorCoeff, &colorCoeff));
183 return blend_term(colorCoeff, filterColor, inColor, inColor) +
184 blend_term(filterColorCoeff, filterColor, inColor, filterColor);
185}
186
187}
188
189class ModeColorFilterEffect : public GrEffect {
190public:
bsalomon83d081a2014-07-08 09:56:10 -0700191 static GrEffect* Create(const GrColor& c, SkXfermode::Mode mode) {
commit-bot@chromium.orga93f4e72013-11-05 15:47:48 +0000192 // TODO: Make the effect take the coeffs rather than mode since we already do the
193 // conversion here.
194 SkXfermode::Coeff srcCoeff, dstCoeff;
195 if (!SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) {
196 SkDebugf("Failing to create color filter for mode %d\n", mode);
197 return NULL;
198 }
bsalomon55fad7a2014-07-08 07:34:20 -0700199 return SkNEW_ARGS(ModeColorFilterEffect, (c, mode));
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000200 }
201
202 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
203
204 bool willUseFilterColor() const {
205 SkXfermode::Coeff dstCoeff;
206 SkXfermode::Coeff srcCoeff;
207 SkAssertResult(SkXfermode::ModeAsCoeff(fMode, &srcCoeff, &dstCoeff));
208 if (SkXfermode::kZero_Coeff == srcCoeff) {
209 return GrBlendCoeffRefsSrc(sk_blend_to_grblend(dstCoeff));
210 }
211 return true;
212 }
213
214 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
215 return GrTBackendEffectFactory<ModeColorFilterEffect>::getInstance();
216 }
217
218 static const char* Name() { return "ModeColorFilterEffect"; }
219
220 SkXfermode::Mode mode() const { return fMode; }
221 GrColor color() const { return fColor; }
222
223 class GLEffect : public GrGLEffect {
224 public:
225 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
226 : INHERITED(factory) {
227 }
228
229 virtual void emitCode(GrGLShaderBuilder* builder,
230 const GrDrawEffect& drawEffect,
bsalomon63e99f72014-07-21 08:03:14 -0700231 const GrEffectKey& key,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000232 const char* outputColor,
233 const char* inputColor,
234 const TransformedCoordsArray& coords,
235 const TextureSamplerArray& samplers) SK_OVERRIDE {
236 SkXfermode::Mode mode = drawEffect.castEffect<ModeColorFilterEffect>().mode();
237
238 SkASSERT(SkXfermode::kDst_Mode != mode);
239 const char* colorFilterColorUniName = NULL;
240 if (drawEffect.castEffect<ModeColorFilterEffect>().willUseFilterColor()) {
241 fFilterColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
242 kVec4f_GrSLType, "FilterColor",
243 &colorFilterColorUniName);
244 }
245
246 GrGLSLExpr4 filter =
247 color_filter_expression(mode, GrGLSLExpr4(colorFilterColorUniName), GrGLSLExpr4(inputColor));
248
249 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, filter.c_str());
250 }
251
bsalomon63e99f72014-07-21 08:03:14 -0700252 static void GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&,
253 GrEffectKeyBuilder* b) {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000254 const ModeColorFilterEffect& colorModeFilter = drawEffect.castEffect<ModeColorFilterEffect>();
255 // The SL code does not depend on filter color at the moment, so no need to represent it
256 // in the key.
bsalomon63e99f72014-07-21 08:03:14 -0700257 b->add32(colorModeFilter.mode());
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000258 }
259
260 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) SK_OVERRIDE {
261 if (fFilterColorUni.isValid()) {
262 const ModeColorFilterEffect& colorModeFilter = drawEffect.castEffect<ModeColorFilterEffect>();
263 GrGLfloat c[4];
264 GrColorToRGBAFloat(colorModeFilter.color(), c);
commit-bot@chromium.orgd3baf202013-11-07 22:06:08 +0000265 uman.set4fv(fFilterColorUni, 1, c);
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000266 }
267 }
268
269 private:
270
271 GrGLUniformManager::UniformHandle fFilterColorUni;
272 typedef GrGLEffect INHERITED;
273 };
274
275 GR_DECLARE_EFFECT_TEST;
276
277private:
278 ModeColorFilterEffect(GrColor color, SkXfermode::Mode mode)
279 : fMode(mode),
280 fColor(color) {
281
282 SkXfermode::Coeff dstCoeff;
283 SkXfermode::Coeff srcCoeff;
284 SkAssertResult(SkXfermode::ModeAsCoeff(fMode, &srcCoeff, &dstCoeff));
285 // These could be calculated from the blend equation with template trickery..
286 if (SkXfermode::kZero_Coeff == dstCoeff && !GrBlendCoeffRefsDst(sk_blend_to_grblend(srcCoeff))) {
287 this->setWillNotUseInputColor();
288 }
289 }
290
291 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
292 const ModeColorFilterEffect& s = CastEffect<ModeColorFilterEffect>(other);
293 return fMode == s.fMode && fColor == s.fColor;
294 }
295
296 SkXfermode::Mode fMode;
297 GrColor fColor;
298
299 typedef GrEffect INHERITED;
300};
301
302namespace {
303
304/** Function color_component_to_int tries to reproduce the GLSL rounding. The spec doesn't specify
305 * to which direction the 0.5 goes.
306 */
307static inline int color_component_to_int(float value) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000308 return sk_float_round2int(SkTMax(0.f, SkTMin(1.f, value)) * 255.f);
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000309}
310
311/** MaskedColorExpr is used to evaluate the color and valid color component flags through the
312 * blending equation. It has members similar to GrGLSLExpr so that it can be used with the
313 * templated helpers above.
314 */
315class MaskedColorExpr {
316public:
317 MaskedColorExpr(const float color[], uint32_t flags)
318 : fFlags(flags) {
319 fColor[0] = color[0];
320 fColor[1] = color[1];
321 fColor[2] = color[2];
322 fColor[3] = color[3];
323 }
324
325 MaskedColorExpr(float v, uint32_t flags = kRGBA_GrColorComponentFlags)
326 : fFlags(flags) {
327 fColor[0] = v;
328 fColor[1] = v;
329 fColor[2] = v;
330 fColor[3] = v;
331 }
332
333 MaskedColorExpr operator*(const MaskedColorExpr& other) const {
334 float tmp[4];
335 tmp[0] = fColor[0] * other.fColor[0];
336 tmp[1] = fColor[1] * other.fColor[1];
337 tmp[2] = fColor[2] * other.fColor[2];
338 tmp[3] = fColor[3] * other.fColor[3];
339
340 return MaskedColorExpr(tmp, fFlags & other.fFlags);
341 }
342
343 MaskedColorExpr operator+(const MaskedColorExpr& other) const {
344 float tmp[4];
345 tmp[0] = fColor[0] + other.fColor[0];
346 tmp[1] = fColor[1] + other.fColor[1];
347 tmp[2] = fColor[2] + other.fColor[2];
348 tmp[3] = fColor[3] + other.fColor[3];
349
350 return MaskedColorExpr(tmp, fFlags & other.fFlags);
351 }
352
353 MaskedColorExpr operator-(const MaskedColorExpr& other) const {
354 float tmp[4];
355 tmp[0] = fColor[0] - other.fColor[0];
356 tmp[1] = fColor[1] - other.fColor[1];
357 tmp[2] = fColor[2] - other.fColor[2];
358 tmp[3] = fColor[3] - other.fColor[3];
359
360 return MaskedColorExpr(tmp, fFlags & other.fFlags);
361 }
362
363 MaskedColorExpr a() const {
364 uint32_t flags = (fFlags & kA_GrColorComponentFlag) ? kRGBA_GrColorComponentFlags : 0;
365 return MaskedColorExpr(fColor[3], flags);
366 }
367
368 GrColor getColor() const {
369 return GrColorPackRGBA(color_component_to_int(fColor[0]),
370 color_component_to_int(fColor[1]),
371 color_component_to_int(fColor[2]),
372 color_component_to_int(fColor[3]));
373 }
374
375 uint32_t getValidComponents() const { return fFlags; }
376
377 typedef MaskedColorExpr AExpr;
378private:
379 float fColor[4];
380 uint32_t fFlags;
381};
382
383}
384
385void ModeColorFilterEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
386 float inputColor[4];
387 GrColorToRGBAFloat(*color, inputColor);
388 float filterColor[4];
389 GrColorToRGBAFloat(fColor, filterColor);
390 MaskedColorExpr result =
391 color_filter_expression(fMode,
392 MaskedColorExpr(filterColor, kRGBA_GrColorComponentFlags),
393 MaskedColorExpr(inputColor, *validFlags));
394
395 *color = result.getColor();
396 *validFlags = result.getValidComponents();
397}
398
399GR_DEFINE_EFFECT_TEST(ModeColorFilterEffect);
bsalomon83d081a2014-07-08 09:56:10 -0700400GrEffect* ModeColorFilterEffect::TestCreate(SkRandom* rand,
401 GrContext*,
402 const GrDrawTargetCaps&,
403 GrTexture*[]) {
commit-bot@chromium.org23267ce2013-10-24 13:29:38 +0000404 SkXfermode::Mode mode = SkXfermode::kDst_Mode;
405 while (SkXfermode::kDst_Mode == mode) {
406 mode = static_cast<SkXfermode::Mode>(rand->nextRangeU(0, SkXfermode::kLastCoeffMode));
407 }
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000408 GrColor color = rand->nextU();
commit-bot@chromium.org23267ce2013-10-24 13:29:38 +0000409 return ModeColorFilterEffect::Create(color, mode);
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000410}
411
bsalomon97b9ab72014-07-08 06:52:35 -0700412GrEffect* SkModeColorFilter::asNewEffect(GrContext*) const {
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000413 if (SkXfermode::kDst_Mode != fMode) {
414 return ModeColorFilterEffect::Create(SkColor2GrColor(fColor), fMode);
415 }
416 return NULL;
417}
418
419#endif
420
421///////////////////////////////////////////////////////////////////////////////
422
reed@google.com43c50c82011-04-14 15:50:52 +0000423class Src_SkModeColorFilter : public SkModeColorFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424public:
reed@google.com43c50c82011-04-14 15:50:52 +0000425 Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000427 virtual uint32_t getFlags() const SK_OVERRIDE {
reed@google.com8b0d0f62012-06-04 18:10:33 +0000428 if (SkGetPackedA32(this->getPMColor()) == 0xFF) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 return kAlphaUnchanged_Flag | kHasFilter16_Flag;
reed@android.com845fdac2009-06-23 03:01:32 +0000430 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431 return 0;
reed@android.com845fdac2009-06-23 03:01:32 +0000432 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000433 }
434
reed@android.com845fdac2009-06-23 03:01:32 +0000435 virtual void filterSpan(const SkPMColor shader[], int count,
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000436 SkPMColor result[]) const SK_OVERRIDE {
reed@google.com8b0d0f62012-06-04 18:10:33 +0000437 sk_memset32(result, this->getPMColor(), count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 }
439
reed@android.com845fdac2009-06-23 03:01:32 +0000440 virtual void filterSpan16(const uint16_t shader[], int count,
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000441 uint16_t result[]) const SK_OVERRIDE {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442 SkASSERT(this->getFlags() & kHasFilter16_Flag);
reed@google.com8b0d0f62012-06-04 18:10:33 +0000443 sk_memset16(result, SkPixel32ToPixel16(this->getPMColor()), count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444 }
445
djsollen@google.comba28d032012-03-26 17:57:35 +0000446 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Src_SkModeColorFilter)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000447
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000449 Src_SkModeColorFilter(SkReadBuffer& buffer)
reed@android.com845fdac2009-06-23 03:01:32 +0000450 : INHERITED(buffer) {}
reed@android.com845fdac2009-06-23 03:01:32 +0000451
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000452private:
reed@google.com43c50c82011-04-14 15:50:52 +0000453 typedef SkModeColorFilter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454};
455
reed@google.com43c50c82011-04-14 15:50:52 +0000456class SrcOver_SkModeColorFilter : public SkModeColorFilter {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457public:
reed@google.com43c50c82011-04-14 15:50:52 +0000458 SrcOver_SkModeColorFilter(SkColor color)
459 : INHERITED(color, SkXfermode::kSrcOver_Mode) {
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000460 fColor32Proc = SkBlitRow::ColorProcFactory();
reed@google.com43c50c82011-04-14 15:50:52 +0000461 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000462
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000463 virtual uint32_t getFlags() const SK_OVERRIDE {
reed@google.com8b0d0f62012-06-04 18:10:33 +0000464 if (SkGetPackedA32(this->getPMColor()) == 0xFF) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465 return kAlphaUnchanged_Flag | kHasFilter16_Flag;
reed@android.com845fdac2009-06-23 03:01:32 +0000466 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467 return 0;
reed@android.com845fdac2009-06-23 03:01:32 +0000468 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000469 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000470
reed@android.com845fdac2009-06-23 03:01:32 +0000471 virtual void filterSpan(const SkPMColor shader[], int count,
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000472 SkPMColor result[]) const SK_OVERRIDE {
reed@google.com8b0d0f62012-06-04 18:10:33 +0000473 fColor32Proc(result, shader, count, this->getPMColor());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000474 }
475
reed@android.com845fdac2009-06-23 03:01:32 +0000476 virtual void filterSpan16(const uint16_t shader[], int count,
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000477 uint16_t result[]) const SK_OVERRIDE {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000478 SkASSERT(this->getFlags() & kHasFilter16_Flag);
reed@google.com8b0d0f62012-06-04 18:10:33 +0000479 sk_memset16(result, SkPixel32ToPixel16(this->getPMColor()), count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000480 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000481
djsollen@google.comba28d032012-03-26 17:57:35 +0000482 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SrcOver_SkModeColorFilter)
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000483
484protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000485 SrcOver_SkModeColorFilter(SkReadBuffer& buffer)
mike@reedtribe.org3eafe9b2012-12-24 18:11:05 +0000486 : INHERITED(buffer) {
487 fColor32Proc = SkBlitRow::ColorProcFactory();
488 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000489
490private:
491
senorblanco@chromium.org29e50542010-12-16 19:07:45 +0000492 SkBlitRow::ColorProc fColor32Proc;
reed@google.com43c50c82011-04-14 15:50:52 +0000493
494 typedef SkModeColorFilter INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495};
496
reed@google.com43c50c82011-04-14 15:50:52 +0000497///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000498
reed@android.com845fdac2009-06-23 03:01:32 +0000499SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color,
500 SkXfermode::Mode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501 unsigned alpha = SkColorGetA(color);
502
503 // first collaps some modes if possible
504
reed@android.com845fdac2009-06-23 03:01:32 +0000505 if (SkXfermode::kClear_Mode == mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506 color = 0;
reed@android.com845fdac2009-06-23 03:01:32 +0000507 mode = SkXfermode::kSrc_Mode;
508 } else if (SkXfermode::kSrcOver_Mode == mode) {
509 if (0 == alpha) {
510 mode = SkXfermode::kDst_Mode;
511 } else if (255 == alpha) {
512 mode = SkXfermode::kSrc_Mode;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000513 }
514 // else just stay srcover
515 }
516
517 // weed out combinations that are noops, and just return null
reed@android.com845fdac2009-06-23 03:01:32 +0000518 if (SkXfermode::kDst_Mode == mode ||
519 (0 == alpha && (SkXfermode::kSrcOver_Mode == mode ||
520 SkXfermode::kDstOver_Mode == mode ||
521 SkXfermode::kDstOut_Mode == mode ||
522 SkXfermode::kSrcATop_Mode == mode ||
523 SkXfermode::kXor_Mode == mode ||
524 SkXfermode::kDarken_Mode == mode)) ||
525 (0xFF == alpha && SkXfermode::kDstIn_Mode == mode)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000526 return NULL;
527 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000528
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529 switch (mode) {
reed@google.com43c50c82011-04-14 15:50:52 +0000530 case SkXfermode::kSrc_Mode:
531 return SkNEW_ARGS(Src_SkModeColorFilter, (color));
532 case SkXfermode::kSrcOver_Mode:
533 return SkNEW_ARGS(SrcOver_SkModeColorFilter, (color));
534 default:
reed@google.com8b0d0f62012-06-04 18:10:33 +0000535 return SkNEW_ARGS(SkModeColorFilter, (color, mode));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536 }
537}
538
reed@android.com845fdac2009-06-23 03:01:32 +0000539///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540
reed@google.com31b30442014-02-06 20:59:47 +0000541static SkScalar byte_to_scale(U8CPU byte) {
542 if (0xFF == byte) {
543 // want to get this exact
544 return 1;
545 } else {
546 return byte * 0.00392156862745f;
547 }
548}
549
reed@android.com845fdac2009-06-23 03:01:32 +0000550SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add) {
reed@google.com31b30442014-02-06 20:59:47 +0000551 SkColorMatrix matrix;
552 matrix.setScale(byte_to_scale(SkColorGetR(mul)),
553 byte_to_scale(SkColorGetG(mul)),
554 byte_to_scale(SkColorGetB(mul)),
555 1);
556 matrix.postTranslate(SkIntToScalar(SkColorGetR(add)),
557 SkIntToScalar(SkColorGetG(add)),
558 SkIntToScalar(SkColorGetB(add)),
559 0);
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000560 return SkColorMatrixFilter::Create(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561}
562
caryclark@google.comd26147a2011-12-15 14:16:43 +0000563SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
reed@google.com8b0d0f62012-06-04 18:10:33 +0000564 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
caryclark@google.comd26147a2011-12-15 14:16:43 +0000565 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Src_SkModeColorFilter)
566 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SrcOver_SkModeColorFilter)
caryclark@google.comd26147a2011-12-15 14:16:43 +0000567SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END