1
2/*
3 * Copyright 2013 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "GrBlend.h"
10
11static inline GrBlendCoeff swap_coeff_src_dst(GrBlendCoeff coeff) {
12    switch (coeff) {
13        case kDC_GrBlendCoeff:
14            return kSC_GrBlendCoeff;
15        case kIDC_GrBlendCoeff:
16            return kISC_GrBlendCoeff;
17        case kDA_GrBlendCoeff:
18            return kSA_GrBlendCoeff;
19        case kIDA_GrBlendCoeff:
20            return kISA_GrBlendCoeff;
21        case kSC_GrBlendCoeff:
22            return kDC_GrBlendCoeff;
23        case kISC_GrBlendCoeff:
24            return kIDC_GrBlendCoeff;
25        case kSA_GrBlendCoeff:
26            return kDA_GrBlendCoeff;
27        case kISA_GrBlendCoeff:
28            return kIDA_GrBlendCoeff;
29        default:
30            return coeff;
31    }
32}
33
34static inline unsigned saturated_add(unsigned a, unsigned b) {
35    SkASSERT(a <= 255);
36    SkASSERT(b <= 255);
37    unsigned sum = a + b;
38    if (sum > 255) {
39        sum = 255;
40    }
41    return sum;
42}
43
44static GrColor add_colors(GrColor src, GrColor dst) {
45    unsigned r = saturated_add(GrColorUnpackR(src), GrColorUnpackR(dst));
46    unsigned g = saturated_add(GrColorUnpackG(src), GrColorUnpackG(dst));
47    unsigned b = saturated_add(GrColorUnpackB(src), GrColorUnpackB(dst));
48    unsigned a = saturated_add(GrColorUnpackA(src), GrColorUnpackA(dst));
49    return GrColorPackRGBA(r, g, b, a);
50}
51
52static inline bool valid_color(uint32_t compFlags) {
53     return (kRGBA_GrColorComponentFlags & compFlags) == kRGBA_GrColorComponentFlags;
54}
55
56static GrColor simplify_blend_term(GrBlendCoeff* srcCoeff,
57                                   GrColor srcColor, uint32_t srcCompFlags,
58                                   GrColor dstColor, uint32_t dstCompFlags,
59                                   GrColor constantColor) {
60
61    SkASSERT(!GrBlendCoeffRefsSrc(*srcCoeff));
62    SkASSERT(NULL != srcCoeff);
63
64    // Check whether srcCoeff can be reduced to kOne or kZero based on known color inputs.
65    // We could pick out the coeff r,g,b,a values here and use them to compute the blend term color,
66    // if possible, below but that is not implemented now.
67    switch (*srcCoeff) {
68        case kIDC_GrBlendCoeff:
69            dstColor = ~dstColor; // fallthrough
70        case kDC_GrBlendCoeff:
71            if (valid_color(dstCompFlags)) {
72                if (0xffffffff == dstColor) {
73                    *srcCoeff = kOne_GrBlendCoeff;
74                } else if (0 == dstColor) {
75                    *srcCoeff = kZero_GrBlendCoeff;
76                }
77            }
78            break;
79
80        case kIDA_GrBlendCoeff:
81            dstColor = ~dstColor; // fallthrough
82        case kDA_GrBlendCoeff:
83            if (kA_GrColorComponentFlag & dstCompFlags) {
84                if (0xff == GrColorUnpackA(dstColor)) {
85                    *srcCoeff = kOne_GrBlendCoeff;
86                } else if (0 == GrColorUnpackA(dstColor)) {
87                    *srcCoeff = kZero_GrBlendCoeff;
88                }
89            }
90            break;
91
92        case kIConstC_GrBlendCoeff:
93            constantColor = ~constantColor; // fallthrough
94        case kConstC_GrBlendCoeff:
95            if (0xffffffff == constantColor) {
96                *srcCoeff = kOne_GrBlendCoeff;
97            } else if (0 == constantColor) {
98                *srcCoeff = kZero_GrBlendCoeff;
99            }
100            break;
101
102        case kIConstA_GrBlendCoeff:
103            constantColor = ~constantColor; // fallthrough
104        case kConstA_GrBlendCoeff:
105            if (0xff == GrColorUnpackA(constantColor)) {
106                *srcCoeff = kOne_GrBlendCoeff;
107            } else if (0 == GrColorUnpackA(constantColor)) {
108                *srcCoeff = kZero_GrBlendCoeff;
109            }
110            break;
111
112        default:
113            break;
114    }
115    // We may have invalidated these above and shouldn't read them again.
116    SkDEBUGCODE(dstColor = constantColor = GrColor_ILLEGAL;)
117
118    if (kZero_GrBlendCoeff == *srcCoeff || (valid_color(srcCompFlags) && 0 == srcColor)) {
119        *srcCoeff = kZero_GrBlendCoeff;
120        return 0;
121    }
122
123    if (kOne_GrBlendCoeff == *srcCoeff && valid_color(srcCompFlags)) {
124        return srcColor;
125    } else {
126        return GrColor_ILLEGAL;
127    }
128}
129
130GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff,
131                        GrBlendCoeff* dstCoeff,
132                        GrColor srcColor, uint32_t srcCompFlags,
133                        GrColor dstColor, uint32_t dstCompFlags,
134                        GrColor constantColor) {
135    GrColor srcTermColor = simplify_blend_term(srcCoeff,
136                                               srcColor, srcCompFlags,
137                                               dstColor, dstCompFlags,
138                                               constantColor);
139
140    // We call the same function to simplify the dst blend coeff. We trick it out by swapping the
141    // src and dst.
142    GrBlendCoeff spoofedCoeff = swap_coeff_src_dst(*dstCoeff);
143    GrColor dstTermColor = simplify_blend_term(&spoofedCoeff,
144                                               dstColor, dstCompFlags,
145                                               srcColor, srcCompFlags,
146                                               constantColor);
147    *dstCoeff = swap_coeff_src_dst(spoofedCoeff);
148
149    if (GrColor_ILLEGAL != srcTermColor && GrColor_ILLEGAL != dstTermColor) {
150        return add_colors(srcTermColor, dstTermColor);
151    } else {
152        return GrColor_ILLEGAL;
153    }
154}
155