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 "src/core/SkBlendModePriv.h" |
9 | #include "src/core/SkCoverageModePriv.h" |
10 | #include "src/core/SkRasterPipeline.h" |
11 | |
12 | bool SkBlendMode_ShouldPreScaleCoverage(SkBlendMode mode, bool rgb_coverage) { |
13 | // The most important things we do here are: |
14 | // 1) never pre-scale with rgb coverage if the blend mode involves a source-alpha term; |
15 | // 2) always pre-scale Plus. |
16 | // |
17 | // When we pre-scale with rgb coverage, we scale each of source r,g,b, with a distinct value, |
18 | // and source alpha with one of those three values. This process destructively updates the |
19 | // source-alpha term, so we can't evaluate blend modes that need its original value. |
20 | // |
21 | // Plus always requires pre-scaling as a specific quirk of its implementation in |
22 | // SkRasterPipeline. This lets us put the clamp inside the blend mode itself rather |
23 | // than as a separate stage that'd come after the lerp. |
24 | // |
25 | // This function is a finer-grained breakdown of SkBlendMode_SupportsCoverageAsAlpha(). |
26 | switch (mode) { |
27 | case SkBlendMode::kDst: // d --> no sa term, ok! |
28 | case SkBlendMode::kDstOver: // d + s*inv(da) --> no sa term, ok! |
29 | case SkBlendMode::kPlus: // clamp(s+d) --> no sa term, ok! |
30 | return true; |
31 | |
32 | case SkBlendMode::kDstOut: // d * inv(sa) |
33 | case SkBlendMode::kSrcATop: // s*da + d*inv(sa) |
34 | case SkBlendMode::kSrcOver: // s + d*inv(sa) |
35 | case SkBlendMode::kXor: // s*inv(da) + d*inv(sa) |
36 | return !rgb_coverage; |
37 | |
38 | default: break; |
39 | } |
40 | return false; |
41 | } |
42 | |
43 | // Users of this function may want to switch to the rgb-coverage aware version above. |
44 | bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) { |
45 | return SkBlendMode_ShouldPreScaleCoverage(mode, false); |
46 | } |
47 | |
48 | struct CoeffRec { |
49 | SkBlendModeCoeff fSrc; |
50 | SkBlendModeCoeff fDst; |
51 | }; |
52 | |
53 | const CoeffRec gCoeffs[] = { |
54 | { SkBlendModeCoeff::kZero, SkBlendModeCoeff::kZero }, |
55 | { SkBlendModeCoeff::kOne, SkBlendModeCoeff::kZero }, |
56 | { SkBlendModeCoeff::kZero, SkBlendModeCoeff::kOne }, |
57 | { SkBlendModeCoeff::kOne, SkBlendModeCoeff::kISA }, |
58 | { SkBlendModeCoeff::kIDA, SkBlendModeCoeff::kOne }, |
59 | { SkBlendModeCoeff::kDA, SkBlendModeCoeff::kZero }, |
60 | { SkBlendModeCoeff::kZero, SkBlendModeCoeff::kSA }, |
61 | { SkBlendModeCoeff::kIDA, SkBlendModeCoeff::kZero }, |
62 | { SkBlendModeCoeff::kZero, SkBlendModeCoeff::kISA }, |
63 | { SkBlendModeCoeff::kDA, SkBlendModeCoeff::kISA }, |
64 | { SkBlendModeCoeff::kIDA, SkBlendModeCoeff::kSA }, |
65 | { SkBlendModeCoeff::kIDA, SkBlendModeCoeff::kISA }, |
66 | |
67 | { SkBlendModeCoeff::kOne, SkBlendModeCoeff::kOne }, |
68 | { SkBlendModeCoeff::kZero, SkBlendModeCoeff::kSC }, |
69 | { SkBlendModeCoeff::kOne, SkBlendModeCoeff::kISC }, // screen |
70 | }; |
71 | |
72 | bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst) { |
73 | if (mode > SkBlendMode::kScreen) { |
74 | return false; |
75 | } |
76 | if (src) { |
77 | *src = gCoeffs[static_cast<int>(mode)].fSrc; |
78 | } |
79 | if (dst) { |
80 | *dst = gCoeffs[static_cast<int>(mode)].fDst; |
81 | } |
82 | return true; |
83 | } |
84 | |
85 | void SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) { |
86 | auto stage = SkRasterPipeline::srcover; |
87 | switch (mode) { |
88 | case SkBlendMode::kClear: stage = SkRasterPipeline::clear; break; |
89 | case SkBlendMode::kSrc: return; // This stage is a no-op. |
90 | case SkBlendMode::kDst: stage = SkRasterPipeline::move_dst_src; break; |
91 | case SkBlendMode::kSrcOver: stage = SkRasterPipeline::srcover; break; |
92 | case SkBlendMode::kDstOver: stage = SkRasterPipeline::dstover; break; |
93 | case SkBlendMode::kSrcIn: stage = SkRasterPipeline::srcin; break; |
94 | case SkBlendMode::kDstIn: stage = SkRasterPipeline::dstin; break; |
95 | case SkBlendMode::kSrcOut: stage = SkRasterPipeline::srcout; break; |
96 | case SkBlendMode::kDstOut: stage = SkRasterPipeline::dstout; break; |
97 | case SkBlendMode::kSrcATop: stage = SkRasterPipeline::srcatop; break; |
98 | case SkBlendMode::kDstATop: stage = SkRasterPipeline::dstatop; break; |
99 | case SkBlendMode::kXor: stage = SkRasterPipeline::xor_; break; |
100 | case SkBlendMode::kPlus: stage = SkRasterPipeline::plus_; break; |
101 | case SkBlendMode::kModulate: stage = SkRasterPipeline::modulate; break; |
102 | |
103 | case SkBlendMode::kScreen: stage = SkRasterPipeline::screen; break; |
104 | case SkBlendMode::kOverlay: stage = SkRasterPipeline::overlay; break; |
105 | case SkBlendMode::kDarken: stage = SkRasterPipeline::darken; break; |
106 | case SkBlendMode::kLighten: stage = SkRasterPipeline::lighten; break; |
107 | case SkBlendMode::kColorDodge: stage = SkRasterPipeline::colordodge; break; |
108 | case SkBlendMode::kColorBurn: stage = SkRasterPipeline::colorburn; break; |
109 | case SkBlendMode::kHardLight: stage = SkRasterPipeline::hardlight; break; |
110 | case SkBlendMode::kSoftLight: stage = SkRasterPipeline::softlight; break; |
111 | case SkBlendMode::kDifference: stage = SkRasterPipeline::difference; break; |
112 | case SkBlendMode::kExclusion: stage = SkRasterPipeline::exclusion; break; |
113 | case SkBlendMode::kMultiply: stage = SkRasterPipeline::multiply; break; |
114 | |
115 | case SkBlendMode::kHue: stage = SkRasterPipeline::hue; break; |
116 | case SkBlendMode::kSaturation: stage = SkRasterPipeline::saturation; break; |
117 | case SkBlendMode::kColor: stage = SkRasterPipeline::color; break; |
118 | case SkBlendMode::kLuminosity: stage = SkRasterPipeline::luminosity; break; |
119 | } |
120 | p->append(stage); |
121 | } |
122 | |
123 | SkPMColor4f SkBlendMode_Apply(SkBlendMode mode, const SkPMColor4f& src, const SkPMColor4f& dst) { |
124 | // special-case simple/common modes... |
125 | switch (mode) { |
126 | case SkBlendMode::kClear: return SK_PMColor4fTRANSPARENT; |
127 | case SkBlendMode::kSrc: return src; |
128 | case SkBlendMode::kDst: return dst; |
129 | case SkBlendMode::kSrcOver: { |
130 | Sk4f r = Sk4f::Load(src.vec()) + Sk4f::Load(dst.vec()) * Sk4f(1 - src.fA); |
131 | return { r[0], r[1], r[2], r[3] }; |
132 | } |
133 | default: |
134 | break; |
135 | } |
136 | |
137 | SkRasterPipeline_<256> p; |
138 | SkPMColor4f src_storage = src, |
139 | dst_storage = dst, |
140 | res_storage; |
141 | SkRasterPipeline_MemoryCtx src_ctx = { &src_storage, 0 }, |
142 | dst_ctx = { &dst_storage, 0 }, |
143 | res_ctx = { &res_storage, 0 }; |
144 | |
145 | p.append(SkRasterPipeline::load_f32, &dst_ctx); |
146 | p.append(SkRasterPipeline::move_src_dst); |
147 | p.append(SkRasterPipeline::load_f32, &src_ctx); |
148 | SkBlendMode_AppendStages(mode, &p); |
149 | p.append(SkRasterPipeline::store_f32, &res_ctx); |
150 | p.run(0,0, 1,1); |
151 | return res_storage; |
152 | } |
153 | |
154 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
155 | |
156 | const SkBlendMode gUncorrelatedCoverageToBlend[] = { |
157 | SkBlendMode::kSrcOver, // or DstOver |
158 | SkBlendMode::kSrcIn, // or kDstIn |
159 | SkBlendMode::kSrcOut, |
160 | SkBlendMode::kDstOut, |
161 | SkBlendMode::kXor, |
162 | }; |
163 | |
164 | SkBlendMode SkUncorrelatedCoverageModeToBlendMode(SkCoverageMode cm) { |
165 | unsigned index = static_cast<unsigned>(cm); |
166 | SkASSERT(index < SK_ARRAY_COUNT(gUncorrelatedCoverageToBlend)); |
167 | return gUncorrelatedCoverageToBlend[index]; |
168 | } |
169 | |