blob: bca23c63bb35390ba7d27822cb100f4a4f74b25f [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 "SkArenaAlloc.h"
#include "SkBlendModePriv.h"
#include "SkBlitRow.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
#include "SkColorSpaceXformer.h"
#include "SkModeColorFilter.h"
#include "SkPM4f.h"
#include "SkPM4fPriv.h"
#include "SkRandom.h"
#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
#include "SkString.h"
#include "SkUtils.h"
#include "SkValidationUtils.h"
#include "SkWriteBuffer.h"
//////////////////////////////////////////////////////////////////////////////////////////////////
SkModeColorFilter::SkModeColorFilter(SkColor color, SkBlendMode mode) {
fColor = color;
fMode = mode;
// cache
fPMColor = SkPreMultiplyColor(fColor);
}
#ifndef SK_IGNORE_TO_STRING
void SkModeColorFilter::toString(SkString* str) const {
str->append("SkModeColorFilter: color: 0x");
str->appendHex(fColor);
str->append(" mode: ");
str->append(SkBlendMode_Name(fMode));
}
#endif
bool SkModeColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const {
if (color) {
*color = fColor;
}
if (mode) {
*mode = fMode;
}
return true;
}
uint32_t SkModeColorFilter::getFlags() const {
uint32_t flags = 0;
switch (fMode) {
case SkBlendMode::kDst: //!< [Da, Dc]
case SkBlendMode::kSrcATop: //!< [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;
switch (fMode) {
case SkBlendMode::kSrc:
sk_memset32(result, color, count);
break;
case SkBlendMode::kSrcIn:
for (int i = 0; i < count; ++i) {
result[i] = SkAlphaMulQ(color, SkAlpha255To256(SkGetPackedA32(shader[i])));
}
break;
case SkBlendMode::kModulate:
for (int i = 0; i < count; ++i) {
int a = SkMulDiv255Round(SkGetPackedA32(color), SkGetPackedA32(shader[i]));
int r = SkMulDiv255Round(SkGetPackedR32(color), SkGetPackedR32(shader[i]));
int g = SkMulDiv255Round(SkGetPackedG32(color), SkGetPackedG32(shader[i]));
int b = SkMulDiv255Round(SkGetPackedB32(color), SkGetPackedB32(shader[i]));
result[i] = SkPackARGB32(a, r, g, b);
}
break;
default: {
SkSTArenaAlloc<256> alloc;
SkRasterPipeline p(&alloc);
p.append(SkRasterPipeline::load_8888, &shader);
if (kN32_SkColorType == kBGRA_8888_SkColorType) {
p.append(SkRasterPipeline::swap_rb);
}
this->appendStages(&p, nullptr, &alloc, false);
if (kN32_SkColorType == kBGRA_8888_SkColorType) {
p.append(SkRasterPipeline::swap_rb);
}
p.append(SkRasterPipeline::store_8888, &result);
p.run(0, 0, count);
} break;
}
}
void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
buffer.writeColor(fColor);
buffer.writeUInt((int)fMode);
}
sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
SkColor color = buffer.readColor();
SkBlendMode mode = (SkBlendMode)buffer.readUInt();
return SkColorFilter::MakeModeFilter(color, mode);
}
void SkModeColorFilter::onAppendStages(SkRasterPipeline* p,
SkColorSpace* dst,
SkArenaAlloc* scratch,
bool shaderIsOpaque) const {
auto color = scratch->make<SkPM4f>(SkPM4f_from_SkColor(fColor, dst));
p->append(SkRasterPipeline::move_src_dst);
p->append(SkRasterPipeline::constant_color, color);
SkBlendMode_AppendStages(fMode, p);
}
sk_sp<SkColorFilter> SkModeColorFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
return SkColorFilter::MakeModeFilter(xformer->apply(fColor), fMode);
}
///////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
#include "GrBlend.h"
#include "effects/GrXfermodeFragmentProcessor.h"
#include "effects/GrConstColorProcessor.h"
#include "SkGr.h"
sk_sp<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
GrContext*, SkColorSpace* dstColorSpace) const {
if (SkBlendMode::kDst == fMode) {
return nullptr;
}
sk_sp<GrFragmentProcessor> constFP(
GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpace),
GrConstColorProcessor::kIgnore_InputMode));
sk_sp<GrFragmentProcessor> fp(
GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(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 ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) {
SkASSERT(fp->hasConstantOutputForConstantInput());
}
#endif
return fp;
}
#endif
///////////////////////////////////////////////////////////////////////////////
sk_sp<SkColorFilter> SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) {
if (!SkIsValidMode(mode)) {
return nullptr;
}
unsigned alpha = SkColorGetA(color);
// first collaps some modes if possible
if (SkBlendMode::kClear == mode) {
color = 0;
mode = SkBlendMode::kSrc;
} else if (SkBlendMode::kSrcOver == mode) {
if (0 == alpha) {
mode = SkBlendMode::kDst;
} else if (255 == alpha) {
mode = SkBlendMode::kSrc;
}
// else just stay srcover
}
// weed out combinations that are noops, and just return null
if (SkBlendMode::kDst == mode ||
(0 == alpha && (SkBlendMode::kSrcOver == mode ||
SkBlendMode::kDstOver == mode ||
SkBlendMode::kDstOut == mode ||
SkBlendMode::kSrcATop == mode ||
SkBlendMode::kXor == mode ||
SkBlendMode::kDarken == mode)) ||
(0xFF == alpha && SkBlendMode::kDstIn == mode)) {
return nullptr;
}
return SkModeColorFilter::Make(color, mode);
}