Index: src/core/Sk4pxXfermode.h |
diff --git a/src/core/Sk4pxXfermode.h b/src/core/Sk4pxXfermode.h |
index 97321b7413cdfe98ad8072f96f3082ac4ec98704..c671b679f82534c9c82b38d2a0ed12ba96052dad 100644 |
--- a/src/core/Sk4pxXfermode.h |
+++ b/src/core/Sk4pxXfermode.h |
@@ -62,37 +62,53 @@ XFERMODE(Exclusion) { |
return (s - p) + (d - p.zeroAlphas()); |
} |
-XFERMODE(HardLight) { |
- auto alphas = SrcOver::Xfer(s,d); |
+// We take care to use exact math for these next few modes where alphas |
+// and colors are calculated using significantly different math. We need |
+// to preserve premul invariants, and exact math makes this easier. |
+// |
+// TODO: Some of these implementations might be able to be sped up a bit |
+// while maintaining exact math, but let's follow up with that. |
+XFERMODE(HardLight) { |
auto sa = s.alphas(), |
da = d.alphas(); |
+ auto srcover = s + (d * sa.inv()).div255(); |
+ |
auto isLite = ((sa-s) < s).widenLoHi(); |
- auto dark = s*d << 1, |
- lite = sa*da - ((da-d)*(sa-s) << 1), |
+ auto lite = sa*da - ((da-d)*(sa-s) << 1), |
+ dark = s*d << 1, |
both = s*da.inv() + d*sa.inv(); |
+ auto alphas = srcover; |
auto colors = (both + isLite.thenElse(lite, dark)).div255(); |
return alphas.zeroColors() + colors.zeroAlphas(); |
} |
XFERMODE(Overlay) { return HardLight::Xfer(d,s); } |
XFERMODE(Darken) { |
- auto sda = s.approxMulDiv255(d.alphas()), |
- dsa = d.approxMulDiv255(s.alphas()); |
- auto srcover = s + (d - dsa), |
- dstover = d + (s - sda); |
+ auto sa = s.alphas(), |
+ da = d.alphas(); |
+ |
+ auto sda = (s*da).div255(), |
+ dsa = (d*sa).div255(); |
+ |
+ auto srcover = s + (d * sa.inv()).div255(), |
+ dstover = d + (s * da.inv()).div255(); |
auto alphas = srcover, |
colors = (sda < dsa).thenElse(srcover, dstover); |
return alphas.zeroColors() + colors.zeroAlphas(); |
} |
XFERMODE(Lighten) { |
- auto sda = s.approxMulDiv255(d.alphas()), |
- dsa = d.approxMulDiv255(s.alphas()); |
- auto srcover = s + (d - dsa), |
- dstover = d + (s - sda); |
+ auto sa = s.alphas(), |
+ da = d.alphas(); |
+ |
+ auto sda = (s*da).div255(), |
+ dsa = (d*sa).div255(); |
+ |
+ auto srcover = s + (d * sa.inv()).div255(), |
+ dstover = d + (s * da.inv()).div255(); |
auto alphas = srcover, |
colors = (dsa < sda).thenElse(srcover, dstover); |
return alphas.zeroColors() + colors.zeroAlphas(); |