/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrBlend.h"
/**
* MaskedColor is used to evaluate the color and valid color component flags through the
* blending equation. Could possibly extend this to be used more broadly.
*/
class MaskedColor {
public:
MaskedColor(GrColor color, GrColorComponentFlags flags)
: fColor(color)
, fFlags(flags) {}
MaskedColor() {}
void set(GrColor color, GrColorComponentFlags flags) {
fColor = color;
fFlags = flags;
}
static MaskedColor Invert(const MaskedColor& in) {
return MaskedColor(GrInvertColor(in.fColor), in.fFlags);
}
static MaskedColor ExtractAlpha(const MaskedColor& in) {
GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
return MaskedColor(GrColorPackA4(GrColorUnpackA(in.fColor)), flags);
}
static MaskedColor ExtractInverseAlpha(const MaskedColor& in) {
GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
return MaskedColor(GrColorPackA4(0xFF - GrColorUnpackA(in.fColor)), flags);
}
static MaskedColor Mul(const MaskedColor& a, const MaskedColor& b) {
GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0) |
b.componentsWithValue(0);
return MaskedColor(GrColorMul(a.fColor, b.fColor), outFlags);
}
static MaskedColor SatAdd(const MaskedColor& a, const MaskedColor& b) {
GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0xFF) |
b.componentsWithValue(0xFF);
return MaskedColor(GrColorSatAdd(a.fColor, b.fColor), outFlags);
}
GrColor color() const { return fColor; }
GrColorComponentFlags validFlags () const { return fFlags; }
private:
GrColorComponentFlags componentsWithValue(unsigned value) const {
GrColorComponentFlags flags = kNone_GrColorComponentFlags;
if ((kR_GrColorComponentFlag & fFlags) && value == GrColorUnpackR(fColor)) {
flags |= kR_GrColorComponentFlag;
}
if ((kG_GrColorComponentFlag & fFlags) && value == GrColorUnpackG(fColor)) {
flags |= kG_GrColorComponentFlag;
}
if ((kB_GrColorComponentFlag & fFlags) && value == GrColorUnpackB(fColor)) {
flags |= kB_GrColorComponentFlag;
}
if ((kA_GrColorComponentFlag & fFlags) && value == GrColorUnpackA(fColor)) {
flags |= kA_GrColorComponentFlag;
}
return flags;
}
GrColor fColor;
GrColorComponentFlags fFlags;
};
static MaskedColor get_term(GrBlendCoeff coeff, const MaskedColor& src, const MaskedColor& dst,
const MaskedColor& value) {
switch (coeff) {
case kZero_GrBlendCoeff:
return MaskedColor(0, kRGBA_GrColorComponentFlags);
case kOne_GrBlendCoeff:
return value;
case kDC_GrBlendCoeff:
return MaskedColor::Mul(dst, value);
case kIDC_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::Invert(dst), value);
case kDA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractAlpha(dst), value);
case kIDA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(dst), value);
case kSC_GrBlendCoeff:
return MaskedColor::Mul(src, value);
case kISC_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::Invert(src), value);
case kSA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractAlpha(src), value);
case kISA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(src), value);
default:
SK_ABORT("Illegal coefficient");
return MaskedColor();
}
}
void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
GrColor srcColor, GrColorComponentFlags srcColorFlags,
GrColor dstColor, GrColorComponentFlags dstColorFlags,
GrColor* outColor,
GrColorComponentFlags* outFlags) {
MaskedColor src(srcColor, srcColorFlags);
MaskedColor dst(dstColor, dstColorFlags);
MaskedColor srcTerm = get_term(srcCoeff, src, dst, src);
MaskedColor dstTerm = get_term(dstCoeff, src, dst, dst);
MaskedColor output = MaskedColor::SatAdd(srcTerm, dstTerm);
*outColor = output.color();
*outFlags = output.validFlags();
}