Chromium Code Reviews| 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(), | |
|
reed1
2015/06/26 17:17:58
in general, I just love the expressiveness of SkPM
| |
| 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 | |
| 121 auto colors = (d == Sk4f(0)).thenElse(dstover, | |
|
reed1
2015/06/26 17:17:58
After staring for a while, it looks like this is a
mtklein
2015/06/26 17:39:56
Acknowledged.
| |
| 122 (s == sa).thenElse(srcover, | |
| 123 sa * Sk4f::Min(da, (d*sa)*(sa-s).approxInvert()) + s*ida + d*isa)); | |
| 124 | |
| 125 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); | |
| 126 } | |
| 127 XFERMODE(ColorBurn) { | |
| 128 auto sa = s.alphas(), | |
| 129 da = d.alphas(), | |
| 130 isa = Sk4f(1)-sa, | |
| 131 ida = Sk4f(1)-da; | |
| 132 | |
| 133 auto srcover = s + d*isa, | |
| 134 dstover = d + s*ida; | |
| 135 | |
| 136 auto colors = (d == da).thenElse(dstover, | |
| 137 (s == Sk4f(0)).thenElse(srcover, | |
| 138 sa*(da-Sk4f::Min(da, (da-d)*sa*s.approxInvert())) + s*ida + d*isa)); | |
| 139 | |
| 140 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); | |
| 141 } | |
| 101 #undef XFERMODE | 142 #undef XFERMODE |
| 102 | 143 |
| 103 // A reasonable fallback mode for doing AA is to simply apply the transfermode f irst, | 144 // A reasonable fallback mode for doing AA is to simply apply the transfermode f irst, |
| 104 // then linearly interpolate the AA. | 145 // then linearly interpolate the AA. |
| 105 template <typename Mode> | 146 template <typename Mode> |
| 106 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { | 147 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { |
| 107 Sk4px bw = Mode::Xfer(s, d); | 148 Sk4px bw = Mode::Xfer(s, d); |
| 108 return (bw * aa + d * aa.inv()).div255(); | 149 return (bw * aa + d * aa.inv()).div255(); |
| 109 } | 150 } |
| 110 | 151 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 133 }); | 174 }); |
| 134 } else { | 175 } else { |
| 135 Sk4px::MapDstSrcAlpha(n, dst, src, aa, | 176 Sk4px::MapDstSrcAlpha(n, dst, src, aa, |
| 136 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha ) { | 177 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha ) { |
| 137 return xfer_aa<ProcType>(src4, dst4, alpha); | 178 return xfer_aa<ProcType>(src4, dst4, alpha); |
| 138 }); | 179 }); |
| 139 } | 180 } |
| 140 } | 181 } |
| 141 | 182 |
| 142 private: | 183 private: |
| 143 SkT4pxXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, ProcType::kM ode) {} | 184 SkT4pxXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) {} |
| 144 | 185 |
| 145 typedef SkProcCoeffXfermode INHERITED; | 186 typedef SkProcCoeffXfermode INHERITED; |
| 146 }; | 187 }; |
| 188 | |
| 189 template <typename ProcType> | |
| 190 class SkTPMFloatXfermode : public SkProcCoeffXfermode { | |
| 191 public: | |
| 192 static SkProcCoeffXfermode* Create(const ProcCoeff& rec) { | |
| 193 return SkNEW_ARGS(SkTPMFloatXfermode, (rec)); | |
| 194 } | |
| 195 | |
| 196 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[ ]) const override { | |
| 197 for (int i = 0; i < n; i++) { | |
| 198 SkPMFloat s(src[i]), | |
| 199 d(dst[i]), | |
| 200 b(ProcType::Xfer(s,d)); | |
| 201 if (aa) { | |
| 202 // We do aa in full float precision before going back down to by tes, because we can! | |
| 203 SkPMFloat a = Sk4f(aa[i]) * Sk4f(1.0f/255); | |
| 204 b = b*a + d*(Sk4f(1)-a); | |
| 205 } | |
| 206 dst[i] = b.round(); | |
| 207 } | |
| 208 } | |
| 209 | |
| 210 private: | |
| 211 SkTPMFloatXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) { } | |
| 212 | |
| 213 typedef SkProcCoeffXfermode INHERITED; | |
| 214 }; | |
| 147 | 215 |
| 148 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode ::Mode mode) { | 216 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode ::Mode mode) { |
| 149 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) | 217 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) |
| 150 switch (mode) { | 218 switch (mode) { |
| 151 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create( rec); | 219 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create( rec); |
| 152 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re c); | 220 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re c); |
| 153 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re c); | 221 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re c); |
| 154 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat e(rec); | 222 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat e(rec); |
| 155 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat e(rec); | 223 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat e(rec); |
| 156 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create( rec); | 224 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create( rec); |
| 157 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create( rec); | 225 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create( rec); |
| 158 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create (rec); | 226 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create (rec); |
| 159 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create (rec); | 227 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create (rec); |
| 160 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat e(rec); | 228 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat e(rec); |
| 161 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat e(rec); | 229 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat e(rec); |
| 162 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re c); | 230 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re c); |
| 163 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r ec); | 231 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r ec); |
| 164 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea te(rec); | 232 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea te(rec); |
| 165 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create (rec); | 233 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create (rec); |
| 166 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea te(rec); | 234 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea te(rec); |
| 167 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr eate(rec); | 235 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr eate(rec); |
| 168 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre ate(rec); | 236 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre ate(rec); |
| 169 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test s). | 237 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test s). |
| 170 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre ate(rec); | 238 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre ate(rec); |
| 171 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat e(rec); | 239 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat e(rec); |
| 172 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create (rec); | 240 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create (rec); |
| 173 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat e(rec); | 241 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat e(rec); |
| 242 | |
| 243 case SkXfermode::kColorDodge_Mode: return SkTPMFloatXfermode<ColorDodge> ::Create(rec); | |
| 244 case SkXfermode::kColorBurn_Mode: return SkTPMFloatXfermode<ColorBurn>: :Create(rec); | |
| 174 #endif | 245 #endif |
| 175 default: break; | 246 default: break; |
| 176 } | 247 } |
| 177 #endif | 248 #endif |
| 178 return nullptr; | 249 return nullptr; |
| 179 } | 250 } |
| 180 | 251 |
| 181 } // namespace | 252 } // namespace |
| 182 | 253 |
| 183 #endif//Sk4pxXfermode_DEFINED | 254 #endif//Sk4pxXfermode_DEFINED |
| OLD | NEW |