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 
27 class SkProcCoeffXfermode : public SkXfermode {
28 public:
SkProcCoeffXfermode(SkBlendMode mode)29     SkProcCoeffXfermode(SkBlendMode mode) : fMode(mode) {}
30 
xfer32(SkPMColor dst[],const SkPMColor src[],int count,const SkAlpha aa[]) const31     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 
60 private:
61     const SkBlendMode fMode;
62 
63     using INHERITED = SkXfermode;
64 };
65 
SkBlendMode_Name(SkBlendMode mode)66 const 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 
Make(SkBlendMode mode)79 sk_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 
IsOpaque(SkBlendMode mode,SrcColorOpacity opacityType)108 bool 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
SkBlendMode_AsXPFactory(SkBlendMode mode)141 const 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