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