commit 55aaa33f526ad11857e3f2e07a87daef1aa56ad4
parent 8d0f56f4c055ea9071b37d8f14581c230979870d
Author: Jan Varga <jvarga@igalia.com>
Date: Wed, 10 Dec 2025 08:03:24 +0000
Bug 1990419 - Add CSSNumericValue <length> reification support for perspective property; r=firefox-style-system-reviewers,dshin
This patch adds CSSNumericValue <length> reification support for the
perspective property. It introduces temporary handling for out-of-range
numeric values (e.g. negative perspective) by wrapping them in calc() during
serialization.
This change depends on the earlier patch "Make CSSMathSum and CSSMathProduct
array comparison order-agnostic," since the perspective property is verified
in WPT using assert_is_equal_with_range_handling. The previous <length>
patches did not require this, as their corresponding tests did not rely on
that helper.
Differential Revision: https://phabricator.services.mozilla.com/D271076
Diffstat:
5 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/layout/style/typedom/CSSUnitValue.cpp b/layout/style/typedom/CSSUnitValue.cpp
@@ -7,6 +7,7 @@
#include "mozilla/dom/CSSUnitValue.h"
#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/CSSPropertyId.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/BindingDeclarations.h"
@@ -58,8 +59,31 @@ void CSSUnitValue::GetUnit(nsCString& aRetVal) const { aRetVal = mUnit; }
void CSSUnitValue::ToCssTextWithProperty(const CSSPropertyId& aPropertyId,
nsACString& aDest) const {
+ // XXX See:
+ // https://drafts.css-houdini.org/css-typed-om-1/#create-an-internal-representation
+ //
+ // The current |isValueOutOfRange| check implements only a minimal subset of
+ // the algorithm step that wraps out-of-range numeric values (e.g. negative
+ // perspective) in a calc() expression to keep them representable.
+ //
+ // This is a temporary solution until a more robust mechanism is added for
+ // handling range checks and value wrapping. The long-term plan is to move
+ // this logic to a dedicated FromTyped trait or similar infrastructure that
+ // can validate and construct internal representations in a property-aware
+ // and fully spec-compliant manner. See bug 2005142
+ const bool isValueOutOfRange =
+ aPropertyId.mId == eCSSProperty_perspective && mValue < 0;
+
+ if (isValueOutOfRange) {
+ aDest.Append("calc("_ns);
+ }
+
aDest.AppendFloat(mValue);
aDest.Append(mUnit);
+
+ if (isValueOutOfRange) {
+ aDest.Append(")"_ns);
+ }
}
CSSUnitValue& CSSStyleValue::GetAsCSSUnitValue() {
diff --git a/servo/components/style/values/generics/box.rs b/servo/components/style/values/generics/box.rs
@@ -199,6 +199,7 @@ impl<I: crate::Zero + ToCss> ToCss for LineClamp<I> {
ToTyped,
)]
#[repr(C, u8)]
+#[typed_value(derive_fields)]
pub enum GenericPerspective<NonNegativeLength> {
/// A non-negative length.
Length(NonNegativeLength),
diff --git a/servo/components/style/values/generics/mod.rs b/servo/components/style/values/generics/mod.rs
@@ -59,6 +59,7 @@ pub mod url;
ToTyped,
)]
#[repr(transparent)]
+#[typed_value(derive_fields)]
pub struct NonNegative<T>(pub T);
/// A trait to clamp a negative value to another.
diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs
@@ -23,9 +23,12 @@ use cssparser::{Parser, Token};
use std::fmt::{self, Write};
use std::ops::Add;
use style_traits::values::specified::AllowedNumericType;
-use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
+use style_traits::{
+ CssString, CssWriter, NumericValue, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss,
+ ToTyped, TypedValue,
+};
-pub use self::align::{ContentDistribution, ItemPlacement, SelfAlignment, JustifyItems};
+pub use self::align::{ContentDistribution, ItemPlacement, JustifyItems, SelfAlignment};
pub use self::angle::{AllowUnitlessZeroAngle, Angle};
pub use self::animation::{
AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode,
@@ -350,6 +353,14 @@ impl ToCss for Number {
}
}
+impl ToTyped for Number {
+ fn to_typed(&self) -> Option<TypedValue> {
+ let value = self.value;
+ let unit = CssString::from("number");
+ Some(TypedValue::Numeric(NumericValue::Unit { value, unit }))
+ }
+}
+
impl IsParallelTo for (Number, Number, Number) {
fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
use euclid::approxeq::ApproxEq;
diff --git a/testing/web-platform/meta/css/css-typed-om/the-stylepropertymap/properties/perspective.html.ini b/testing/web-platform/meta/css/css-typed-om/the-stylepropertymap/properties/perspective.html.ini
@@ -3,9 +3,6 @@
[Can set 'perspective' to var() references: ]
expected: FAIL
- [Can set 'perspective' to a length: ]
- expected: FAIL
-
[Setting 'perspective' to a percent: throws TypeError]
expected: FAIL