commit b9daf63e7c7b0f79ab612ae4339079cf530bfa5c
parent 75b5b74832e62fa4129ee70d450863ff13e3e6d5
Author: Jonathan Kew <jkew@mozilla.com>
Date: Wed, 10 Dec 2025 16:41:10 +0000
Bug 2005214 - patch 1 - Fix PositionAreaKeyword::to_self_alignment() to resolve correctly for the containing block's writing mode. r=layout-reviewers,firefox-style-system-reviewers,jwatt,emilio
Differential Revision: https://phabricator.services.mozilla.com/D275798
Diffstat:
3 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/servo/components/style/logical_geometry.rs b/servo/components/style/logical_geometry.rs
@@ -113,7 +113,7 @@ bitflags!(
const WRITING_MODE_HORIZONTAL_TB = 0;
/// * writing-mode: vertical_rl;
const WRITING_MODE_VERTICAL_RL = WritingMode::VERTICAL.bits();
- /// * writing-mode: vertcail-lr;
+ /// * writing-mode: vertical-lr;
const WRITING_MODE_VERTICAL_LR = WritingMode::VERTICAL.bits() |
WritingMode::VERTICAL_LR.bits() |
WritingMode::LINE_INVERTED.bits();
@@ -223,6 +223,11 @@ impl WritingMode {
}
#[inline]
+ pub fn is_vertical_rl(&self) -> bool {
+ self.is_vertical() && !self.is_vertical_lr()
+ }
+
+ #[inline]
pub fn is_horizontal(&self) -> bool {
!self.is_vertical()
}
diff --git a/servo/components/style/values/specified/position.rs b/servo/components/style/values/specified/position.rs
@@ -1177,10 +1177,13 @@ impl PositionAreaKeyword {
}
/// Returns a value for the self-alignment properties in order to resolve
- /// `normal`.
+ /// `normal`, in terms of the containing block's writing mode.
+ ///
+ /// Note that the caller must have converted the position-area to physical
+ /// values.
///
/// <https://drafts.csswg.org/css-anchor-position/#position-area-alignment>
- pub fn to_self_alignment(self) -> Option<AlignFlags> {
+ pub fn to_self_alignment(self, axis: LogicalAxis, cb_wm: &WritingMode) -> Option<AlignFlags> {
let track = self.track()?;
Some(match track {
// "If the only the center track in an axis is selected, the default alignment in that axis is center."
@@ -1190,10 +1193,24 @@ impl PositionAreaKeyword {
// "Otherwise, the default alignment in that axis is toward the non-specified side track: if it’s
// specifying the “start” track of its axis, the default alignment in that axis is end; etc."
_ => {
- if track.start() {
- AlignFlags::END
+ debug_assert_eq!(self.group_type(), PositionAreaType::Physical);
+ if axis == LogicalAxis::Inline {
+ // For the inline axis, map 'start' to 'end' unless the axis is inline-reversed,
+ // meaning that its logical flow is counter to physical coordinates and therefore
+ // physical 'start' already corresponds to logical 'end'.
+ if track.start() == cb_wm.intersects(WritingMode::INLINE_REVERSED) {
+ AlignFlags::START
+ } else {
+ AlignFlags::END
+ }
} else {
- AlignFlags::START
+ // For the block axis, only vertical-rl has reversed flow and therefore
+ // does not map 'start' to 'end' here.
+ if track.start() == cb_wm.is_vertical_rl() {
+ AlignFlags::START
+ } else {
+ AlignFlags::END
+ }
}
},
})
diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs
@@ -164,9 +164,7 @@ use style::values::computed::length_percentage::{
AllowAnchorPosResolutionInCalcPercentage, Unpacked,
};
use style::values::computed::position::{AnchorFunction, PositionArea};
-use style::values::computed::{
- self, ContentVisibility, Context, ToComputedValue,
-};
+use style::values::computed::{self, ContentVisibility, Context, ToComputedValue};
use style::values::distance::{ComputeSquaredDistance, SquaredDistance};
use style::values::generics::color::ColorMixFlags;
use style::values::generics::easing::BeforeFlag;
@@ -10852,14 +10850,15 @@ pub extern "C" fn Servo_ResolvePositionAreaSelfAlignment(
out: &mut AlignFlags,
) {
// As well as converting `area` and `axis` to the same form for comparison
- // this also makes sure `area`'s second keyword explicit (not none).
+ // this also makes sure `area`'s second keyword is explicit (not none).
let physical_area = area.to_physical(*cb_wm, *self_wm);
let physical_axis = axis.to_physical(*cb_wm);
let area_keyword = match physical_axis {
PhysicalAxis::Horizontal => physical_area.first,
PhysicalAxis::Vertical => physical_area.second,
};
- let Some(align) = area_keyword.to_self_alignment() else {
+ // Note that area_keyword is a physical value (left/right/top/bottom).
+ let Some(align) = area_keyword.to_self_alignment(axis, cb_wm) else {
debug_assert!(
false,
"ResolvePositionAreaSelfAlignment called on {:?}",