blob: 1e104d8dc77856b7ba07940769836e9a0e444025 [file] [log] [blame]
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBlitRow.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
#include "SkModeColorFilter.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkUtils.h"
#include "SkString.h"
#include "SkValidationUtils.h"
#include "SkPM4f.h"
//////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef SK_IGNORE_TO_STRING
void SkModeColorFilter::toString(SkString* str) const {
str->append("SkModeColorFilter: color: 0x");
str->appendHex(fColor);
str->append(" mode: ");
str->append(SkXfermode::ModeName(fMode));
}
#endif
bool SkModeColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) const {
if (color) {
*color = fColor;
}
if (mode) {
*mode = fMode;
}
return true;
}
uint32_t SkModeColorFilter::getFlags() const {
uint32_t flags = 0;
switch (fMode) {
case SkXfermode::kDst_Mode: //!< [Da, Dc]
case SkXfermode::kSrcATop_Mode: //!< [Da, Sc * Da + (1 - Sa) * Dc]
flags |= kAlphaUnchanged_Flag;
default:
break;
}
return flags;
}
void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
SkPMColor color = fPMColor;
SkXfermodeProc proc = fProc;
for (int i = 0; i < count; i++) {
result[i] = proc(color, shader[i]);
}
}
void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
SkPM4f color = SkPM4f::FromPMColor(fPMColor);
SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode);
for (int i = 0; i < count; i++) {
result[i] = proc(color, shader[i]);
}
}
void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
buffer.writeColor(fColor);
buffer.writeUInt(fMode);
}
void SkModeColorFilter::updateCache() {
fPMColor = SkPreMultiplyColor(fColor);
fProc = SkXfermode::GetProc(fMode);
}
SkFlattenable* SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
SkColor color = buffer.readColor();
SkXfermode::Mode mode = (SkXfermode::Mode)buffer.readUInt();
return SkColorFilter::CreateModeFilter(color, mode);
}
///////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
#include "GrBlend.h"
#include "GrInvariantOutput.h"
#include "effects/GrXfermodeFragmentProcessor.h"
#include "effects/GrConstColorProcessor.h"
#include "SkGr.h"
const GrFragmentProcessor* SkModeColorFilter::asFragmentProcessor(GrContext*) const {
if (SkXfermode::kDst_Mode == fMode) {
return nullptr;
}
SkAutoTUnref<const GrFragmentProcessor> constFP(
GrConstColorProcessor::Create(SkColorToPremulGrColor(fColor),
GrConstColorProcessor::kIgnore_InputMode));
const GrFragmentProcessor* fp =
GrXfermodeFragmentProcessor::CreateFromSrcProcessor(constFP, fMode);
if (!fp) {
return nullptr;
}
#ifdef SK_DEBUG
// With a solid color input this should always be able to compute the blended color
// (at least for coeff modes)
if (fMode <= SkXfermode::kLastCoeffMode) {
static SkRandom gRand;
GrInvariantOutput io(GrPremulColor(gRand.nextU()), kRGBA_GrColorComponentFlags,
false);
fp->computeInvariantOutput(&io);
SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags);
}
#endif
return fp;
}
#endif
///////////////////////////////////////////////////////////////////////////////
class Src_SkModeColorFilter final : public SkModeColorFilter {
public:
Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {}
void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
sk_memset32(result, this->getPMColor(), count);
}
private:
typedef SkModeColorFilter INHERITED;
};
class SrcOver_SkModeColorFilter final : public SkModeColorFilter {
public:
SrcOver_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrcOver_Mode) { }
void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override {
SkBlitRow::Color32(result, shader, count, this->getPMColor());
}
private:
typedef SkModeColorFilter INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color, SkXfermode::Mode mode) {
if (!SkIsValidMode(mode)) {
return nullptr;
}
unsigned alpha = SkColorGetA(color);
// first collaps some modes if possible
if (SkXfermode::kClear_Mode == mode) {
color = 0;
mode = SkXfermode::kSrc_Mode;
} else if (SkXfermode::kSrcOver_Mode == mode) {
if (0 == alpha) {
mode = SkXfermode::kDst_Mode;
} else if (255 == alpha) {
mode = SkXfermode::kSrc_Mode;
}
// else just stay srcover
}
// weed out combinations that are noops, and just return null
if (SkXfermode::kDst_Mode == mode ||
(0 == alpha && (SkXfermode::kSrcOver_Mode == mode ||
SkXfermode::kDstOver_Mode == mode ||
SkXfermode::kDstOut_Mode == mode ||
SkXfermode::kSrcATop_Mode == mode ||
SkXfermode::kXor_Mode == mode ||
SkXfermode::kDarken_Mode == mode)) ||
(0xFF == alpha && SkXfermode::kDstIn_Mode == mode)) {
return nullptr;
}
switch (mode) {
case SkXfermode::kSrc_Mode:
return new Src_SkModeColorFilter(color);
case SkXfermode::kSrcOver_Mode:
return new SrcOver_SkModeColorFilter(color);
default:
return SkModeColorFilter::Create(color, mode);
}
}