1 /*
2  * Copyright 2014 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 #ifndef GrInvariantOutput_DEFINED
9 #define GrInvariantOutput_DEFINED
10 
11 #include "GrColor.h"
12 
13 struct GrInitInvariantOutput {
GrInitInvariantOutputGrInitInvariantOutput14     GrInitInvariantOutput()
15         : fValidFlags(kNone_GrColorComponentFlags)
16         , fColor(0)
17         , fIsSingleComponent(false)
18         , fIsLCDCoverage(false) {}
19 
setKnownFourComponentsGrInitInvariantOutput20     void setKnownFourComponents(GrColor color) {
21         fColor = color;
22         fValidFlags = kRGBA_GrColorComponentFlags;
23         fIsSingleComponent = false;
24     }
25 
setUnknownFourComponentsGrInitInvariantOutput26     void setUnknownFourComponents() {
27         fValidFlags = kNone_GrColorComponentFlags;
28         fIsSingleComponent = false;
29     }
30 
setUnknownOpaqueFourComponentsGrInitInvariantOutput31     void setUnknownOpaqueFourComponents() {
32         fColor = 0xffU << GrColor_SHIFT_A;
33         fValidFlags = kA_GrColorComponentFlag;
34         fIsSingleComponent = false;
35     }
36 
setKnownSingleComponentGrInitInvariantOutput37     void setKnownSingleComponent(uint8_t alpha) {
38         fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
39         fValidFlags = kRGBA_GrColorComponentFlags;
40         fIsSingleComponent = true;
41     }
42 
setUnknownSingleComponentGrInitInvariantOutput43     void setUnknownSingleComponent() {
44         fValidFlags = kNone_GrColorComponentFlags;
45         fIsSingleComponent = true;
46     }
47 
setUsingLCDCoverageGrInitInvariantOutput48     void setUsingLCDCoverage() { fIsLCDCoverage = true; }
49 
50     GrColorComponentFlags   fValidFlags;
51     GrColor                 fColor;
52     bool                    fIsSingleComponent;
53     bool                    fIsLCDCoverage; // Temorary data member until texture pixel configs are
54                                             // updated
55 };
56 
57 class GrInvariantOutput {
58 public:
GrInvariantOutput(GrColor color,GrColorComponentFlags flags,bool isSingleComponent)59     GrInvariantOutput(GrColor color, GrColorComponentFlags flags, bool isSingleComponent)
60         : fColor(color)
61         , fValidFlags(flags)
62         , fIsSingleComponent(isSingleComponent)
63         , fNonMulStageFound(false)
64         , fWillUseInputColor(true)
65         , fIsLCDCoverage(false) {}
66 
GrInvariantOutput(const GrInitInvariantOutput & io)67     GrInvariantOutput(const GrInitInvariantOutput& io)
68         : fColor(io.fColor)
69         , fValidFlags(io.fValidFlags)
70         , fIsSingleComponent(io.fIsSingleComponent)
71         , fNonMulStageFound(false)
72         , fWillUseInputColor(false)
73         , fIsLCDCoverage(io.fIsLCDCoverage) {}
74 
~GrInvariantOutput()75     virtual ~GrInvariantOutput() {}
76 
77     enum ReadInput {
78         kWill_ReadInput,
79         kWillNot_ReadInput,
80     };
81 
mulByUnknownOpaqueFourComponents()82     void mulByUnknownOpaqueFourComponents() {
83         SkDEBUGCODE(this->validate());
84         if (this->isOpaque()) {
85             fValidFlags = kA_GrColorComponentFlag;
86             fIsSingleComponent = false;
87         } else {
88             // Since the current state is not opaque we no longer care if the color being
89             // multiplied is opaque.
90             this->mulByUnknownFourComponents();
91         }
92         SkDEBUGCODE(this->validate());
93     }
94 
mulByUnknownFourComponents()95     void mulByUnknownFourComponents() {
96         SkDEBUGCODE(this->validate());
97         if (this->hasZeroAlpha()) {
98             this->internalSetToTransparentBlack();
99         } else {
100             this->internalSetToUnknown();
101         }
102         SkDEBUGCODE(this->validate());
103     }
104 
mulByUnknownSingleComponent()105     void mulByUnknownSingleComponent() {
106         SkDEBUGCODE(this->validate());
107         if (this->hasZeroAlpha()) {
108             this->internalSetToTransparentBlack();
109         } else {
110             // We don't need to change fIsSingleComponent in this case
111             fValidFlags = kNone_GrColorComponentFlags;
112         }
113         SkDEBUGCODE(this->validate());
114     }
115 
mulByKnownSingleComponent(uint8_t alpha)116     void mulByKnownSingleComponent(uint8_t alpha) {
117         SkDEBUGCODE(this->validate());
118         if (this->hasZeroAlpha() || 0 == alpha) {
119             this->internalSetToTransparentBlack();
120         } else {
121             if (alpha != 255) {
122                 // Multiply color by alpha
123                 fColor = GrColorPackRGBA(SkMulDiv255Round(GrColorUnpackR(fColor), alpha),
124                                          SkMulDiv255Round(GrColorUnpackG(fColor), alpha),
125                                          SkMulDiv255Round(GrColorUnpackB(fColor), alpha),
126                                          SkMulDiv255Round(GrColorUnpackA(fColor), alpha));
127                 // We don't need to change fIsSingleComponent in this case
128             }
129         }
130         SkDEBUGCODE(this->validate());
131     }
132 
mulByKnownFourComponents(GrColor color)133     void mulByKnownFourComponents(GrColor color) {
134         SkDEBUGCODE(this->validate());
135         uint32_t a;
136         if (GetAlphaAndCheckSingleChannel(color, &a)) {
137             this->mulByKnownSingleComponent(a);
138         } else {
139             if (color != 0xffffffff) {
140                 fColor = GrColorPackRGBA(
141                     SkMulDiv255Round(GrColorUnpackR(fColor), GrColorUnpackR(color)),
142                     SkMulDiv255Round(GrColorUnpackG(fColor), GrColorUnpackG(color)),
143                     SkMulDiv255Round(GrColorUnpackB(fColor), GrColorUnpackB(color)),
144                     SkMulDiv255Round(GrColorUnpackA(fColor), a));
145                 if (kRGBA_GrColorComponentFlags == fValidFlags) {
146                     fIsSingleComponent = GetAlphaAndCheckSingleChannel(fColor, &a);
147                 }
148             }
149         }
150         SkDEBUGCODE(this->validate());
151     }
152 
153     // Ignores the incoming color's RGB and muls its alpha by color.
mulAlphaByKnownFourComponents(GrColor color)154     void mulAlphaByKnownFourComponents(GrColor color) {
155         SkDEBUGCODE(this->validate());
156         uint32_t a;
157         if (GetAlphaAndCheckSingleChannel(color, &a)) {
158             this->mulAlphaByKnownSingleComponent(a);
159         } else if (fValidFlags & kA_GrColorComponentFlag) {
160             GrColor preAlpha = GrColorUnpackA(fColor);
161             if (0 == preAlpha) {
162                 this->internalSetToTransparentBlack();
163             } else {
164                 // We know that color has different component values
165                 fIsSingleComponent = false;
166                 fColor = GrColorPackRGBA(
167                     SkMulDiv255Round(preAlpha, GrColorUnpackR(color)),
168                     SkMulDiv255Round(preAlpha, GrColorUnpackG(color)),
169                     SkMulDiv255Round(preAlpha, GrColorUnpackB(color)),
170                     SkMulDiv255Round(preAlpha, a));
171                 fValidFlags = kRGBA_GrColorComponentFlags;
172             }
173         } else {
174             fIsSingleComponent = false;
175             fValidFlags = kNone_GrColorComponentFlags;
176         }
177         SkDEBUGCODE(this->validate());
178     }
179 
180     // Ignores the incoming color's RGB and muls its alpha by the alpha param and sets all channels
181     // equal to that value.
mulAlphaByKnownSingleComponent(uint8_t alpha)182     void mulAlphaByKnownSingleComponent(uint8_t alpha) {
183         SkDEBUGCODE(this->validate());
184         if (0 == alpha || this->hasZeroAlpha()) {
185             this->internalSetToTransparentBlack();
186         } else {
187             if (fValidFlags & kA_GrColorComponentFlag) {
188                 GrColor a = GrColorUnpackA(fColor);
189                 a = SkMulDiv255Round(alpha, a);
190                 fColor = GrColorPackRGBA(a, a, a, a);
191                 fValidFlags = kRGBA_GrColorComponentFlags;
192             } else {
193                 fValidFlags = kNone_GrColorComponentFlags;
194             }
195             fIsSingleComponent = true;
196         }
197         SkDEBUGCODE(this->validate());
198     }
199 
invalidateComponents(GrColorComponentFlags invalidateFlags,ReadInput readsInput)200     void invalidateComponents(GrColorComponentFlags invalidateFlags, ReadInput readsInput) {
201         SkDEBUGCODE(this->validate());
202         fValidFlags = (fValidFlags & ~invalidateFlags);
203         fIsSingleComponent = false;
204         fNonMulStageFound = true;
205         if (kWillNot_ReadInput == readsInput) {
206             fWillUseInputColor = false;
207         }
208         SkDEBUGCODE(this->validate());
209     }
210 
setToOther(GrColorComponentFlags validFlags,GrColor color,ReadInput readsInput)211     void setToOther(GrColorComponentFlags validFlags, GrColor color, ReadInput readsInput) {
212         SkDEBUGCODE(this->validate());
213         fValidFlags = validFlags;
214         fColor = color;
215         fIsSingleComponent = false;
216         fNonMulStageFound = true;
217         if (kWillNot_ReadInput == readsInput) {
218             fWillUseInputColor = false;
219         }
220         if (kRGBA_GrColorComponentFlags == fValidFlags) {
221             uint32_t a;
222             if (GetAlphaAndCheckSingleChannel(color, &a)) {
223                 fIsSingleComponent = true;
224             }
225         }
226         SkDEBUGCODE(this->validate());
227     }
228 
setToUnknown(ReadInput readsInput)229     void setToUnknown(ReadInput readsInput) {
230         SkDEBUGCODE(this->validate());
231         this->internalSetToUnknown();
232         fNonMulStageFound= true;
233         if (kWillNot_ReadInput == readsInput) {
234             fWillUseInputColor = false;
235         }
236         SkDEBUGCODE(this->validate());
237     }
238 
239     // Temporary setter to handle LCD text correctly until we improve texture pixel config queries
240     // and thus can rely solely on number of coverage components for RGA vs single channel coverage.
setUsingLCDCoverage()241     void setUsingLCDCoverage() {
242         fIsLCDCoverage = true;
243     }
244 
color()245     GrColor color() const { return fColor; }
validFlags()246     GrColorComponentFlags validFlags() const { return fValidFlags; }
willUseInputColor()247     bool willUseInputColor() const { return fWillUseInputColor; }
248 
249     /**
250      * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the
251      * same. If the flags are all set then all color components must be equal.
252      */
253     SkDEBUGCODE(void validate() const;)
254 
255 private:
256     friend class GrProcOptInfo;
257 
258     /** Extracts the alpha channel and returns true if r,g,b == a. */
GetAlphaAndCheckSingleChannel(GrColor color,uint32_t * alpha)259     static bool GetAlphaAndCheckSingleChannel(GrColor color, uint32_t* alpha) {
260         *alpha = GrColorUnpackA(color);
261         return *alpha == GrColorUnpackR(color) && *alpha == GrColorUnpackG(color) &&
262                *alpha == GrColorUnpackB(color);
263     }
264 
reset(GrColor color,GrColorComponentFlags flags,bool isSingleComponent)265     void reset(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) {
266         fColor = color;
267         fValidFlags = flags;
268         fIsSingleComponent = isSingleComponent;
269         fNonMulStageFound = false;
270         fWillUseInputColor = true;
271     }
272 
reset(const GrInitInvariantOutput & io)273     void reset(const GrInitInvariantOutput& io) {
274         fColor = io.fColor;
275         fValidFlags = io.fValidFlags;
276         fIsSingleComponent = io.fIsSingleComponent;
277         fNonMulStageFound = false;
278         fWillUseInputColor = true;
279         fIsLCDCoverage = io.fIsLCDCoverage;
280     }
281 
internalSetToTransparentBlack()282     void internalSetToTransparentBlack() {
283         fValidFlags = kRGBA_GrColorComponentFlags;
284         fColor = 0;
285         fIsSingleComponent = true;
286     }
287 
internalSetToUnknown()288     void internalSetToUnknown() {
289         fValidFlags = kNone_GrColorComponentFlags;
290         fIsSingleComponent = false;
291     }
292 
hasZeroAlpha()293     bool hasZeroAlpha() const {
294         return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor));
295     }
296 
isOpaque()297     bool isOpaque() const {
298         return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor));
299     }
300 
isSolidWhite()301     bool isSolidWhite() const {
302         return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor);
303     }
304 
isSingleComponent()305     bool isSingleComponent() const { return fIsSingleComponent; }
306 
resetWillUseInputColor()307     void resetWillUseInputColor() { fWillUseInputColor = true; }
308 
allStagesMulInput()309     bool allStagesMulInput() const { return !fNonMulStageFound; }
resetNonMulStageFound()310     void resetNonMulStageFound() { fNonMulStageFound = false; }
311 
isLCDCoverage()312     bool isLCDCoverage() const { return fIsLCDCoverage; }
313 
314     SkDEBUGCODE(bool colorComponentsAllEqual() const;)
315     /**
316      * If alpha is valid, check that any valid R,G,B values are <= A
317      */
318     SkDEBUGCODE(bool validPreMulColor() const;)
319 
320     GrColor fColor;
321     GrColorComponentFlags fValidFlags;
322     bool fIsSingleComponent;
323     bool fNonMulStageFound;
324     bool fWillUseInputColor;
325     bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated
326 
327 };
328 
329 #endif
330 
331