Enable CSS aspect-ratio sizing

This commit is contained in:
Basilisk-Dev 2026-05-10 13:00:24 -04:00 committed by wuggy
commit 7766f8f53d
12 changed files with 164 additions and 1310 deletions

File diff suppressed because it is too large Load diff

View file

@ -4652,7 +4652,10 @@ nsFrame::GetIntrinsicSize()
/* virtual */ AspectRatio
nsFrame::GetIntrinsicRatio()
{
return AspectRatio();
const nsStylePosition* stylePos = StylePosition();
return stylePos->mAspectRatio == 0.0f
? AspectRatio()
: AspectRatio(stylePos->mAspectRatio);
}
void
@ -4721,9 +4724,16 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext,
const LogicalSize& aPadding,
ComputeSizeFlags aFlags)
{
MOZ_ASSERT(!GetIntrinsicRatio(),
"Please override this method and call "
"nsFrame::ComputeSizeWithIntrinsicDimensions instead.");
AspectRatio intrinsicRatio = GetIntrinsicRatio();
if (intrinsicRatio) {
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
GetIntrinsicSize(),
intrinsicRatio,
aCBSize, aMargin,
aBorder, aPadding,
aFlags);
}
LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
aCBSize, aAvailableISize,
aMargin, aBorder, aPadding,

View file

@ -944,6 +944,8 @@ protected:
// Property specific parsing routines
bool ParseImageLayers(const nsCSSPropertyID aTable[]);
bool ParseAspectRatio(nsCSSValue& aValue);
bool ParseAspectRatioRatio(nsCSSValue& aValue);
struct ImageLayersShorthandParseState {
nsCSSValue& mColor;
@ -12993,6 +12995,59 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSPropertyID aPropID)
#define BG_CLR (BG_CENTER | BG_LEFT | BG_RIGHT)
#define BG_LR (BG_LEFT | BG_RIGHT)
bool
CSSParserImpl::ParseAspectRatioRatio(nsCSSValue& aValue)
{
nsCSSValue width;
if (!ParseNonNegativeNumber(width)) {
return false;
}
float w = width.GetFloatValue();
float h = 1.0f;
if (ExpectSymbol('/', true)) {
nsCSSValue height;
if (!ParseNonNegativeNumber(height)) {
return false;
}
h = height.GetFloatValue();
}
// Degenerate ratios behave as auto in layout.
aValue.SetFloatValue(w == 0.0f || h == 0.0f ? 0.0f : w / h,
eCSSUnit_Number);
return true;
}
bool
CSSParserImpl::ParseAspectRatio(nsCSSValue& aValue)
{
if (ParseSingleTokenVariant(aValue, VARIANT_INHERIT, nullptr)) {
return true;
}
nsCSSValue autoValue;
bool hasAuto = ParseSingleTokenVariant(autoValue, VARIANT_AUTO, nullptr);
nsCSSValue ratioValue;
bool hasRatio = ParseAspectRatioRatio(ratioValue);
if (!hasAuto && !hasRatio) {
return false;
}
if (hasRatio) {
if (!hasAuto) {
// The grammar is "auto || <ratio>", so auto may appear after the ratio.
ParseSingleTokenVariant(autoValue, VARIANT_AUTO, nullptr);
}
aValue = ratioValue;
return true;
}
aValue.SetAutoValue();
return true;
}
CSSParseResult
CSSParserImpl::ParseBoxProperty(nsCSSValue& aValue,
nsCSSPropertyID aPropID)
@ -13031,6 +13086,8 @@ CSSParserImpl::ParseSingleValuePropertyByFunction(nsCSSValue& aValue,
switch (aPropID) {
case eCSSProperty_clip_path:
return ParseClipPath(aValue);
case eCSSProperty_aspect_ratio:
return ParseAspectRatio(aValue);
case eCSSProperty_contain:
return ParseContain(aValue);
case eCSSProperty_font_family:

View file

@ -470,19 +470,17 @@ CSS_PROP_DISPLAY(
kAppearanceKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_POSITION(
aspect-ratio,
aspect_ratio,
AspectRatio,
CSS_PROPERTY_INTERNAL |
CSS_PROPERTY_PARSE_INACCESSIBLE,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_VALUE_PARSER_FUNCTION,
"",
VARIANT_NUMBER,
0,
nullptr,
offsetof(nsStylePosition, mAspectRatio),
eStyleAnimType_None)
#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_DISPLAY(
backface-visibility,
backface_visibility,

View file

@ -964,6 +964,22 @@ nsComputedDOMStyle::DoGetBinding()
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetAspectRatio()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
float ratio = StylePosition()->mAspectRatio;
if (ratio == 0.0f) {
val->SetIdent(eCSSKeyword_auto);
} else {
nsAutoString ratioString;
nsStyleUtil::AppendCSSNumber(ratio, ratioString);
ratioString.AppendLiteral(" / 1");
val->SetString(ratioString);
}
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetClear()
{
@ -6841,6 +6857,4 @@ already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetOverflowBlockEnd()
{
return DoGetOverflowBlock();
}
}

View file

@ -226,6 +226,7 @@ private:
*/
already_AddRefed<CSSValue> DoGetAppearance();
already_AddRefed<CSSValue> DoGetAspectRatio();
/* Box properties */
already_AddRefed<CSSValue> DoGetBoxAlign();

View file

@ -51,6 +51,7 @@ COMPUTED_STYLE_PROP(animation_iteration_count, AnimationIterationCount)
COMPUTED_STYLE_PROP(animation_name, AnimationName)
COMPUTED_STYLE_PROP(animation_play_state, AnimationPlayState)
COMPUTED_STYLE_PROP(animation_timing_function, AnimationTimingFunction)
COMPUTED_STYLE_PROP(aspect_ratio, AspectRatio)
COMPUTED_STYLE_PROP(backface_visibility, BackfaceVisibility)
//// COMPUTED_STYLE_PROP(background, Background)
COMPUTED_STYLE_PROP(background_attachment, BackgroundAttachment)

View file

@ -8982,11 +8982,16 @@ nsRuleNode::ComputePositionData(void* aStartStruct,
SETCOORD_UNSET_INITIAL,
aContext, mPresContext, conditions);
// aspect-ratio: float, initial
SetFactor(*aRuleData->ValueForAspectRatio(),
pos->mAspectRatio, conditions,
parentPos->mAspectRatio, 0.0f,
SETFCT_UNSET_INITIAL | SETFCT_POSITIVE | SETFCT_NONE);
// aspect-ratio: auto | <ratio>
const nsCSSValue* aspectRatio = aRuleData->ValueForAspectRatio();
if (aspectRatio->GetUnit() == eCSSUnit_Auto) {
pos->mAspectRatio = 0.0f;
} else {
SetFactor(*aspectRatio,
pos->mAspectRatio, conditions,
parentPos->mAspectRatio, 0.0f,
SETFCT_UNSET_INITIAL | SETFCT_POSITIVE | SETFCT_NONE);
}
// box-sizing: enum, inherit, initial
SetValue(*aRuleData->ValueForBoxSizing(),

View file

@ -105,7 +105,6 @@ const char *gInaccessibleProperties[] = {
"-x-span",
"-x-system-font",
"-x-text-zoom",
"aspect-ratio", // for now.
"-moz-control-character-visibility",
"-moz-script-level", // parsed by UA sheets only
"-moz-script-size-multiplier",

View file

@ -70,6 +70,7 @@ support-files = file_animations_with_disabled_properties.html
[test_any_dynamic.html]
[test_at_rule_parse_serialize.html]
[test_attribute_selector_eof_behavior.html]
[test_aspect_ratio_property.html]
[test_background_blend_mode.html]
[test_box_size_keywords.html]
[test_bug73586.html]

View file

@ -1162,6 +1162,14 @@ var gCSSProperties = {
other_values: ["url(foo.xml)"],
invalid_values: [],
},
"aspect-ratio": {
domProp: "aspectRatio",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: ["auto"],
other_values: ["1", "2"],
invalid_values: ["none", "-1", "1px", "1 / -1", "1 /", "auto auto"],
},
"-moz-border-bottom-colors": {
domProp: "MozBorderBottomColors",
inherited: false,

View file

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test CSS aspect-ratio property</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="container" style="position:absolute; left:0; top:0; width:120px;">
<div id="ratio" style="width:120px; aspect-ratio:3 / 2;"></div>
<div id="wrapper" style="position:relative; width:120px; aspect-ratio:1 / 1;">
<div style="position:absolute; inset:0;"></div>
</div>
</div>
<pre id="test">
<script type="application/javascript">
ok(CSS.supports("aspect-ratio", "1 / 1"),
"aspect-ratio accepts ratio syntax");
ok(CSS.supports("aspect-ratio", "auto"),
"aspect-ratio accepts auto");
ok(CSS.supports("aspect-ratio", "auto 16 / 9"),
"aspect-ratio accepts auto plus ratio");
ok(!CSS.supports("aspect-ratio", "1px"),
"aspect-ratio rejects lengths");
var ratio = document.getElementById("ratio");
is(ratio.getBoundingClientRect().height, 80,
"aspect-ratio computes an automatic block size from inline size");
var wrapper = document.getElementById("wrapper");
is(wrapper.getBoundingClientRect().height, 120,
"aspect-ratio gives an empty wrapper with absolute children a block size");
is(getComputedStyle(wrapper).aspectRatio, "1 / 1",
"computed aspect-ratio exposes a ratio value");
</script>
</pre>
</body>
</html>