| /* |
| * Copyright 2014 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef GrInvariantOutput_DEFINED |
| #define GrInvariantOutput_DEFINED |
| |
| #include "GrColor.h" |
| |
| struct GrInitInvariantOutput { |
| GrInitInvariantOutput() |
| : fValidFlags(kNone_GrColorComponentFlags) |
| , fColor(0) |
| , fIsSingleComponent(false) |
| , fIsLCDCoverage(false) {} |
| |
| void setKnownFourComponents(GrColor color) { |
| fColor = color; |
| fValidFlags = kRGBA_GrColorComponentFlags; |
| fIsSingleComponent = false; |
| } |
| |
| void setUnknownFourComponents() { |
| fValidFlags = kNone_GrColorComponentFlags; |
| fIsSingleComponent = false; |
| } |
| |
| void setUnknownOpaqueFourComponents() { |
| fColor = 0xffU << GrColor_SHIFT_A; |
| fValidFlags = kA_GrColorComponentFlag; |
| fIsSingleComponent = false; |
| } |
| |
| void setKnownSingleComponent(uint8_t alpha) { |
| fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha); |
| fValidFlags = kRGBA_GrColorComponentFlags; |
| fIsSingleComponent = true; |
| } |
| |
| void setUnknownSingleComponent() { |
| fValidFlags = kNone_GrColorComponentFlags; |
| fIsSingleComponent = true; |
| } |
| |
| void setUsingLCDCoverage() { fIsLCDCoverage = true; } |
| |
| GrColorComponentFlags fValidFlags; |
| GrColor fColor; |
| bool fIsSingleComponent; |
| bool fIsLCDCoverage; // Temorary data member until texture pixel configs are |
| // updated |
| }; |
| |
| class GrInvariantOutput { |
| public: |
| GrInvariantOutput(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) |
| : fColor(color) |
| , fValidFlags(flags) |
| , fIsSingleComponent(isSingleComponent) |
| , fNonMulStageFound(false) |
| , fWillUseInputColor(true) |
| , fIsLCDCoverage(false) {} |
| |
| GrInvariantOutput(const GrInitInvariantOutput& io) |
| : fColor(io.fColor) |
| , fValidFlags(io.fValidFlags) |
| , fIsSingleComponent(io.fIsSingleComponent) |
| , fNonMulStageFound(false) |
| , fWillUseInputColor(false) |
| , fIsLCDCoverage(io.fIsLCDCoverage) {} |
| |
| virtual ~GrInvariantOutput() {} |
| |
| enum ReadInput { |
| kWill_ReadInput, |
| kWillNot_ReadInput, |
| }; |
| |
| void mulByUnknownOpaqueFourComponents() { |
| SkDEBUGCODE(this->validate()); |
| if (this->isOpaque()) { |
| fValidFlags = kA_GrColorComponentFlag; |
| fIsSingleComponent = false; |
| } else { |
| // Since the current state is not opaque we no longer care if the color being |
| // multiplied is opaque. |
| this->mulByUnknownFourComponents(); |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void mulByUnknownFourComponents() { |
| SkDEBUGCODE(this->validate()); |
| if (this->hasZeroAlpha()) { |
| this->internalSetToTransparentBlack(); |
| } else { |
| this->internalSetToUnknown(); |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void mulByUnknownSingleComponent() { |
| SkDEBUGCODE(this->validate()); |
| if (this->hasZeroAlpha()) { |
| this->internalSetToTransparentBlack(); |
| } else { |
| // We don't need to change fIsSingleComponent in this case |
| fValidFlags = kNone_GrColorComponentFlags; |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void mulByKnownSingleComponent(uint8_t alpha) { |
| SkDEBUGCODE(this->validate()); |
| if (this->hasZeroAlpha() || 0 == alpha) { |
| this->internalSetToTransparentBlack(); |
| } else { |
| if (alpha != 255) { |
| // Multiply color by alpha |
| fColor = GrColorPackRGBA(SkMulDiv255Round(GrColorUnpackR(fColor), alpha), |
| SkMulDiv255Round(GrColorUnpackG(fColor), alpha), |
| SkMulDiv255Round(GrColorUnpackB(fColor), alpha), |
| SkMulDiv255Round(GrColorUnpackA(fColor), alpha)); |
| // We don't need to change fIsSingleComponent in this case |
| } |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void mulByKnownFourComponents(GrColor color) { |
| SkDEBUGCODE(this->validate()); |
| uint32_t a; |
| if (GetAlphaAndCheckSingleChannel(color, &a)) { |
| this->mulByKnownSingleComponent(a); |
| } else { |
| if (color != 0xffffffff) { |
| fColor = GrColorPackRGBA( |
| SkMulDiv255Round(GrColorUnpackR(fColor), GrColorUnpackR(color)), |
| SkMulDiv255Round(GrColorUnpackG(fColor), GrColorUnpackG(color)), |
| SkMulDiv255Round(GrColorUnpackB(fColor), GrColorUnpackB(color)), |
| SkMulDiv255Round(GrColorUnpackA(fColor), a)); |
| if (kRGBA_GrColorComponentFlags == fValidFlags) { |
| fIsSingleComponent = GetAlphaAndCheckSingleChannel(fColor, &a); |
| } |
| } |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| // Ignores the incoming color's RGB and muls its alpha by color. |
| void mulAlphaByKnownFourComponents(GrColor color) { |
| SkDEBUGCODE(this->validate()); |
| uint32_t a; |
| if (GetAlphaAndCheckSingleChannel(color, &a)) { |
| this->mulAlphaByKnownSingleComponent(a); |
| } else if (fValidFlags & kA_GrColorComponentFlag) { |
| GrColor preAlpha = GrColorUnpackA(fColor); |
| if (0 == preAlpha) { |
| this->internalSetToTransparentBlack(); |
| } else { |
| // We know that color has different component values |
| fIsSingleComponent = false; |
| fColor = GrColorPackRGBA( |
| SkMulDiv255Round(preAlpha, GrColorUnpackR(color)), |
| SkMulDiv255Round(preAlpha, GrColorUnpackG(color)), |
| SkMulDiv255Round(preAlpha, GrColorUnpackB(color)), |
| SkMulDiv255Round(preAlpha, a)); |
| fValidFlags = kRGBA_GrColorComponentFlags; |
| } |
| } else { |
| fIsSingleComponent = false; |
| fValidFlags = kNone_GrColorComponentFlags; |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| // Ignores the incoming color's RGB and muls its alpha by the alpha param and sets all channels |
| // equal to that value. |
| void mulAlphaByKnownSingleComponent(uint8_t alpha) { |
| SkDEBUGCODE(this->validate()); |
| if (0 == alpha || this->hasZeroAlpha()) { |
| this->internalSetToTransparentBlack(); |
| } else { |
| if (fValidFlags & kA_GrColorComponentFlag) { |
| GrColor a = GrColorUnpackA(fColor); |
| a = SkMulDiv255Round(alpha, a); |
| fColor = GrColorPackRGBA(a, a, a, a); |
| fValidFlags = kRGBA_GrColorComponentFlags; |
| } else { |
| fValidFlags = kNone_GrColorComponentFlags; |
| } |
| fIsSingleComponent = true; |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void premulFourChannelColor() { |
| SkDEBUGCODE(this->validate()); |
| SkASSERT(!fIsSingleComponent); |
| fNonMulStageFound = true; |
| if (!(fValidFlags & kA_GrColorComponentFlag)) { |
| fValidFlags = kNone_GrColorComponentFlags; |
| } else { |
| fColor = GrPremulColor(fColor); |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void invalidateComponents(GrColorComponentFlags invalidateFlags, ReadInput readsInput) { |
| SkDEBUGCODE(this->validate()); |
| fValidFlags = (fValidFlags & ~invalidateFlags); |
| fIsSingleComponent = false; |
| fNonMulStageFound = true; |
| if (kWillNot_ReadInput == readsInput) { |
| fWillUseInputColor = false; |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void setToOther(GrColorComponentFlags validFlags, GrColor color, ReadInput readsInput) { |
| SkDEBUGCODE(this->validate()); |
| fValidFlags = validFlags; |
| fColor = color; |
| fIsSingleComponent = false; |
| fNonMulStageFound = true; |
| if (kWillNot_ReadInput == readsInput) { |
| fWillUseInputColor = false; |
| } |
| if (kRGBA_GrColorComponentFlags == fValidFlags) { |
| uint32_t a; |
| if (GetAlphaAndCheckSingleChannel(color, &a)) { |
| fIsSingleComponent = true; |
| } |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| void setToUnknown(ReadInput readsInput) { |
| SkDEBUGCODE(this->validate()); |
| this->internalSetToUnknown(); |
| fNonMulStageFound= true; |
| if (kWillNot_ReadInput == readsInput) { |
| fWillUseInputColor = false; |
| } |
| SkDEBUGCODE(this->validate()); |
| } |
| |
| // Temporary setter to handle LCD text correctly until we improve texture pixel config queries |
| // and thus can rely solely on number of coverage components for RGA vs single channel coverage. |
| void setUsingLCDCoverage() { |
| fIsLCDCoverage = true; |
| } |
| |
| GrColor color() const { return fColor; } |
| GrColorComponentFlags validFlags() const { return fValidFlags; } |
| bool willUseInputColor() const { return fWillUseInputColor; } |
| |
| /** |
| * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the |
| * same. If the flags are all set then all color components must be equal. |
| */ |
| SkDEBUGCODE(void validate() const;) |
| |
| private: |
| friend class GrProcOptInfo; |
| |
| /** Extracts the alpha channel and returns true if r,g,b == a. */ |
| static bool GetAlphaAndCheckSingleChannel(GrColor color, uint32_t* alpha) { |
| *alpha = GrColorUnpackA(color); |
| return *alpha == GrColorUnpackR(color) && *alpha == GrColorUnpackG(color) && |
| *alpha == GrColorUnpackB(color); |
| } |
| |
| void reset(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) { |
| fColor = color; |
| fValidFlags = flags; |
| fIsSingleComponent = isSingleComponent; |
| fNonMulStageFound = false; |
| fWillUseInputColor = true; |
| } |
| |
| void reset(const GrInitInvariantOutput& io) { |
| fColor = io.fColor; |
| fValidFlags = io.fValidFlags; |
| fIsSingleComponent = io.fIsSingleComponent; |
| fNonMulStageFound = false; |
| fWillUseInputColor = true; |
| fIsLCDCoverage = io.fIsLCDCoverage; |
| } |
| |
| void internalSetToTransparentBlack() { |
| fValidFlags = kRGBA_GrColorComponentFlags; |
| fColor = 0; |
| fIsSingleComponent = true; |
| } |
| |
| void internalSetToUnknown() { |
| fValidFlags = kNone_GrColorComponentFlags; |
| fIsSingleComponent = false; |
| } |
| |
| bool hasZeroAlpha() const { |
| return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor)); |
| } |
| |
| bool isOpaque() const { |
| return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor)); |
| } |
| |
| bool isSolidWhite() const { |
| return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor); |
| } |
| |
| bool isSingleComponent() const { return fIsSingleComponent; } |
| |
| void resetWillUseInputColor() { fWillUseInputColor = true; } |
| |
| bool allStagesMulInput() const { return !fNonMulStageFound; } |
| void resetNonMulStageFound() { fNonMulStageFound = false; } |
| |
| bool isLCDCoverage() const { return fIsLCDCoverage; } |
| |
| SkDEBUGCODE(bool colorComponentsAllEqual() const;) |
| /** |
| * If alpha is valid, check that any valid R,G,B values are <= A |
| */ |
| SkDEBUGCODE(bool validPreMulColor() const;) |
| |
| GrColor fColor; |
| GrColorComponentFlags fValidFlags; |
| bool fIsSingleComponent; |
| bool fNonMulStageFound; |
| bool fWillUseInputColor; |
| bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated |
| |
| }; |
| |
| #endif |
| |