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