/* * 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 "SkBlendModePriv.h" #include "SkColorPriv.h" #include "SkMathPriv.h" #include "SkOnce.h" #include "SkOpts.h" #include "SkPM4f.h" #include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkString.h" #include "SkWriteBuffer.h" #include "SkXfermodePriv.h" #if SK_SUPPORT_GPU #include "GrFragmentProcessor.h" #include "effects/GrCustomXfermode.h" #include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrXfermodeFragmentProcessor.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; if (kN32_SkColorType == kBGRA_8888_SkColorType) { p.append(SkRasterPipeline::load_bgra_dst, &dst); p.append(SkRasterPipeline::load_bgra , &src); } else { p.append(SkRasterPipeline::load_8888_dst, &dst); p.append(SkRasterPipeline::load_8888, &src); } SkBlendMode_AppendStagesNoClamp(fMode, &p); if (aa) { p.append(SkRasterPipeline::lerp_u8, &aa); } SkBlendMode_AppendClampIfNeeded(fMode, &p); if (kN32_SkColorType == kBGRA_8888_SkColorType) { p.append(SkRasterPipeline::store_bgra, &dst); } else { p.append(SkRasterPipeline::store_8888, &dst); } p.run(0, 0, count); } private: const SkBlendMode fMode; typedef SkXfermode INHERITED; }; const char* SkBlendMode_Name(SkBlendMode mode) { SkASSERT((unsigned) mode <= (unsigned)SkBlendMode::kLastMode); const char* gModeStrings[] = { "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn", "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus", "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion", "Multiply", "Hue", "Saturation", "Color", "Luminosity" }; return gModeStrings[(int)mode]; static_assert(SK_ARRAY_COUNT(gModeStrings) == (size_t)SkBlendMode::kLastMode + 1, "mode_count"); } sk_sp 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