/* * 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::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