| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef Sk4pxXfermode_DEFINED | 8 #ifndef Sk4pxXfermode_DEFINED |
| 9 #define Sk4pxXfermode_DEFINED | 9 #define Sk4pxXfermode_DEFINED |
| 10 | 10 |
| 11 #include "Sk4px.h" | 11 #include "Sk4px.h" |
| 12 #include "SkPMFloat.h" |
| 12 | 13 |
| 13 // This file is possibly included into multiple .cpp files. | 14 // This file is possibly included into multiple .cpp files. |
| 14 // Each gets its own independent instantiation by wrapping in an anonymous names
pace. | 15 // Each gets its own independent instantiation by wrapping in an anonymous names
pace. |
| 15 namespace { | 16 namespace { |
| 16 | 17 |
| 18 // Most xfermodes can be done most efficiently 4 pixels at a time in 8 or 16-bit
fixed point. |
| 17 #define XFERMODE(Name) \ | 19 #define XFERMODE(Name) \ |
| 18 struct Name { \ | 20 struct Name { \ |
| 19 static Sk4px Xfer(const Sk4px&, const Sk4px&); \ | 21 static Sk4px Xfer(const Sk4px&, const Sk4px&); \ |
| 20 static const SkXfermode::Mode kMode = SkXfermode::k##Name##_Mode; \ | 22 static const SkXfermode::Mode kMode = SkXfermode::k##Name##_Mode; \ |
| 21 }; \ | 23 }; \ |
| 22 inline Sk4px Name::Xfer(const Sk4px& s, const Sk4px& d) | 24 inline Sk4px Name::Xfer(const Sk4px& s, const Sk4px& d) |
| 23 | 25 |
| 24 XFERMODE(Clear) { return Sk4px::DupPMColor(0); } | 26 XFERMODE(Clear) { return Sk4px::DupPMColor(0); } |
| 25 XFERMODE(Src) { return s; } | 27 XFERMODE(Src) { return s; } |
| 26 XFERMODE(Dst) { return d; } | 28 XFERMODE(Dst) { return d; } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 } | 92 } |
| 91 XFERMODE(Lighten) { | 93 XFERMODE(Lighten) { |
| 92 auto sda = s.approxMulDiv255(d.alphas()), | 94 auto sda = s.approxMulDiv255(d.alphas()), |
| 93 dsa = d.approxMulDiv255(s.alphas()); | 95 dsa = d.approxMulDiv255(s.alphas()); |
| 94 auto srcover = s + (d - dsa), | 96 auto srcover = s + (d - dsa), |
| 95 dstover = d + (s - sda); | 97 dstover = d + (s - sda); |
| 96 auto alphas = srcover, | 98 auto alphas = srcover, |
| 97 colors = (sda < dsa).thenElse(dstover, srcover); | 99 colors = (sda < dsa).thenElse(dstover, srcover); |
| 98 return alphas.zeroColors() + colors.zeroAlphas(); | 100 return alphas.zeroColors() + colors.zeroAlphas(); |
| 99 } | 101 } |
| 102 #undef XFERMODE |
| 100 | 103 |
| 104 // Some xfermodes use math like divide or sqrt that's best done in floats 1 pixe
l at a time. |
| 105 #define XFERMODE(Name) \ |
| 106 struct Name { \ |
| 107 static SkPMFloat Xfer(const SkPMFloat&, const SkPMFloat&); \ |
| 108 static const SkXfermode::Mode kMode = SkXfermode::k##Name##_Mode; \ |
| 109 }; \ |
| 110 inline SkPMFloat Name::Xfer(const SkPMFloat& s, const SkPMFloat& d) |
| 111 |
| 112 XFERMODE(ColorDodge) { |
| 113 auto sa = s.alphas(), |
| 114 da = d.alphas(), |
| 115 isa = Sk4f(1)-sa, |
| 116 ida = Sk4f(1)-da; |
| 117 |
| 118 auto srcover = s + d*isa, |
| 119 dstover = d + s*ida, |
| 120 otherwise = sa * Sk4f::Min(da, (d*sa)*(sa-s).approxInvert()) + s*ida +
d*isa; |
| 121 |
| 122 // Order matters here, preferring d==0 over s==sa. |
| 123 auto colors = (d == Sk4f(0)).thenElse(dstover, |
| 124 (s == sa).thenElse(srcover, |
| 125 otherwise)); |
| 126 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); |
| 127 } |
| 128 XFERMODE(ColorBurn) { |
| 129 auto sa = s.alphas(), |
| 130 da = d.alphas(), |
| 131 isa = Sk4f(1)-sa, |
| 132 ida = Sk4f(1)-da; |
| 133 |
| 134 auto srcover = s + d*isa, |
| 135 dstover = d + s*ida, |
| 136 otherwise = sa*(da-Sk4f::Min(da, (da-d)*sa*s.approxInvert())) + s*ida +
d*isa; |
| 137 |
| 138 // Order matters here, preferring d==da over s==0. |
| 139 auto colors = (d == da).thenElse(dstover, |
| 140 (s == Sk4f(0)).thenElse(srcover, |
| 141 otherwise)); |
| 142 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); |
| 143 } |
| 101 #undef XFERMODE | 144 #undef XFERMODE |
| 102 | 145 |
| 103 // A reasonable fallback mode for doing AA is to simply apply the transfermode f
irst, | 146 // A reasonable fallback mode for doing AA is to simply apply the transfermode f
irst, |
| 104 // then linearly interpolate the AA. | 147 // then linearly interpolate the AA. |
| 105 template <typename Mode> | 148 template <typename Mode> |
| 106 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { | 149 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { |
| 107 Sk4px bw = Mode::Xfer(s, d); | 150 Sk4px bw = Mode::Xfer(s, d); |
| 108 return (bw * aa + d * aa.inv()).div255(); | 151 return (bw * aa + d * aa.inv()).div255(); |
| 109 } | 152 } |
| 110 | 153 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 133 }); | 176 }); |
| 134 } else { | 177 } else { |
| 135 Sk4px::MapDstSrcAlpha(n, dst, src, aa, | 178 Sk4px::MapDstSrcAlpha(n, dst, src, aa, |
| 136 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha
) { | 179 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha
) { |
| 137 return xfer_aa<ProcType>(src4, dst4, alpha); | 180 return xfer_aa<ProcType>(src4, dst4, alpha); |
| 138 }); | 181 }); |
| 139 } | 182 } |
| 140 } | 183 } |
| 141 | 184 |
| 142 private: | 185 private: |
| 143 SkT4pxXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, ProcType::kM
ode) {} | 186 SkT4pxXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) {} |
| 144 | 187 |
| 145 typedef SkProcCoeffXfermode INHERITED; | 188 typedef SkProcCoeffXfermode INHERITED; |
| 146 }; | 189 }; |
| 190 |
| 191 template <typename ProcType> |
| 192 class SkTPMFloatXfermode : public SkProcCoeffXfermode { |
| 193 public: |
| 194 static SkProcCoeffXfermode* Create(const ProcCoeff& rec) { |
| 195 return SkNEW_ARGS(SkTPMFloatXfermode, (rec)); |
| 196 } |
| 197 |
| 198 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[
]) const override { |
| 199 for (int i = 0; i < n; i++) { |
| 200 SkPMFloat s(src[i]), |
| 201 d(dst[i]), |
| 202 b(ProcType::Xfer(s,d)); |
| 203 if (aa) { |
| 204 // We do aa in full float precision before going back down to by
tes, because we can! |
| 205 SkPMFloat a = Sk4f(aa[i]) * Sk4f(1.0f/255); |
| 206 b = b*a + d*(Sk4f(1)-a); |
| 207 } |
| 208 dst[i] = b.round(); |
| 209 } |
| 210 } |
| 211 |
| 212 private: |
| 213 SkTPMFloatXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) {
} |
| 214 |
| 215 typedef SkProcCoeffXfermode INHERITED; |
| 216 }; |
| 147 | 217 |
| 148 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode
::Mode mode) { | 218 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode
::Mode mode) { |
| 149 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) | 219 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) |
| 150 switch (mode) { | 220 switch (mode) { |
| 151 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create(
rec); | 221 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create(
rec); |
| 152 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re
c); | 222 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re
c); |
| 153 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re
c); | 223 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re
c); |
| 154 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat
e(rec); | 224 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat
e(rec); |
| 155 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat
e(rec); | 225 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat
e(rec); |
| 156 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create(
rec); | 226 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create(
rec); |
| 157 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create(
rec); | 227 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create(
rec); |
| 158 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create
(rec); | 228 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create
(rec); |
| 159 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create
(rec); | 229 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create
(rec); |
| 160 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat
e(rec); | 230 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat
e(rec); |
| 161 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat
e(rec); | 231 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat
e(rec); |
| 162 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re
c); | 232 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re
c); |
| 163 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r
ec); | 233 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r
ec); |
| 164 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea
te(rec); | 234 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea
te(rec); |
| 165 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create
(rec); | 235 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create
(rec); |
| 166 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea
te(rec); | 236 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea
te(rec); |
| 167 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr
eate(rec); | 237 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr
eate(rec); |
| 168 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre
ate(rec); | 238 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre
ate(rec); |
| 169 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test
s). | 239 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test
s). |
| 170 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre
ate(rec); | 240 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre
ate(rec); |
| 171 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat
e(rec); | 241 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat
e(rec); |
| 172 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create
(rec); | 242 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create
(rec); |
| 173 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat
e(rec); | 243 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat
e(rec); |
| 244 |
| 245 case SkXfermode::kColorDodge_Mode: return SkTPMFloatXfermode<ColorDodge>
::Create(rec); |
| 246 case SkXfermode::kColorBurn_Mode: return SkTPMFloatXfermode<ColorBurn>:
:Create(rec); |
| 174 #endif | 247 #endif |
| 175 default: break; | 248 default: break; |
| 176 } | 249 } |
| 177 #endif | 250 #endif |
| 178 return nullptr; | 251 return nullptr; |
| 179 } | 252 } |
| 180 | 253 |
| 181 } // namespace | 254 } // namespace |
| 182 | 255 |
| 183 #endif//Sk4pxXfermode_DEFINED | 256 #endif//Sk4pxXfermode_DEFINED |
| OLD | NEW |