|
@@ -69,6 +69,7 @@
|
|
|
#include <LibWeb/Layout/Node.h>
|
|
|
#include <LibWeb/Loader/ResourceLoader.h>
|
|
|
#include <LibWeb/Namespace.h>
|
|
|
+#include <LibWeb/Painting/PaintableBox.h>
|
|
|
#include <LibWeb/Platform/FontPlugin.h>
|
|
|
#include <LibWeb/ReferrerPolicy/AbstractOperations.h>
|
|
|
#include <math.h>
|
|
@@ -758,18 +759,315 @@ static ErrorOr<void> cascade_custom_properties(DOM::Element& element, Optional<C
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
-static ErrorOr<NonnullRefPtr<StyleValue const>> interpolate_value(StyleValue const& from, StyleValue const& to, float delta)
|
|
|
+template<typename T>
|
|
|
+static T interpolate_raw(T from, T to, float delta)
|
|
|
{
|
|
|
- if (from.type() != to.type())
|
|
|
- return delta >= 0.5f ? to : from;
|
|
|
+ if constexpr (IsSame<T, double>) {
|
|
|
+ return from + (to - from) * static_cast<double>(delta);
|
|
|
+ } else {
|
|
|
+ return static_cast<RemoveCVReference<T>>(from + (to - from) * delta);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static ErrorOr<NonnullRefPtr<StyleValue const>> interpolate_transform(DOM::Element& element, StyleValue const& from, StyleValue const& to, float delta)
|
|
|
+{
|
|
|
+ // Note that the spec uses column-major notation, so all the matrix indexing is reversed.
|
|
|
+
|
|
|
+ static constexpr auto make_transformation = [](TransformationStyleValue const& transformation) -> ErrorOr<Transformation> {
|
|
|
+ Vector<TransformValue> values;
|
|
|
+
|
|
|
+ for (auto const& value : transformation.values()) {
|
|
|
+ switch (value->type()) {
|
|
|
+ case StyleValue::Type::Angle:
|
|
|
+ values.append(AngleOrCalculated { value->as_angle().angle() });
|
|
|
+ break;
|
|
|
+ case StyleValue::Type::Calculated:
|
|
|
+ values.append(AngleOrCalculated { value->as_calculated() });
|
|
|
+ break;
|
|
|
+ case StyleValue::Type::Length:
|
|
|
+ values.append(LengthPercentage { value->as_length().length() });
|
|
|
+ break;
|
|
|
+ case StyleValue::Type::Percentage:
|
|
|
+ values.append(LengthPercentage { value->as_percentage().percentage() });
|
|
|
+ break;
|
|
|
+ case StyleValue::Type::Number:
|
|
|
+ values.append(NumberPercentage { Number(Number::Type::Number, value->as_number().number()) });
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return Error::from_string_literal("Transform contains unsupported style value");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return Transformation { transformation.transform_function(), move(values) };
|
|
|
+ };
|
|
|
+
|
|
|
+ static constexpr auto transformation_style_value_to_matrix = [](DOM::Element& element, TransformationStyleValue const& value) -> ErrorOr<FloatMatrix4x4> {
|
|
|
+ auto transformation = TRY(make_transformation(value.as_transformation()));
|
|
|
+ Optional<Painting::PaintableBox const&> paintable_box;
|
|
|
+ if (auto layout_node = element.layout_node()) {
|
|
|
+ if (auto paintable = layout_node->paintable(); paintable && is<Painting::PaintableBox>(paintable))
|
|
|
+ paintable_box = *static_cast<Painting::PaintableBox*>(paintable);
|
|
|
+ }
|
|
|
+ return transformation.to_matrix(paintable_box);
|
|
|
+ };
|
|
|
+
|
|
|
+ static constexpr auto style_value_to_matrix = [](DOM::Element& element, StyleValue const& value) -> ErrorOr<FloatMatrix4x4> {
|
|
|
+ if (value.to_identifier() == ValueID::None)
|
|
|
+ return FloatMatrix4x4::identity();
|
|
|
+
|
|
|
+ if (value.is_transformation())
|
|
|
+ return transformation_style_value_to_matrix(element, value.as_transformation());
|
|
|
+
|
|
|
+ VERIFY(value.is_value_list());
|
|
|
+ auto matrix = FloatMatrix4x4::identity();
|
|
|
+ for (auto const& value_element : value.as_value_list().values()) {
|
|
|
+ if (value_element->is_transformation())
|
|
|
+ matrix = matrix * TRY(transformation_style_value_to_matrix(element, value_element->as_transformation()));
|
|
|
+ }
|
|
|
+
|
|
|
+ return matrix;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct DecomposedValues {
|
|
|
+ FloatVector3 translation;
|
|
|
+ FloatVector3 scale;
|
|
|
+ FloatVector3 skew;
|
|
|
+ FloatVector4 rotation;
|
|
|
+ FloatVector4 perspective;
|
|
|
+ };
|
|
|
+ // https://drafts.csswg.org/css-transforms-2/#decomposing-a-3d-matrix
|
|
|
+ static constexpr auto decompose = [](FloatMatrix4x4 matrix) -> ErrorOr<DecomposedValues> {
|
|
|
+ // https://drafts.csswg.org/css-transforms-1/#supporting-functions
|
|
|
+ static constexpr auto combine = [](auto a, auto b, float ascl, float bscl) {
|
|
|
+ return FloatVector3 {
|
|
|
+ ascl * a[0] + bscl * b[0],
|
|
|
+ ascl * a[1] + bscl * b[1],
|
|
|
+ ascl * a[2] + bscl * b[2],
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+ // Normalize the matrix.
|
|
|
+ if (matrix(3, 3) == 0.f)
|
|
|
+ return Error::from_string_literal("Cannot interpolate non-invertible matrix");
|
|
|
+
|
|
|
+ for (int i = 0; i < 4; i++)
|
|
|
+ for (int j = 0; j < 4; j++)
|
|
|
+ matrix(i, j) /= matrix(3, 3);
|
|
|
+
|
|
|
+ // perspectiveMatrix is used to solve for perspective, but it also provides
|
|
|
+ // an easy way to test for singularity of the upper 3x3 component.
|
|
|
+ auto perspective_matrix = matrix;
|
|
|
+ for (int i = 0; i < 3; i++)
|
|
|
+ perspective_matrix(3, i) = 0.f;
|
|
|
+ perspective_matrix(3, 3) = 1.f;
|
|
|
+
|
|
|
+ if (!perspective_matrix.is_invertible())
|
|
|
+ return Error::from_string_literal("Cannot interpolate non-invertible matrix");
|
|
|
+
|
|
|
+ DecomposedValues values;
|
|
|
+
|
|
|
+ // First, isolate perspective.
|
|
|
+ if (matrix(3, 0) != 0.f || matrix(3, 1) != 0.f || matrix(3, 2) != 0.f) {
|
|
|
+ // rightHandSide is the right hand side of the equation.
|
|
|
+ // Note: It is the bottom side in a row-major matrix
|
|
|
+ FloatVector4 bottom_side = {
|
|
|
+ matrix(3, 0),
|
|
|
+ matrix(3, 1),
|
|
|
+ matrix(3, 2),
|
|
|
+ matrix(3, 3),
|
|
|
+ };
|
|
|
+
|
|
|
+ // Solve the equation by inverting perspectiveMatrix and multiplying
|
|
|
+ // rightHandSide by the inverse.
|
|
|
+ auto inverse_perspective_matrix = perspective_matrix.inverse();
|
|
|
+ auto transposed_inverse_perspective_matrix = inverse_perspective_matrix.transpose();
|
|
|
+ values.perspective = transposed_inverse_perspective_matrix * bottom_side;
|
|
|
+ } else {
|
|
|
+ // No perspective.
|
|
|
+ values.perspective = { 0.0, 0.0, 0.0, 1.0 };
|
|
|
+ }
|
|
|
+
|
|
|
+ // Next take care of translation
|
|
|
+ for (int i = 0; i < 3; i++)
|
|
|
+ values.translation[i] = matrix(i, 3);
|
|
|
+
|
|
|
+ // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
|
|
|
+ FloatVector3 row[3];
|
|
|
+ for (int i = 0; i < 3; i++)
|
|
|
+ row[i] = { matrix(0, i), matrix(1, i), matrix(2, i) };
|
|
|
+
|
|
|
+ // Compute X scale factor and normalize first row.
|
|
|
+ values.scale[0] = row[0].length();
|
|
|
+ row[0].normalize();
|
|
|
+
|
|
|
+ // Compute XY shear factor and make 2nd row orthogonal to 1st.
|
|
|
+ values.skew[0] = row[0].dot(row[1]);
|
|
|
+ row[1] = combine(row[1], row[0], 1.f, -values.skew[0]);
|
|
|
+
|
|
|
+ // Now, compute Y scale and normalize 2nd row.
|
|
|
+ values.scale[1] = row[1].length();
|
|
|
+ row[1].normalize();
|
|
|
+ values.skew[0] /= values.scale[1];
|
|
|
+
|
|
|
+ // Compute XZ and YZ shears, orthogonalize 3rd row
|
|
|
+ values.skew[1] = row[0].dot(row[2]);
|
|
|
+ row[2] = combine(row[2], row[0], 1.f, -values.skew[1]);
|
|
|
+ values.skew[2] = row[1].dot(row[2]);
|
|
|
+ row[2] = combine(row[2], row[1], 1.f, -values.skew[2]);
|
|
|
+
|
|
|
+ // Next, get Z scale and normalize 3rd row.
|
|
|
+ values.scale[2] = row[2].length();
|
|
|
+ row[2].normalize();
|
|
|
+ values.skew[1] /= values.scale[2];
|
|
|
+ values.skew[2] /= values.scale[2];
|
|
|
+
|
|
|
+ // At this point, the matrix (in rows) is orthonormal.
|
|
|
+ // Check for a coordinate system flip. If the determinant
|
|
|
+ // is -1, then negate the matrix and the scaling factors.
|
|
|
+ auto pdum3 = row[1].cross(row[2]);
|
|
|
+ if (row[0].dot(pdum3) < 0.f) {
|
|
|
+ for (int i = 0; i < 3; i++) {
|
|
|
+ values.scale[i] *= -1.f;
|
|
|
+ row[i][0] *= -1.f;
|
|
|
+ row[i][1] *= -1.f;
|
|
|
+ row[i][2] *= -1.f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now, get the rotations out
|
|
|
+ values.rotation[0] = 0.5f * sqrt(max(1.f + row[0][0] - row[1][1] - row[2][2], 0.f));
|
|
|
+ values.rotation[1] = 0.5f * sqrt(max(1.f - row[0][0] + row[1][1] - row[2][2], 0.f));
|
|
|
+ values.rotation[2] = 0.5f * sqrt(max(1.f - row[0][0] - row[1][1] + row[2][2], 0.f));
|
|
|
+ values.rotation[3] = 0.5f * sqrt(max(1.f + row[0][0] + row[1][1] + row[2][2], 0.f));
|
|
|
+
|
|
|
+ if (row[2][1] > row[1][2])
|
|
|
+ values.rotation[0] = -values.rotation[0];
|
|
|
+ if (row[0][2] > row[2][0])
|
|
|
+ values.rotation[1] = -values.rotation[1];
|
|
|
+ if (row[1][0] > row[0][1])
|
|
|
+ values.rotation[2] = -values.rotation[2];
|
|
|
+
|
|
|
+ // FIXME: This accounts for the fact that the browser coordinate system is left-handed instead of right-handed.
|
|
|
+ // The reason for this is that the positive Y-axis direction points down instead of up. To fix this, we
|
|
|
+ // invert the Y axis. However, it feels like the spec pseudo-code above should have taken something like
|
|
|
+ // this into account, so we're probably doing something else wrong.
|
|
|
+ values.rotation[2] *= -1;
|
|
|
+
|
|
|
+ return values;
|
|
|
+ };
|
|
|
+
|
|
|
+ // https://drafts.csswg.org/css-transforms-2/#recomposing-to-a-3d-matrix
|
|
|
+ static constexpr auto recompose = [](DecomposedValues const& values) -> FloatMatrix4x4 {
|
|
|
+ auto matrix = FloatMatrix4x4::identity();
|
|
|
+
|
|
|
+ // apply perspective
|
|
|
+ for (int i = 0; i < 4; i++)
|
|
|
+ matrix(3, i) = values.perspective[i];
|
|
|
+
|
|
|
+ // apply translation
|
|
|
+ for (int i = 0; i < 4; i++) {
|
|
|
+ for (int j = 0; j < 3; j++)
|
|
|
+ matrix(i, 3) += values.translation[j] * matrix(i, j);
|
|
|
+ }
|
|
|
+
|
|
|
+ // apply rotation
|
|
|
+ auto x = values.rotation[0];
|
|
|
+ auto y = values.rotation[1];
|
|
|
+ auto z = values.rotation[2];
|
|
|
+ auto w = values.rotation[3];
|
|
|
+
|
|
|
+ // Construct a composite rotation matrix from the quaternion values
|
|
|
+ // rotationMatrix is a identity 4x4 matrix initially
|
|
|
+ auto rotation_matrix = FloatMatrix4x4::identity();
|
|
|
+ rotation_matrix(0, 0) = 1.f - 2.f * (y * y + z * z);
|
|
|
+ rotation_matrix(1, 0) = 2.f * (x * y - z * w);
|
|
|
+ rotation_matrix(2, 0) = 2.f * (x * z + y * w);
|
|
|
+ rotation_matrix(0, 1) = 2.f * (x * y + z * w);
|
|
|
+ rotation_matrix(1, 1) = 1.f - 2.f * (x * x + z * z);
|
|
|
+ rotation_matrix(2, 1) = 2.f * (y * z - x * w);
|
|
|
+ rotation_matrix(0, 2) = 2.f * (x * z - y * w);
|
|
|
+ rotation_matrix(1, 2) = 2.f * (y * z + x * w);
|
|
|
+ rotation_matrix(2, 2) = 1.f - 2.f * (x * x + y * y);
|
|
|
+
|
|
|
+ matrix = matrix * rotation_matrix;
|
|
|
+
|
|
|
+ // apply skew
|
|
|
+ // temp is a identity 4x4 matrix initially
|
|
|
+ auto temp = FloatMatrix4x4::identity();
|
|
|
+ if (values.skew[2] != 0.f) {
|
|
|
+ temp(1, 2) = values.skew[2];
|
|
|
+ matrix = matrix * temp;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (values.skew[1] != 0.f) {
|
|
|
+ temp(1, 2) = 0.f;
|
|
|
+ temp(0, 2) = values.skew[1];
|
|
|
+ matrix = matrix * temp;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (values.skew[0] != 0.f) {
|
|
|
+ temp(0, 2) = 0.f;
|
|
|
+ temp(0, 1) = values.skew[0];
|
|
|
+ matrix = matrix * temp;
|
|
|
+ }
|
|
|
+
|
|
|
+ // apply scale
|
|
|
+ for (int i = 0; i < 3; i++) {
|
|
|
+ for (int j = 0; j < 4; j++)
|
|
|
+ matrix(j, i) *= values.scale[i];
|
|
|
+ }
|
|
|
|
|
|
- auto interpolate_raw = [delta = static_cast<double>(delta)](auto from, auto to) {
|
|
|
- return static_cast<RemoveCVReference<decltype(from)>>(static_cast<double>(from) + static_cast<double>(to - from) * delta);
|
|
|
+ return matrix;
|
|
|
};
|
|
|
|
|
|
+ // https://drafts.csswg.org/css-transforms-2/#interpolation-of-decomposed-3d-matrix-values
|
|
|
+ static constexpr auto interpolate = [](DecomposedValues& from, DecomposedValues& to, float delta) -> DecomposedValues {
|
|
|
+ auto product = clamp(from.rotation.dot(to.rotation), -1.0f, 1.0f);
|
|
|
+ FloatVector4 interpolated_rotation;
|
|
|
+ if (fabsf(product) == 1.0f) {
|
|
|
+ interpolated_rotation = from.rotation;
|
|
|
+ } else {
|
|
|
+ auto theta = acos(product);
|
|
|
+ auto w = sin(delta * theta) / sqrtf(1.0f - product * product);
|
|
|
+
|
|
|
+ for (int i = 0; i < 4; i++) {
|
|
|
+ from.rotation[i] *= cos(delta * theta) - product * w;
|
|
|
+ to.rotation[i] *= w;
|
|
|
+ interpolated_rotation[i] = from.rotation[i] + to.rotation[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ interpolate_raw(from.translation, to.translation, delta),
|
|
|
+ interpolate_raw(from.scale, to.scale, delta),
|
|
|
+ interpolate_raw(from.skew, to.skew, delta),
|
|
|
+ interpolated_rotation,
|
|
|
+ interpolate_raw(from.perspective, to.perspective, delta),
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+ auto from_matrix = TRY(style_value_to_matrix(element, from));
|
|
|
+ auto to_matrix = TRY(style_value_to_matrix(element, to));
|
|
|
+ auto from_decomposed = TRY(decompose(from_matrix));
|
|
|
+ auto to_decomposed = TRY(decompose(to_matrix));
|
|
|
+ auto interpolated_decomposed = interpolate(from_decomposed, to_decomposed, delta);
|
|
|
+ auto interpolated = recompose(interpolated_decomposed);
|
|
|
+
|
|
|
+ StyleValueVector values;
|
|
|
+ values.ensure_capacity(16);
|
|
|
+ for (int i = 0; i < 16; i++)
|
|
|
+ values.append(NumberStyleValue::create(static_cast<double>(interpolated(i % 4, i / 4))));
|
|
|
+ return StyleValueList::create({ TransformationStyleValue::create(TransformFunction::Matrix3d, move(values)) }, StyleValueList::Separator::Comma);
|
|
|
+}
|
|
|
+
|
|
|
+static ErrorOr<NonnullRefPtr<StyleValue const>> interpolate_value(DOM::Element& element, StyleValue const& from, StyleValue const& to, float delta)
|
|
|
+{
|
|
|
+ if (from.type() != to.type())
|
|
|
+ return delta >= 0.5f ? to : from;
|
|
|
+
|
|
|
switch (from.type()) {
|
|
|
case StyleValue::Type::Angle:
|
|
|
- return AngleStyleValue::create(Angle::make_degrees(interpolate_raw(from.as_angle().angle().to_degrees(), to.as_angle().angle().to_degrees())));
|
|
|
+ return AngleStyleValue::create(Angle::make_degrees(interpolate_raw(from.as_angle().angle().to_degrees(), to.as_angle().angle().to_degrees(), delta)));
|
|
|
case StyleValue::Type::Color: {
|
|
|
auto from_color = from.as_color().color();
|
|
|
auto to_color = to.as_color().color();
|
|
@@ -777,41 +1075,41 @@ static ErrorOr<NonnullRefPtr<StyleValue const>> interpolate_value(StyleValue con
|
|
|
auto to_oklab = to_color.to_oklab();
|
|
|
|
|
|
auto color = Color::from_oklab(
|
|
|
- interpolate_raw(from_oklab.L, to_oklab.L),
|
|
|
- interpolate_raw(from_oklab.a, to_oklab.a),
|
|
|
- interpolate_raw(from_oklab.b, to_oklab.b));
|
|
|
- color.set_alpha(interpolate_raw(from_color.alpha(), to_color.alpha()));
|
|
|
+ interpolate_raw(from_oklab.L, to_oklab.L, delta),
|
|
|
+ interpolate_raw(from_oklab.a, to_oklab.a, delta),
|
|
|
+ interpolate_raw(from_oklab.b, to_oklab.b, delta));
|
|
|
+ color.set_alpha(interpolate_raw(from_color.alpha(), to_color.alpha(), delta));
|
|
|
|
|
|
return ColorStyleValue::create(color);
|
|
|
}
|
|
|
case StyleValue::Type::Integer:
|
|
|
- return IntegerStyleValue::create(interpolate_raw(from.as_integer().integer(), to.as_integer().integer()));
|
|
|
+ return IntegerStyleValue::create(interpolate_raw(from.as_integer().integer(), to.as_integer().integer(), delta));
|
|
|
case StyleValue::Type::Length: {
|
|
|
auto& from_length = from.as_length().length();
|
|
|
auto& to_length = to.as_length().length();
|
|
|
- return LengthStyleValue::create(Length(interpolate_raw(from_length.raw_value(), to_length.raw_value()), from_length.type()));
|
|
|
+ return LengthStyleValue::create(Length(interpolate_raw(from_length.raw_value(), to_length.raw_value(), delta), from_length.type()));
|
|
|
}
|
|
|
case StyleValue::Type::Number:
|
|
|
- return NumberStyleValue::create(interpolate_raw(from.as_number().number(), to.as_number().number()));
|
|
|
+ return NumberStyleValue::create(interpolate_raw(from.as_number().number(), to.as_number().number(), delta));
|
|
|
case StyleValue::Type::Percentage:
|
|
|
- return PercentageStyleValue::create(Percentage(interpolate_raw(from.as_percentage().percentage().value(), to.as_percentage().percentage().value())));
|
|
|
+ return PercentageStyleValue::create(Percentage(interpolate_raw(from.as_percentage().percentage().value(), to.as_percentage().percentage().value(), delta)));
|
|
|
case StyleValue::Type::Position: {
|
|
|
// https://www.w3.org/TR/css-values-4/#combine-positions
|
|
|
// FIXME: Interpolation of <position> is defined as the independent interpolation of each component (x, y) normalized as an offset from the top left corner as a <length-percentage>.
|
|
|
auto& from_position = from.as_position();
|
|
|
auto& to_position = to.as_position();
|
|
|
return PositionStyleValue::create(
|
|
|
- TRY(interpolate_value(from_position.edge_x(), to_position.edge_x(), delta))->as_edge(),
|
|
|
- TRY(interpolate_value(from_position.edge_y(), to_position.edge_y(), delta))->as_edge());
|
|
|
+ TRY(interpolate_value(element, from_position.edge_x(), to_position.edge_x(), delta))->as_edge(),
|
|
|
+ TRY(interpolate_value(element, from_position.edge_y(), to_position.edge_y(), delta))->as_edge());
|
|
|
}
|
|
|
case StyleValue::Type::Rect: {
|
|
|
auto from_rect = from.as_rect().rect();
|
|
|
auto to_rect = to.as_rect().rect();
|
|
|
return RectStyleValue::create({
|
|
|
- Length(interpolate_raw(from_rect.top_edge.raw_value(), to_rect.top_edge.raw_value()), from_rect.top_edge.type()),
|
|
|
- Length(interpolate_raw(from_rect.right_edge.raw_value(), to_rect.right_edge.raw_value()), from_rect.right_edge.type()),
|
|
|
- Length(interpolate_raw(from_rect.bottom_edge.raw_value(), to_rect.bottom_edge.raw_value()), from_rect.bottom_edge.type()),
|
|
|
- Length(interpolate_raw(from_rect.left_edge.raw_value(), to_rect.left_edge.raw_value()), from_rect.left_edge.type()),
|
|
|
+ Length(interpolate_raw(from_rect.top_edge.raw_value(), to_rect.top_edge.raw_value(), delta), from_rect.top_edge.type()),
|
|
|
+ Length(interpolate_raw(from_rect.right_edge.raw_value(), to_rect.right_edge.raw_value(), delta), from_rect.right_edge.type()),
|
|
|
+ Length(interpolate_raw(from_rect.bottom_edge.raw_value(), to_rect.bottom_edge.raw_value(), delta), from_rect.bottom_edge.type()),
|
|
|
+ Length(interpolate_raw(from_rect.left_edge.raw_value(), to_rect.left_edge.raw_value(), delta), from_rect.left_edge.type()),
|
|
|
});
|
|
|
}
|
|
|
case StyleValue::Type::Transformation:
|
|
@@ -825,7 +1123,7 @@ static ErrorOr<NonnullRefPtr<StyleValue const>> interpolate_value(StyleValue con
|
|
|
StyleValueVector interpolated_values;
|
|
|
interpolated_values.ensure_capacity(from_list.size());
|
|
|
for (size_t i = 0; i < from_list.size(); ++i)
|
|
|
- interpolated_values.append(TRY(interpolate_value(from_list.values()[i], to_list.values()[i], delta)));
|
|
|
+ interpolated_values.append(TRY(interpolate_value(element, from_list.values()[i], to_list.values()[i], delta)));
|
|
|
|
|
|
return StyleValueList::create(move(interpolated_values), from_list.separator());
|
|
|
}
|
|
@@ -834,12 +1132,12 @@ static ErrorOr<NonnullRefPtr<StyleValue const>> interpolate_value(StyleValue con
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static ErrorOr<ValueComparingNonnullRefPtr<StyleValue const>> interpolate_property(PropertyID property_id, StyleValue const& from, StyleValue const& to, float delta)
|
|
|
+static ErrorOr<ValueComparingNonnullRefPtr<StyleValue const>> interpolate_property(DOM::Element& element, PropertyID property_id, StyleValue const& from, StyleValue const& to, float delta)
|
|
|
{
|
|
|
auto animation_type = animation_type_from_longhand_property(property_id);
|
|
|
switch (animation_type) {
|
|
|
case AnimationType::ByComputedValue:
|
|
|
- return interpolate_value(from, to, delta);
|
|
|
+ return interpolate_value(element, from, to, delta);
|
|
|
case AnimationType::None:
|
|
|
return to;
|
|
|
case AnimationType::Custom: {
|
|
@@ -861,7 +1159,7 @@ static ErrorOr<ValueComparingNonnullRefPtr<StyleValue const>> interpolate_proper
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- return from;
|
|
|
+ return interpolate_transform(element, from, to, delta);
|
|
|
}
|
|
|
|
|
|
// FIXME: Handle all custom animatable properties
|
|
@@ -955,7 +1253,7 @@ ErrorOr<void> StyleComputer::collect_animation_into(JS::NonnullGCPtr<Animations:
|
|
|
auto start = resolved_start_property.release_nonnull();
|
|
|
auto end = resolved_end_property.release_nonnull();
|
|
|
|
|
|
- auto next_value = TRY(interpolate_property(it.key, *start, *end, progress_in_keyframe));
|
|
|
+ auto next_value = TRY(interpolate_property(*effect->target(), it.key, *start, *end, progress_in_keyframe));
|
|
|
dbgln_if(LIBWEB_CSS_ANIMATION_DEBUG, "Interpolated value for property {} at {}: {} -> {} = {}", string_from_property_id(it.key), progress_in_keyframe, start->to_string(), end->to_string(), next_value->to_string());
|
|
|
style_properties.set_property(it.key, next_value);
|
|
|
}
|