OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2015 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 #ifndef Sk4pxXfermode_DEFINED |
| 9 #define Sk4pxXfermode_DEFINED |
| 10 |
| 11 #include "Sk4px.h" |
| 12 |
| 13 // This file is possibly included into multiple .cpp files. |
| 14 // Each gets its own independent instantiation by wrapping in an anonymous names
pace. |
| 15 namespace { |
| 16 |
| 17 #define XFERMODE(Name) \ |
| 18 struct Name { \ |
| 19 static Sk4px Xfer(const Sk4px&, const Sk4px&); \ |
| 20 static const SkXfermode::Mode kMode = SkXfermode::k##Name##_Mode; \ |
| 21 }; \ |
| 22 inline Sk4px Name::Xfer(const Sk4px& s, const Sk4px& d) |
| 23 |
| 24 XFERMODE(Clear) { return Sk4px((SkPMColor)0); } |
| 25 XFERMODE(Src) { return s; } |
| 26 XFERMODE(Dst) { return d; } |
| 27 XFERMODE(SrcIn) { return s.fastMulDiv255Round(d.alphas() ); } |
| 28 XFERMODE(SrcOut) { return s.fastMulDiv255Round(d.alphas().inv()); } |
| 29 XFERMODE(SrcOver) { return s + d.fastMulDiv255Round(s.alphas().inv()); } |
| 30 XFERMODE(DstIn) { return SrcIn ::Xfer(d,s); } |
| 31 XFERMODE(DstOut) { return SrcOut ::Xfer(d,s); } |
| 32 XFERMODE(DstOver) { return SrcOver::Xfer(d,s); } |
| 33 |
| 34 // [ S * Da + (1 - Sa) * D] |
| 35 XFERMODE(SrcATop) { |
| 36 return Sk4px::Wide(s.mulWiden(d.alphas()) + d.mulWiden(s.alphas().inv())) |
| 37 .div255RoundNarrow(); |
| 38 } |
| 39 XFERMODE(DstATop) { return SrcATop::Xfer(d,s); } |
| 40 //[ S * (1 - Da) + (1 - Sa) * D ] |
| 41 XFERMODE(Xor) { |
| 42 return Sk4px::Wide(s.mulWiden(d.alphas().inv()) + d.mulWiden(s.alphas().inv(
))) |
| 43 .div255RoundNarrow(); |
| 44 } |
| 45 // [S + D ] |
| 46 XFERMODE(Plus) { return s.saturatedAdd(d); } |
| 47 // [S * D ] |
| 48 XFERMODE(Modulate) { return s.fastMulDiv255Round(d); } |
| 49 // [S + D - S * D] |
| 50 XFERMODE(Screen) { |
| 51 // Doing the math as S + (1-S)*D or S + (D - S*D) means the add and subtract
can be done |
| 52 // in 8-bit space without overflow. S + (1-S)*D is a touch faster because i
nv() is cheap. |
| 53 return s + d.fastMulDiv255Round(s.inv()); |
| 54 } |
| 55 XFERMODE(Multiply) { |
| 56 return Sk4px::Wide(s.mulWiden(d.alphas().inv()) + |
| 57 d.mulWiden(s.alphas().inv()) + |
| 58 s.mulWiden(d)) |
| 59 .div255RoundNarrow(); |
| 60 } |
| 61 // [ Sa + Da - Sa*Da, Sc + Dc - 2*min(Sc*Da, Dc*Sa) ] (And notice Sa*Da == min(
Sa*Da, Da*Sa).) |
| 62 XFERMODE(Difference) { |
| 63 auto m = Sk4px::Wide(Sk16h::Min(s.mulWiden(d.alphas()), d.mulWiden(s.alphas(
)))) |
| 64 .div255RoundNarrow(); |
| 65 // There's no chance of underflow, and if we subtract m before adding s+d, n
o overflow. |
| 66 return (s - m) + (d - m.zeroAlphas()); |
| 67 } |
| 68 // [ Sa + Da - Sa*Da, Sc + Dc - 2*Sc*Dc ] |
| 69 XFERMODE(Exclusion) { |
| 70 auto p = s.fastMulDiv255Round(d); |
| 71 // There's no chance of underflow, and if we subtract p before adding src+ds
t, no overflow. |
| 72 return (s - p) + (d - p.zeroAlphas()); |
| 73 } |
| 74 |
| 75 #undef XFERMODE |
| 76 |
| 77 // A reasonable fallback mode for doing AA is to simply apply the transfermode f
irst, |
| 78 // then linearly interpolate the AA. |
| 79 template <typename Mode> |
| 80 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk16b& aa) { |
| 81 Sk4px noAA = Mode::Xfer(s, d); |
| 82 return Sk4px::Wide(noAA.mulWiden(aa) + d.mulWiden(Sk4px(aa).inv())) |
| 83 .div255RoundNarrow(); |
| 84 } |
| 85 |
| 86 // For some transfermodes we specialize AA, either for correctness or performanc
e. |
| 87 #ifndef SK_NO_SPECIALIZED_AA_XFERMODES |
| 88 #define XFERMODE_AA(Name) \ |
| 89 template <> Sk4px xfer_aa<Name>(const Sk4px& s, const Sk4px& d, const Sk
16b& aa) |
| 90 |
| 91 // Plus' clamp needs to happen after AA. skia:3852 |
| 92 XFERMODE_AA(Plus) { // [ clamp(D + AA*S) ] |
| 93 // We implement this as D + Min(S*AA, (1-D)) to fit the arguments to Min
in 16 bits. |
| 94 return d + |
| 95 Sk4px::Wide(Sk16h::Min(s.mulWiden(aa), d.inv().mul255Widen())).div25
5RoundNarrow(); |
| 96 } |
| 97 |
| 98 #undef XFERMODE_AA |
| 99 #endif |
| 100 |
| 101 template <typename ProcType> |
| 102 class SkT4pxXfermode : public SkProcCoeffXfermode { |
| 103 public: |
| 104 static SkProcCoeffXfermode* Create(const ProcCoeff& rec) { |
| 105 return SkNEW_ARGS(SkT4pxXfermode, (rec)); |
| 106 } |
| 107 |
| 108 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[
]) const override { |
| 109 if (NULL == aa) { |
| 110 Sk4px::MapDstSrc(n, dst, src, [&](const Sk4px& dst4, const Sk4px& sr
c4) { |
| 111 return ProcType::Xfer(src4, dst4); |
| 112 }); |
| 113 } else { |
| 114 Sk4px::MapDstSrcAlpha(n, dst, src, aa, |
| 115 [&](const Sk4px& dst4, const Sk4px& src4, const Sk16b& alpha
) { |
| 116 return xfer_aa<ProcType>(src4, dst4, alpha); |
| 117 }); |
| 118 } |
| 119 } |
| 120 |
| 121 private: |
| 122 SkT4pxXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, ProcType::kM
ode) {} |
| 123 |
| 124 typedef SkProcCoeffXfermode INHERITED; |
| 125 }; |
| 126 |
| 127 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode
::Mode mode) { |
| 128 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) |
| 129 switch (mode) { |
| 130 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create(
rec); |
| 131 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re
c); |
| 132 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re
c); |
| 133 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat
e(rec); |
| 134 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat
e(rec); |
| 135 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create(
rec); |
| 136 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create(
rec); |
| 137 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create
(rec); |
| 138 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create
(rec); |
| 139 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat
e(rec); |
| 140 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat
e(rec); |
| 141 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re
c); |
| 142 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r
ec); |
| 143 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea
te(rec); |
| 144 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create
(rec); |
| 145 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea
te(rec); |
| 146 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr
eate(rec); |
| 147 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre
ate(rec); |
| 148 default: break; |
| 149 } |
| 150 #endif |
| 151 return nullptr; |
| 152 } |
| 153 |
| 154 } // namespace |
| 155 |
| 156 #endif//Sk4pxXfermode_DEFINED |
OLD | NEW |