1/*
2* Copyright 2015 Google Inc.
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 "GrBlend.h"
9
10/**
11 * MaskedColor is used to evaluate the color and valid color component flags through the
12 * blending equation. Could possibly extend this to be used more broadly.
13 */
14class MaskedColor {
15public:
16    MaskedColor(GrColor color, GrColorComponentFlags flags)
17        : fColor(color)
18        , fFlags(flags) {}
19
20    MaskedColor() {}
21
22    void set(GrColor color, GrColorComponentFlags flags) {
23        fColor = color;
24        fFlags = flags;
25    }
26
27    static MaskedColor Invert(const MaskedColor& in) {
28        return MaskedColor(GrInvertColor(in.fColor), in.fFlags);
29    }
30
31    static MaskedColor ExtractAlpha(const MaskedColor& in) {
32        GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
33            kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
34        return MaskedColor(GrColorPackA4(GrColorUnpackA(in.fColor)), flags);
35    }
36
37    static MaskedColor ExtractInverseAlpha(const MaskedColor& in) {
38        GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
39            kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
40        return MaskedColor(GrColorPackA4(0xFF - GrColorUnpackA(in.fColor)), flags);
41    }
42
43    static MaskedColor Mul(const MaskedColor& a, const MaskedColor& b) {
44        GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0) |
45                                         b.componentsWithValue(0);
46        return MaskedColor(GrColorMul(a.fColor, b.fColor), outFlags);
47    }
48
49    static MaskedColor SatAdd(const MaskedColor& a, const MaskedColor& b) {
50        GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0xFF) |
51                                         b.componentsWithValue(0xFF);
52        return MaskedColor(GrColorSatAdd(a.fColor, b.fColor), outFlags);
53    }
54
55    GrColor color() const { return fColor; }
56
57    GrColorComponentFlags validFlags () const { return fFlags; }
58
59private:
60    GrColorComponentFlags componentsWithValue(unsigned value) const {
61        GrColorComponentFlags flags = kNone_GrColorComponentFlags;
62        if ((kR_GrColorComponentFlag & fFlags) && value == GrColorUnpackR(fColor)) {
63            flags |= kR_GrColorComponentFlag;
64        }
65        if ((kG_GrColorComponentFlag & fFlags) && value == GrColorUnpackG(fColor)) {
66            flags |= kG_GrColorComponentFlag;
67        }
68        if ((kB_GrColorComponentFlag & fFlags) && value == GrColorUnpackB(fColor)) {
69            flags |= kB_GrColorComponentFlag;
70        }
71        if ((kA_GrColorComponentFlag & fFlags) && value == GrColorUnpackA(fColor)) {
72            flags |= kA_GrColorComponentFlag;
73        }
74        return flags;
75    }
76
77    GrColor                 fColor;
78    GrColorComponentFlags   fFlags;
79};
80
81static MaskedColor get_term(GrBlendCoeff coeff, const MaskedColor& src, const MaskedColor& dst,
82                            const MaskedColor& value) {
83    switch (coeff) {
84        case kZero_GrBlendCoeff:
85            return MaskedColor(0, kRGBA_GrColorComponentFlags);
86        case kOne_GrBlendCoeff:
87            return value;
88        case kDC_GrBlendCoeff:
89            return MaskedColor::Mul(dst, value);
90        case kIDC_GrBlendCoeff:
91            return MaskedColor::Mul(MaskedColor::Invert(dst), value);
92        case kDA_GrBlendCoeff:
93            return MaskedColor::Mul(MaskedColor::ExtractAlpha(dst), value);
94        case kIDA_GrBlendCoeff:
95            return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(dst), value);
96        case kSC_GrBlendCoeff:
97            return MaskedColor::Mul(src, value);
98        case kISC_GrBlendCoeff:
99            return MaskedColor::Mul(MaskedColor::Invert(src), value);
100        case kSA_GrBlendCoeff:
101            return MaskedColor::Mul(MaskedColor::ExtractAlpha(src), value);
102        case kISA_GrBlendCoeff:
103            return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(src), value);
104        default:
105            SK_ABORT("Illegal coefficient");
106            return MaskedColor();
107    }
108}
109
110void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
111                                    GrColor srcColor, GrColorComponentFlags srcColorFlags,
112                                    GrColor dstColor, GrColorComponentFlags dstColorFlags,
113                                    GrColor* outColor,
114                                    GrColorComponentFlags* outFlags) {
115    MaskedColor src(srcColor, srcColorFlags);
116    MaskedColor dst(dstColor, dstColorFlags);
117
118    MaskedColor srcTerm = get_term(srcCoeff, src, dst, src);
119    MaskedColor dstTerm = get_term(dstCoeff, src, dst, dst);
120
121    MaskedColor output = MaskedColor::SatAdd(srcTerm, dstTerm);
122    *outColor = output.color();
123    *outFlags = output.validFlags();
124}
125