• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 Google Inc.
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 "SkRasterPipeline.h"
10 
SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode)11 bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) {
12     switch (mode) {
13         case SkBlendMode::kDst:
14         case SkBlendMode::kSrcOver:
15         case SkBlendMode::kDstOver:
16         case SkBlendMode::kDstOut:
17         case SkBlendMode::kSrcATop:
18         case SkBlendMode::kXor:
19         case SkBlendMode::kPlus:
20             return true;
21         default:
22             break;
23     }
24     return false;
25 }
26 
27 struct CoeffRec {
28     SkBlendModeCoeff    fSrc;
29     SkBlendModeCoeff    fDst;
30 };
31 
32 const CoeffRec gCoeffs[] = {
33     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kZero },
34     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kZero },
35     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kOne  },
36     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISA  },
37     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kOne  },
38     { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kZero },
39     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSA   },
40     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kZero },
41     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kISA  },
42     { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kISA  },
43     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kSA   },
44     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kISA  },
45 
46     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kOne  },
47     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSC   },
48     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISC  },    // screen
49 };
50 
SkBlendMode_AsCoeff(SkBlendMode mode,SkBlendModeCoeff * src,SkBlendModeCoeff * dst)51 bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst) {
52     if (mode > SkBlendMode::kScreen) {
53         return false;
54     }
55     if (src) {
56         *src = gCoeffs[static_cast<int>(mode)].fSrc;
57     }
58     if (dst) {
59         *dst = gCoeffs[static_cast<int>(mode)].fDst;
60     }
61     return true;
62 }
63 
SkBlendMode_AppendStagesNoClamp(SkBlendMode mode,SkRasterPipeline * p)64 void SkBlendMode_AppendStagesNoClamp(SkBlendMode mode, SkRasterPipeline* p) {
65     auto stage = SkRasterPipeline::srcover;
66     switch (mode) {
67         case SkBlendMode::kClear:    stage = SkRasterPipeline::clear; break;
68         case SkBlendMode::kSrc:      return;  // This stage is a no-op.
69         case SkBlendMode::kDst:      stage = SkRasterPipeline::move_dst_src; break;
70         case SkBlendMode::kSrcOver:  stage = SkRasterPipeline::srcover; break;
71         case SkBlendMode::kDstOver:  stage = SkRasterPipeline::dstover; break;
72         case SkBlendMode::kSrcIn:    stage = SkRasterPipeline::srcin; break;
73         case SkBlendMode::kDstIn:    stage = SkRasterPipeline::dstin; break;
74         case SkBlendMode::kSrcOut:   stage = SkRasterPipeline::srcout; break;
75         case SkBlendMode::kDstOut:   stage = SkRasterPipeline::dstout; break;
76         case SkBlendMode::kSrcATop:  stage = SkRasterPipeline::srcatop; break;
77         case SkBlendMode::kDstATop:  stage = SkRasterPipeline::dstatop; break;
78         case SkBlendMode::kXor:      stage = SkRasterPipeline::xor_; break;
79         case SkBlendMode::kPlus:     stage = SkRasterPipeline::plus_; break;
80         case SkBlendMode::kModulate: stage = SkRasterPipeline::modulate; break;
81 
82         case SkBlendMode::kScreen:     stage = SkRasterPipeline::screen; break;
83         case SkBlendMode::kOverlay:    stage = SkRasterPipeline::overlay; break;
84         case SkBlendMode::kDarken:     stage = SkRasterPipeline::darken; break;
85         case SkBlendMode::kLighten:    stage = SkRasterPipeline::lighten; break;
86         case SkBlendMode::kColorDodge: stage = SkRasterPipeline::colordodge; break;
87         case SkBlendMode::kColorBurn:  stage = SkRasterPipeline::colorburn; break;
88         case SkBlendMode::kHardLight:  stage = SkRasterPipeline::hardlight; break;
89         case SkBlendMode::kSoftLight:  stage = SkRasterPipeline::softlight; break;
90         case SkBlendMode::kDifference: stage = SkRasterPipeline::difference; break;
91         case SkBlendMode::kExclusion:  stage = SkRasterPipeline::exclusion; break;
92         case SkBlendMode::kMultiply:   stage = SkRasterPipeline::multiply; break;
93 
94         case SkBlendMode::kHue:        stage = SkRasterPipeline::hue; break;
95         case SkBlendMode::kSaturation: stage = SkRasterPipeline::saturation; break;
96         case SkBlendMode::kColor:      stage = SkRasterPipeline::color; break;
97         case SkBlendMode::kLuminosity: stage = SkRasterPipeline::luminosity; break;
98     }
99     p->append(stage);
100 }
101 
SkBlendMode_AppendClampIfNeeded(SkBlendMode mode,SkRasterPipeline * p)102 void SkBlendMode_AppendClampIfNeeded(SkBlendMode mode, SkRasterPipeline* p) {
103     if (mode == SkBlendMode::kPlus) {
104         // Both clamp_a and clamp_1 would preserve premultiplication invariants here,
105         // so we pick clamp_1 for being a smidge faster.
106         p->append(SkRasterPipeline::clamp_1);
107     }
108 }
109 
SkBlendMode_Apply(SkBlendMode mode,const SkPM4f & src,const SkPM4f & dst)110 SkPM4f SkBlendMode_Apply(SkBlendMode mode, const SkPM4f& src, const SkPM4f& dst) {
111     // special-case simple/common modes...
112     switch (mode) {
113         case SkBlendMode::kClear:   return {{ 0, 0, 0, 0 }};
114         case SkBlendMode::kSrc:     return src;
115         case SkBlendMode::kDst:     return dst;
116         case SkBlendMode::kSrcOver:
117             return SkPM4f::From4f(src.to4f() + dst.to4f() * Sk4f(1 - src.a()));
118         default:
119             break;
120     }
121 
122     SkRasterPipeline_<256> p;
123     SkPM4f                 src_storage = src,
124                            dst_storage = dst,
125                            result_storage,
126                            *src_ctx = &src_storage,
127                            *dst_ctx = &dst_storage,
128                            *res_ctx = &result_storage;
129 
130     p.append(SkRasterPipeline::load_f32, &dst_ctx);
131     p.append(SkRasterPipeline::move_src_dst);
132     p.append(SkRasterPipeline::load_f32, &src_ctx);
133     SkBlendMode_AppendStages(mode, &p);
134     p.append(SkRasterPipeline::store_f32, &res_ctx);
135     p.run(0, 0, 1);
136     return result_storage;
137 }
138