LibWeb: Reduce inaccuracies when creating rotation matrices

When converting rotate transform functions `sin` and `cos` can sometimes
be inaccurate. To avoid these inaccuracies we:
 - Mod the angle to minimise inaccuracies in the first place.
 - Discard tiny (smaller than epsilon) values returned by `sin` and
   `cos` as inaccuracies.

This is in line with  other browsers (e.g. Gecko and WebKit).
This commit is contained in:
Callum Law 2025-08-03 21:05:26 +12:00 committed by Sam Atkins
parent 719ab5735e
commit 7182a537f3
5 changed files with 20 additions and 13 deletions

View File

@ -63,6 +63,13 @@ constexpr static Matrix4x4<T> rotation_matrix(Vector3<T> const& axis, T angle)
{
T c, s;
AK::sincos(angle, s, c);
if (abs(c) < AK::NumericLimits<T>::epsilon())
c = 0.0;
if (abs(s) < AK::NumericLimits<T>::epsilon())
s = 0.0;
T t = 1 - c;
T x = axis.x();
T y = axis.y();

View File

@ -28,9 +28,9 @@ ErrorOr<Gfx::FloatMatrix4x4> Transformation::to_matrix(Optional<Painting::Painta
return m_values[index].visit(
[&](CSS::AngleOrCalculated const& value) -> ErrorOr<float> {
if (!value.is_calculated())
return value.value().to_radians();
return fmod(value.value().to_radians(), 2 * AK::Pi<double>);
if (auto resolved = value.resolved(context); resolved.has_value())
return resolved->to_radians();
return fmod(resolved->to_radians(), 2 * AK::Pi<double>);
return Error::from_string_literal("Transform contains non absolute units");
},
[&](CSS::LengthPercentage const& value) -> ErrorOr<float> {

View File

@ -25,10 +25,10 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x996]
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x996] [children: 7] (z-index: auto)
SC for BlockContainer<DIV>.sin [8,8 80x100] [children: 0] (z-index: auto), transform: [-4.371139e-8 1 -1 -4.371139e-8 0 0]
SC for BlockContainer<DIV>.cos [8,108 100x100] [children: 0] (z-index: auto), transform: [-4.371139e-8 1 -1 -4.371139e-8 0 0]
SC for BlockContainer<DIV>.tan [8,208 120x100] [children: 0] (z-index: auto), transform: [-4.371139e-8 1 -1 -4.371139e-8 0 0]
SC for BlockContainer<DIV>.asin [8,308 100x140] [children: 0] (z-index: auto), transform: [-4.371139e-8 1 -1 -4.371139e-8 0 0]
SC for BlockContainer<DIV>.acos [8,448 100x160] [children: 0] (z-index: auto), transform: [-4.371139e-8 1 -1 -4.371139e-8 0 0]
SC for BlockContainer<DIV>.atan [8,608 100x180] [children: 0] (z-index: auto), transform: [-4.371139e-8 1 -1 -4.371139e-8 0 0]
SC for BlockContainer<DIV>.atan2 [8,788 100x200] [children: 0] (z-index: auto), transform: [-4.371139e-8 1 -1 -4.371139e-8 0 0]
SC for BlockContainer<DIV>.sin [8,8 80x100] [children: 0] (z-index: auto), transform: [0 1 -1 0 0 0]
SC for BlockContainer<DIV>.cos [8,108 100x100] [children: 0] (z-index: auto), transform: [0 1 -1 0 0 0]
SC for BlockContainer<DIV>.tan [8,208 120x100] [children: 0] (z-index: auto), transform: [0 1 -1 0 0 0]
SC for BlockContainer<DIV>.asin [8,308 100x140] [children: 0] (z-index: auto), transform: [0 1 -1 0 0 0]
SC for BlockContainer<DIV>.acos [8,448 100x160] [children: 0] (z-index: auto), transform: [0 1 -1 0 0 0]
SC for BlockContainer<DIV>.atan [8,608 100x180] [children: 0] (z-index: auto), transform: [0 1 -1 0 0 0]
SC for BlockContainer<DIV>.atan2 [8,788 100x200] [children: 0] (z-index: auto), transform: [0 1 -1 0 0 0]

View File

@ -24,8 +24,8 @@ scale3d(100%, 200%, 150%) => matrix3d(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1.5, 0, 0, 0
rotate(1deg) => matrix(0.9998477101325989, 0.017452405765652657, -0.017452405765652657, 0.9998477101325989, 0, 0)
rotateX(1rad) => matrix3d(1, 0, 0, 0, 0, 0.5403022766113281, 0.8414709568023682, 0, 0, -0.8414709568023682, 0.5403022766113281, 0, 0, 0, 0, 1)
rotateY(1grad) => matrix3d(0.9998766183853149, 0, -0.015707317739725113, 0, 0, 1, 0, 0, 0.015707317739725113, 0, 0.9998766183853149, 0, 0, 0, 0, 1)
rotateZ(1turn) => matrix(1, 1.7484555314695172e-7, -1.7484555314695172e-7, 1, 0, 0)
rotate3d(0, 1, 0, 45rad) => matrix3d(0.5253219604492188, 0, -0.8509035110473633, 0, 0, 1, 0, 0, 0.8509035110473633, 0, 0.5253219604492188, 0, 0, 0, 0, 1)
rotateZ(1turn) => matrix(1, 0, 0, 1, 0, 0)
rotate3d(0, 1, 0, 45rad) => matrix3d(0.5253220200538635, 0, -0.8509035110473633, 0, 0, 1, 0, 0, 0.8509035110473633, 0, 0.5253220200538635, 0, 0, 0, 0, 1)
skew(1deg, 1rad) => matrix(1, 1.5574077367782593, 0.01745506562292576, 1, 0, 0)
skewX(1deg) => matrix(1, 0, 0.01745506562292576, 1, 0, 0)
skewY(1rad) => matrix(1, 1.5574077367782593, 0, 1, 0, 0)

View File

@ -2,7 +2,7 @@
2. 35.06980604270564
3. 22.06722747248274
4. 26.483172559777778
5. {"a":30,"b":40,"c":-9.999999999999998,"d":-19.999999999999996,"e":50,"f":60,"m11":30,"m12":40,"m13":0,"m14":0,"m21":-9.999999999999998,"m22":-19.999999999999996,"m23":0,"m24":0,"m31":0,"m32":0,"m33":1,"m34":0,"m41":50,"m42":60,"m43":0,"m44":1,"is2D":true,"isIdentity":false}
6. {"a":30,"b":40,"c":-9.999999999999998,"d":-19.999999999999996,"e":50,"f":60,"m11":30,"m12":40,"m13":0,"m14":0,"m21":-9.999999999999998,"m22":-19.999999999999996,"m23":0,"m24":0,"m31":0,"m32":0,"m33":1,"m34":0,"m41":50,"m42":60,"m43":0,"m44":1,"is2D":true,"isIdentity":false}
5. {"a":30,"b":40,"c":-10,"d":-20,"e":50,"f":60,"m11":30,"m12":40,"m13":0,"m14":0,"m21":-10,"m22":-20,"m23":0,"m24":0,"m31":0,"m32":0,"m33":1,"m34":0,"m41":50,"m42":60,"m43":0,"m44":1,"is2D":true,"isIdentity":false}
6. {"a":30,"b":40,"c":-10,"d":-20,"e":50,"f":60,"m11":30,"m12":40,"m13":0,"m14":0,"m21":-10,"m22":-20,"m23":0,"m24":0,"m31":0,"m32":0,"m33":1,"m34":0,"m41":50,"m42":60,"m43":0,"m44":1,"is2D":true,"isIdentity":false}
7. {"a":9.84807753012208,"b":19.69615506024416,"c":30,"d":40,"e":50,"f":60,"m11":9.84807753012208,"m12":19.69615506024416,"m13":-0.17364817766693033,"m14":0,"m21":30,"m22":40,"m23":0,"m24":0,"m31":1.7364817766693033,"m32":3.4729635533386065,"m33":0.984807753012208,"m34":0,"m41":50,"m42":60,"m43":0,"m44":1,"is2D":false,"isIdentity":false}
8. {"a":9.84807753012208,"b":19.69615506024416,"c":30,"d":40,"e":50,"f":60,"m11":9.84807753012208,"m12":19.69615506024416,"m13":-0.17364817766693033,"m14":0,"m21":30,"m22":40,"m23":0,"m24":0,"m31":1.7364817766693033,"m32":3.4729635533386065,"m33":0.984807753012208,"m34":0,"m41":50,"m42":60,"m43":0,"m44":1,"is2D":false,"isIdentity":false}