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