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