Index: src/core/SkXfermode.cpp |
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp |
index 928fa5001eaa655fa577310505b46a127eef122e..99f83f9f3dec80700c7e8422e56d77a150ef57a8 100644 |
--- a/src/core/SkXfermode.cpp |
+++ b/src/core/SkXfermode.cpp |
@@ -1241,6 +1241,30 @@ XFERMODE(Exclusion) { |
#undef XFERMODE |
+// A reasonable fallback mode for doing AA is to simply apply the transfermode first, |
+// then linearly interpolate the AA. |
+template <typename Mode> |
+static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk16b& aa) { |
+ Sk4px noAA = Mode::Xfer(s, d); |
+ return Sk4px::Wide(noAA.mulWiden(aa) + d.mulWiden(Sk4px(aa).inv())) |
+ .div255RoundNarrow(); |
+} |
+ |
+// For some transfermodes we specialize AA, either for correctness or performance. |
+#ifndef SK_NO_SPECIALIZED_AA_XFERMODES |
+ #define XFERMODE_AA(Name) \ |
+ template <> Sk4px xfer_aa<Name>(const Sk4px& s, const Sk4px& d, const Sk16b& aa) |
+ |
+ // Plus' clamp needs to happen after AA. skia:3852 |
+ XFERMODE_AA(Plus) { // [ clamp(D + AA*S) ] |
+ // We implement this as D + Min(S*AA, (1-D)) to fit the arguments to Min in 16 bits. |
+ return d + |
+ Sk4px::Wide(Sk16h::Min(s.mulWiden(aa), d.inv().mul255Widen())).div255RoundNarrow(); |
+ } |
+ |
+ #undef XFERMODE_AA |
+#endif |
+ |
template <typename ProcType> |
class SkT4pxXfermode : public SkProcCoeffXfermode { |
public: |
@@ -1256,9 +1280,7 @@ public: |
} else { |
Sk4px::MapDstSrcAlpha(n, dst, src, aa, |
[&](const Sk4px& dst4, const Sk4px& src4, const Sk16b& alpha) { |
- Sk4px res4 = ProcType::Xfer(src4, dst4); |
- return Sk4px::Wide(res4.mulWiden(alpha) + dst4.mulWiden(Sk4px(alpha).inv())) |
- .div255RoundNarrow(); |
+ return xfer_aa<ProcType>(src4, dst4, alpha); |
}); |
} |
} |