diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index bd1f2768723..0cacfb794a7 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -18,6 +18,7 @@ use gfx::text::text_run::GlyphRun; use servo_arc::Arc; use style::properties::ComputedValues; use style::values::computed::{Length, LengthPercentage, Percentage}; +use style::values::specified::text::TextAlignKeyword; use style::Zero; use webrender_api::FontInstanceKey; @@ -260,8 +261,11 @@ impl InlineFormattingContext { ); ifc.current_nesting_level = partial.parent_nesting_level } else { - ifc.lines - .finish_line(&mut ifc.current_nesting_level, containing_block); + ifc.lines.finish_line( + &mut ifc.current_nesting_level, + containing_block, + ifc.inline_position, + ); return FlowLayout { fragments: ifc.lines.fragments, content_block_size: ifc.lines.next_line_block_position, @@ -277,21 +281,62 @@ impl Lines { &mut self, top_nesting_level: &mut InlineNestingLevelState, containing_block: &ContainingBlock, + line_content_inline_size: Length, ) { + let mut line_contents = std::mem::take(&mut top_nesting_level.fragments_so_far); + let line_block_size = std::mem::replace( + &mut top_nesting_level.max_block_size_of_fragments_so_far, + Length::zero(), + ); + enum TextAlign { + Start, + Center, + End, + } + let line_left_is_inline_start = containing_block + .style + .writing_mode + .line_left_is_inline_start(); + let text_align = match containing_block.style.clone_text_align() { + TextAlignKeyword::Start => TextAlign::Start, + TextAlignKeyword::Center => TextAlign::Center, + TextAlignKeyword::End => TextAlign::End, + TextAlignKeyword::Left => { + if line_left_is_inline_start { + TextAlign::Start + } else { + TextAlign::End + } + }, + TextAlignKeyword::Right => { + if line_left_is_inline_start { + TextAlign::End + } else { + TextAlign::Start + } + }, + }; + let move_by = match text_align { + TextAlign::Start => Length::zero(), + TextAlign::Center => (containing_block.inline_size - line_content_inline_size) / 2., + TextAlign::End => containing_block.inline_size - line_content_inline_size, + }; + if move_by > Length::zero() { + for fragment in &mut line_contents { + fragment.position_mut().inline += move_by; + } + } let start_corner = Vec2 { inline: Length::zero(), block: self.next_line_block_position, }; let size = Vec2 { inline: containing_block.inline_size, - block: std::mem::replace( - &mut top_nesting_level.max_block_size_of_fragments_so_far, - Length::zero(), - ), + block: line_block_size, }; self.next_line_block_position += size.block; self.fragments.push(Fragment::Anonymous(AnonymousFragment { - children: std::mem::take(&mut top_nesting_level.fragments_so_far), + children: line_contents, rect: Rect { start_corner, size }, mode: containing_block.style.writing_mode, })) @@ -639,7 +684,8 @@ impl TextRun { partial.parent_nesting_level.inline_start = Length::zero(); nesting_level = &mut partial.parent_nesting_level; } - ifc.lines.finish_line(nesting_level, ifc.containing_block); + ifc.lines + .finish_line(nesting_level, ifc.containing_block, ifc.inline_position); ifc.inline_position = Length::zero(); } } diff --git a/components/layout_2020/fragments.rs b/components/layout_2020/fragments.rs index 4dbacc5611e..29f9db8e0b3 100644 --- a/components/layout_2020/fragments.rs +++ b/components/layout_2020/fragments.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::geom::flow_relative::{Rect, Sides}; +use crate::geom::flow_relative::{Rect, Sides, Vec2}; use gfx::text::glyph::GlyphStore; use servo_arc::Arc as ServoArc; use std::sync::Arc; @@ -68,6 +68,17 @@ pub(crate) struct ImageFragment { pub image_key: ImageKey, } +impl Fragment { + pub fn position_mut(&mut self) -> &mut Vec2 { + match self { + Fragment::Box(f) => &mut f.content_rect.start_corner, + Fragment::Anonymous(f) => &mut f.rect.start_corner, + Fragment::Text(f) => &mut f.rect.start_corner, + Fragment::Image(f) => &mut f.rect.start_corner, + } + } +} + impl AnonymousFragment { pub fn no_op(mode: WritingMode) -> Self { Self { diff --git a/components/style/logical_geometry.rs b/components/style/logical_geometry.rs index 9019d252cdb..cb45544146b 100644 --- a/components/style/logical_geometry.rs +++ b/components/style/logical_geometry.rs @@ -206,6 +206,20 @@ impl WritingMode { self.intersects(WritingMode::UPRIGHT) } + /// https://drafts.csswg.org/css-writing-modes/#logical-to-physical + /// + /// | Return | line-left is… | line-right is… | + /// |---------|---------------|----------------| + /// | `true` | inline-start | inline-end | + /// | `false` | inline-end | inline-start | + #[inline] + pub fn line_left_is_inline_start(&self) -> bool { + // https://drafts.csswg.org/css-writing-modes/#inline-start + // “For boxes with a used direction value of ltr, this means the line-left side. + // For boxes with a used direction value of rtl, this means the line-right side.” + self.is_bidi_ltr() + } + #[inline] pub fn inline_start_physical_side(&self) -> PhysicalSide { match (self.is_vertical(), self.is_inline_tb(), self.is_bidi_ltr()) { diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index 428b40a101f..e7cfbba377b 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -156,7 +156,6 @@ ${helpers.predefined_type( "TextAlign", "computed::TextAlign::Start", engines="gecko servo-2013 servo-2020", - servo_2020_pref="layout.2020.unimplemented", animation_value_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-text-align", servo_restyle_damage = "reflow", diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index 946e97eb619..cc4bcee1a55 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -544,6 +544,7 @@ pub enum TextAlignKeyword { Left, Right, Center, + #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] Justify, #[cfg(feature = "gecko")] MozCenter, @@ -551,11 +552,11 @@ pub enum TextAlignKeyword { MozLeft, #[cfg(feature = "gecko")] MozRight, - #[cfg(feature = "servo")] + #[cfg(feature = "servo-layout-2013")] ServoCenter, - #[cfg(feature = "servo")] + #[cfg(feature = "servo-layout-2013")] ServoLeft, - #[cfg(feature = "servo")] + #[cfg(feature = "servo-layout-2013")] ServoRight, #[css(skip)] #[cfg(feature = "gecko")]