blob: 9b1a9a1eff49d0370acdeb5e992d51d4ca3e9610 [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 "include/core/SkString.h"
#include "include/private/SkColorData.h"
#include "include/private/SkOnce.h"
#include "src/core/SkBlendModePriv.h"
#include "src/core/SkMathPriv.h"
#include "src/core/SkOpts.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/core/SkXfermodePriv.h"
#if SK_SUPPORT_GPU
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/effects/GrCustomXfermode.h"
#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
class SkProcCoeffXfermode : public SkXfermode {
public:
SkProcCoeffXfermode(SkBlendMode mode) : fMode(mode) {}
void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const override {
SkASSERT(dst && src && count >= 0);
SkRasterPipeline_<256> p;
SkRasterPipeline_MemoryCtx dst_ctx = { (void*)dst, 0 },
src_ctx = { (void*)src, 0 },
aa_ctx = { (void*)aa, 0 };
p.append_load (kN32_SkColorType, &src_ctx);
p.append_load_dst(kN32_SkColorType, &dst_ctx);
if (SkBlendMode_ShouldPreScaleCoverage(fMode, /*rgb_coverage=*/false)) {
if (aa) {
p.append(SkRasterPipeline::scale_u8, &aa_ctx);
}
SkBlendMode_AppendStages(fMode, &p);
} else {
SkBlendMode_AppendStages(fMode, &p);
if (aa) {
p.append(SkRasterPipeline::lerp_u8, &aa_ctx);
}
}
p.append_store(kN32_SkColorType, &dst_ctx);
p.run(0, 0, count,1);
}
private:
const SkBlendMode fMode;
using INHERITED = SkXfermode;
};
const char* SkBlendMode_Name(SkBlendMode bm) {
switch (bm) {
case SkBlendMode::kClear: return "Clear";
case SkBlendMode::kSrc: return "Src";
case SkBlendMode::kDst: return "Dst";
case SkBlendMode::kSrcOver: return "SrcOver";
case SkBlendMode::kDstOver: return "DstOver";
case SkBlendMode::kSrcIn: return "SrcIn";
case SkBlendMode::kDstIn: return "DstIn";
case SkBlendMode::kSrcOut: return "SrcOut";
case SkBlendMode::kDstOut: return "DstOut";
case SkBlendMode::kSrcATop: return "SrcATop";
case SkBlendMode::kDstATop: return "DstATop";
case SkBlendMode::kXor: return "Xor";
case SkBlendMode::kPlus: return "Plus";
case SkBlendMode::kModulate: return "Modulate";
case SkBlendMode::kScreen: return "Screen";
case SkBlendMode::kOverlay: return "Overlay";
case SkBlendMode::kDarken: return "Darken";
case SkBlendMode::kLighten: return "Lighten";
case SkBlendMode::kColorDodge: return "ColorDodge";
case SkBlendMode::kColorBurn: return "ColorBurn";
case SkBlendMode::kHardLight: return "HardLight";
case SkBlendMode::kSoftLight: return "SoftLight";
case SkBlendMode::kDifference: return "Difference";
case SkBlendMode::kExclusion: return "Exclusion";
case SkBlendMode::kMultiply: return "Multiply";
case SkBlendMode::kHue: return "Hue";
case SkBlendMode::kSaturation: return "Saturation";
case SkBlendMode::kColor: return "Color";
case SkBlendMode::kLuminosity: return "Luminosity";
}
SkUNREACHABLE;
}
sk_sp<SkXfermode> SkXfermode::Make(SkBlendMode mode) {
if ((unsigned)mode > (unsigned)SkBlendMode::kLastMode) {
// report error
return nullptr;
}
// Skia's "default" mode is srcover. nullptr in SkPaint is interpreted as srcover
// so we can just return nullptr from the factory.
if (SkBlendMode::kSrcOver == mode) {
return nullptr;
}
const int COUNT_BLENDMODES = (int)SkBlendMode::kLastMode + 1;
static SkOnce once[COUNT_BLENDMODES];
static SkXfermode* cached[COUNT_BLENDMODES];
once[(int)mode]([mode] {
if (auto xfermode = SkOpts::create_xfermode(mode)) {
cached[(int)mode] = xfermode;
} else {
cached[(int)mode] = new SkProcCoeffXfermode(mode);
}
});
return sk_ref_sp(cached[(int)mode]);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
bool SkXfermode::IsOpaque(SkBlendMode mode, SrcColorOpacity opacityType) {
SkBlendModeCoeff src, dst;
if (!SkBlendMode_AsCoeff(mode, &src, &dst)) {
return false;
}
switch (src) {
case SkBlendModeCoeff::kDA:
case SkBlendModeCoeff::kDC:
case SkBlendModeCoeff::kIDA:
case SkBlendModeCoeff::kIDC:
return false;
default:
break;
}
switch (dst) {
case SkBlendModeCoeff::kZero:
return true;
case SkBlendModeCoeff::kISA:
return kOpaque_SrcColorOpacity == opacityType;
case SkBlendModeCoeff::kSA:
return kTransparentBlack_SrcColorOpacity == opacityType ||
kTransparentAlpha_SrcColorOpacity == opacityType;
case SkBlendModeCoeff::kSC:
return kTransparentBlack_SrcColorOpacity == opacityType;
default:
return false;
}
return false;
}
#if SK_SUPPORT_GPU
const GrXPFactory* SkBlendMode_AsXPFactory(SkBlendMode mode) {
if (SkBlendMode_AsCoeff(mode, nullptr, nullptr)) {
const GrXPFactory* result = GrPorterDuffXPFactory::Get(mode);
SkASSERT(result);
return result;
}
SkASSERT(GrCustomXfermode::IsSupportedMode(mode));
return GrCustomXfermode::Get(mode);
}
#endif