1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "include/core/SkString.h"
9#include "include/private/SkColorData.h"
10#include "include/private/SkOnce.h"
11#include "src/core/SkBlendModePriv.h"
12#include "src/core/SkMathPriv.h"
13#include "src/core/SkOpts.h"
14#include "src/core/SkRasterPipeline.h"
15#include "src/core/SkReadBuffer.h"
16#include "src/core/SkWriteBuffer.h"
17#include "src/core/SkXfermodePriv.h"
18
19#if SK_SUPPORT_GPU
20#include "src/gpu/GrFragmentProcessor.h"
21#include "src/gpu/effects/GrCustomXfermode.h"
22#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
23#endif
24
25///////////////////////////////////////////////////////////////////////////////////////////////////
26
27class SkProcCoeffXfermode : public SkXfermode {
28public:
29 SkProcCoeffXfermode(SkBlendMode mode) : fMode(mode) {}
30
31 void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
32 const SkAlpha aa[]) const override {
33 SkASSERT(dst && src && count >= 0);
34
35 SkRasterPipeline_<256> p;
36
37 SkRasterPipeline_MemoryCtx dst_ctx = { (void*)dst, 0 },
38 src_ctx = { (void*)src, 0 },
39 aa_ctx = { (void*)aa, 0 };
40
41 p.append_load (kN32_SkColorType, &src_ctx);
42 p.append_load_dst(kN32_SkColorType, &dst_ctx);
43
44 if (SkBlendMode_ShouldPreScaleCoverage(fMode, /*rgb_coverage=*/false)) {
45 if (aa) {
46 p.append(SkRasterPipeline::scale_u8, &aa_ctx);
47 }
48 SkBlendMode_AppendStages(fMode, &p);
49 } else {
50 SkBlendMode_AppendStages(fMode, &p);
51 if (aa) {
52 p.append(SkRasterPipeline::lerp_u8, &aa_ctx);
53 }
54 }
55
56 p.append_store(kN32_SkColorType, &dst_ctx);
57 p.run(0, 0, count,1);
58 }
59
60private:
61 const SkBlendMode fMode;
62
63 typedef SkXfermode INHERITED;
64};
65
66const char* SkBlendMode_Name(SkBlendMode mode) {
67 SkASSERT((unsigned) mode <= (unsigned)SkBlendMode::kLastMode);
68 const char* gModeStrings[] = {
69 "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
70 "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
71 "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
72 "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
73 "Multiply", "Hue", "Saturation", "Color", "Luminosity"
74 };
75 return gModeStrings[(int)mode];
76 static_assert(SK_ARRAY_COUNT(gModeStrings) == (size_t)SkBlendMode::kLastMode + 1, "mode_count");
77}
78
79sk_sp<SkXfermode> SkXfermode::Make(SkBlendMode mode) {
80 if ((unsigned)mode > (unsigned)SkBlendMode::kLastMode) {
81 // report error
82 return nullptr;
83 }
84
85 // Skia's "default" mode is srcover. nullptr in SkPaint is interpreted as srcover
86 // so we can just return nullptr from the factory.
87 if (SkBlendMode::kSrcOver == mode) {
88 return nullptr;
89 }
90
91 const int COUNT_BLENDMODES = (int)SkBlendMode::kLastMode + 1;
92
93 static SkOnce once[COUNT_BLENDMODES];
94 static SkXfermode* cached[COUNT_BLENDMODES];
95
96 once[(int)mode]([mode] {
97 if (auto xfermode = SkOpts::create_xfermode(mode)) {
98 cached[(int)mode] = xfermode;
99 } else {
100 cached[(int)mode] = new SkProcCoeffXfermode(mode);
101 }
102 });
103 return sk_ref_sp(cached[(int)mode]);
104}
105
106///////////////////////////////////////////////////////////////////////////////////////////////////
107
108bool SkXfermode::IsOpaque(SkBlendMode mode, SrcColorOpacity opacityType) {
109 SkBlendModeCoeff src, dst;
110 if (!SkBlendMode_AsCoeff(mode, &src, &dst)) {
111 return false;
112 }
113
114 switch (src) {
115 case SkBlendModeCoeff::kDA:
116 case SkBlendModeCoeff::kDC:
117 case SkBlendModeCoeff::kIDA:
118 case SkBlendModeCoeff::kIDC:
119 return false;
120 default:
121 break;
122 }
123
124 switch (dst) {
125 case SkBlendModeCoeff::kZero:
126 return true;
127 case SkBlendModeCoeff::kISA:
128 return kOpaque_SrcColorOpacity == opacityType;
129 case SkBlendModeCoeff::kSA:
130 return kTransparentBlack_SrcColorOpacity == opacityType ||
131 kTransparentAlpha_SrcColorOpacity == opacityType;
132 case SkBlendModeCoeff::kSC:
133 return kTransparentBlack_SrcColorOpacity == opacityType;
134 default:
135 return false;
136 }
137 return false;
138}
139
140#if SK_SUPPORT_GPU
141const GrXPFactory* SkBlendMode_AsXPFactory(SkBlendMode mode) {
142 if (SkBlendMode_AsCoeff(mode, nullptr, nullptr)) {
143 const GrXPFactory* result = GrPorterDuffXPFactory::Get(mode);
144 SkASSERT(result);
145 return result;
146 }
147
148 SkASSERT(GrCustomXfermode::IsSupportedMode(mode));
149 return GrCustomXfermode::Get(mode);
150}
151#endif
152
153