Auto merge of #25203 - servo:text-align, r=nox

Implement `text-align` (except `justify`)
This commit is contained in:
bors-servo 2019-12-10 00:20:55 -05:00 committed by GitHub
commit 64c9928b2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 190 additions and 128 deletions

View file

@ -4,7 +4,6 @@
use crate::fragments::{BoxFragment, Fragment}; use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2}; use crate::geom::physical::{Rect, Vec2};
use crate::style_ext::ComputedValuesExt;
use euclid::{Point2D, SideOffsets2D}; use euclid::{Point2D, SideOffsets2D};
use gfx::text::glyph::GlyphStore; use gfx::text::glyph::GlyphStore;
use std::sync::Arc; use std::sync::Arc;
@ -54,8 +53,8 @@ impl Fragment {
Fragment::Text(t) => { Fragment::Text(t) => {
is_contentful.0 = true; is_contentful.0 = true;
let rect = t let rect = t
.content_rect .rect
.to_physical(t.parent_style.writing_mode(), containing_block) .to_physical(t.parent_style.writing_mode, containing_block)
.translate(&containing_block.top_left); .translate(&containing_block.top_left);
let mut baseline_origin = rect.top_left.clone(); let mut baseline_origin = rect.top_left.clone();
baseline_origin.y += t.ascent; baseline_origin.y += t.ascent;
@ -80,8 +79,8 @@ impl Fragment {
use style::computed_values::image_rendering::T as ImageRendering; use style::computed_values::image_rendering::T as ImageRendering;
is_contentful.0 = true; is_contentful.0 = true;
let rect = i let rect = i
.content_rect .rect
.to_physical(i.style.writing_mode(), containing_block) .to_physical(i.style.writing_mode, containing_block)
.translate(&containing_block.top_left); .translate(&containing_block.top_left);
let common = CommonItemProperties { let common = CommonItemProperties {
clip_rect: rect.clone().into(), clip_rect: rect.clone().into(),
@ -117,7 +116,7 @@ impl BoxFragment {
) { ) {
let border_rect = self let border_rect = self
.border_rect() .border_rect()
.to_physical(self.style.writing_mode(), containing_block) .to_physical(self.style.writing_mode, containing_block)
.translate(&containing_block.top_left) .translate(&containing_block.top_left)
.into(); .into();
let common = CommonItemProperties { let common = CommonItemProperties {
@ -133,7 +132,7 @@ impl BoxFragment {
self.border_display_items(builder, &common, border_rect); self.border_display_items(builder, &common, border_rect);
let content_rect = self let content_rect = self
.content_rect .content_rect
.to_physical(self.style.writing_mode(), containing_block) .to_physical(self.style.writing_mode, containing_block)
.translate(&containing_block.top_left); .translate(&containing_block.top_left);
for child in &self.children { for child in &self.children {
child.build_display_list(builder, is_contentful, &content_rect) child.build_display_list(builder, is_contentful, &content_rect)

View file

@ -18,6 +18,7 @@ use gfx::text::text_run::GlyphRun;
use servo_arc::Arc; use servo_arc::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage}; use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::specified::text::TextAlignKeyword;
use style::Zero; use style::Zero;
use webrender_api::FontInstanceKey; use webrender_api::FontInstanceKey;
@ -69,15 +70,16 @@ struct PartialInlineBoxFragment<'box_tree> {
struct InlineFormattingContextState<'box_tree, 'a> { struct InlineFormattingContextState<'box_tree, 'a> {
absolutely_positioned_fragments: &'a mut Vec<AbsolutelyPositionedFragment<'box_tree>>, absolutely_positioned_fragments: &'a mut Vec<AbsolutelyPositionedFragment<'box_tree>>,
containing_block: &'a ContainingBlock, containing_block: &'a ContainingBlock<'a>,
line_boxes: LinesBoxes, lines: Lines,
inline_position: Length, inline_position: Length,
partial_inline_boxes_stack: Vec<PartialInlineBoxFragment<'box_tree>>, partial_inline_boxes_stack: Vec<PartialInlineBoxFragment<'box_tree>>,
current_nesting_level: InlineNestingLevelState<'box_tree>, current_nesting_level: InlineNestingLevelState<'box_tree>,
} }
struct LinesBoxes { struct Lines {
boxes: Vec<Fragment>, // One anonymous fragment per line
fragments: Vec<Fragment>,
next_line_block_position: Length, next_line_block_position: Length,
} }
@ -201,8 +203,8 @@ impl InlineFormattingContext {
absolutely_positioned_fragments, absolutely_positioned_fragments,
containing_block, containing_block,
partial_inline_boxes_stack: Vec::new(), partial_inline_boxes_stack: Vec::new(),
line_boxes: LinesBoxes { lines: Lines {
boxes: Vec::new(), fragments: Vec::new(),
next_line_block_position: Length::zero(), next_line_block_position: Length::zero(),
}, },
inline_position: Length::zero(), inline_position: Length::zero(),
@ -233,7 +235,7 @@ impl InlineFormattingContext {
DisplayOutside::Inline => ifc.inline_position, DisplayOutside::Inline => ifc.inline_position,
DisplayOutside::Block => Length::zero(), DisplayOutside::Block => Length::zero(),
}, },
block: ifc.line_boxes.next_line_block_position, block: ifc.lines.next_line_block_position,
}, },
Display::Contents => { Display::Contents => {
panic!("display:contents does not generate an abspos box") panic!("display:contents does not generate an abspos box")
@ -259,11 +261,14 @@ impl InlineFormattingContext {
); );
ifc.current_nesting_level = partial.parent_nesting_level ifc.current_nesting_level = partial.parent_nesting_level
} else { } else {
ifc.line_boxes ifc.lines.finish_line(
.finish_line(&mut ifc.current_nesting_level, containing_block); &mut ifc.current_nesting_level,
containing_block,
ifc.inline_position,
);
return FlowLayout { return FlowLayout {
fragments: ifc.line_boxes.boxes, fragments: ifc.lines.fragments,
content_block_size: ifc.line_boxes.next_line_block_position, content_block_size: ifc.lines.next_line_block_position,
collapsible_margins_in_children: CollapsedBlockMargins::zero(), collapsible_margins_in_children: CollapsedBlockMargins::zero(),
}; };
} }
@ -271,28 +276,69 @@ impl InlineFormattingContext {
} }
} }
impl LinesBoxes { impl Lines {
fn finish_line( fn finish_line(
&mut self, &mut self,
top_nesting_level: &mut InlineNestingLevelState, top_nesting_level: &mut InlineNestingLevelState,
containing_block: &ContainingBlock, 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 { let start_corner = Vec2 {
inline: Length::zero(), inline: Length::zero(),
block: self.next_line_block_position, block: self.next_line_block_position,
}; };
let size = Vec2 { let size = Vec2 {
inline: containing_block.inline_size, inline: containing_block.inline_size,
block: std::mem::replace( block: line_block_size,
&mut top_nesting_level.max_block_size_of_fragments_so_far,
Length::zero(),
),
}; };
self.next_line_block_position += size.block; self.next_line_block_position += size.block;
self.boxes.push(Fragment::Anonymous(AnonymousFragment { 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 }, rect: Rect { start_corner, size },
mode: containing_block.mode, mode: containing_block.style.writing_mode,
})) }))
} }
} }
@ -446,10 +492,11 @@ fn layout_atomic<'box_tree>(
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
inline_size, inline_size,
block_size, block_size,
mode: atomic.style.writing_mode(), style: &atomic.style,
}; };
assert_eq!( assert_eq!(
ifc.containing_block.mode, containing_block_for_children.mode, ifc.containing_block.style.writing_mode,
containing_block_for_children.style.writing_mode,
"Mixed writing modes are not supported yet" "Mixed writing modes are not supported yet"
); );
// FIXME is this correct? // FIXME is this correct?
@ -599,7 +646,7 @@ impl TextRun {
LineHeight::Number(n) => font_size * n.0, LineHeight::Number(n) => font_size * n.0,
LineHeight::Length(l) => l.0, LineHeight::Length(l) => l.0,
}; };
let content_rect = Rect { let rect = Rect {
start_corner: Vec2 { start_corner: Vec2 {
block: Length::zero(), block: Length::zero(),
inline: ifc.inline_position - ifc.current_nesting_level.inline_start, inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
@ -617,7 +664,7 @@ impl TextRun {
.fragments_so_far .fragments_so_far
.push(Fragment::Text(TextFragment { .push(Fragment::Text(TextFragment {
parent_style: self.parent_style.clone(), parent_style: self.parent_style.clone(),
content_rect, rect,
ascent: font_ascent.into(), ascent: font_ascent.into(),
font_key, font_key,
glyphs, glyphs,
@ -637,8 +684,8 @@ impl TextRun {
partial.parent_nesting_level.inline_start = Length::zero(); partial.parent_nesting_level.inline_start = Length::zero();
nesting_level = &mut partial.parent_nesting_level; nesting_level = &mut partial.parent_nesting_level;
} }
ifc.line_boxes ifc.lines
.finish_line(nesting_level, ifc.containing_block); .finish_line(nesting_level, ifc.containing_block, ifc.inline_position);
ifc.inline_position = Length::zero(); ifc.inline_position = Length::zero();
} }
} }

View file

@ -14,11 +14,12 @@ use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::adjust_static_positions; use crate::positioned::adjust_static_positions;
use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::style_ext::{ComputedValuesExt, Position}; use crate::style_ext::ComputedValuesExt;
use crate::{relative_adjustement, ContainingBlock}; use crate::{relative_adjustement, ContainingBlock};
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt; use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc; use servo_arc::Arc;
use style::computed_values::position::T as Position;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::values::generics::length::MaxSize; use style::values::generics::length::MaxSize;
@ -323,11 +324,15 @@ impl BlockLevelBox {
}, },
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
absolutely_positioned_fragments.push(box_.layout(Vec2::zero(), tree_rank)); absolutely_positioned_fragments.push(box_.layout(Vec2::zero(), tree_rank));
Fragment::Anonymous(AnonymousFragment::no_op(containing_block.mode)) Fragment::Anonymous(AnonymousFragment::no_op(
containing_block.style.writing_mode,
))
}, },
BlockLevelBox::OutOfFlowFloatBox(_box_) => { BlockLevelBox::OutOfFlowFloatBox(_box_) => {
// TODO // TODO
Fragment::Anonymous(AnonymousFragment::no_op(containing_block.mode)) Fragment::Anonymous(AnonymousFragment::no_op(
containing_block.style.writing_mode,
))
}, },
} }
} }
@ -412,11 +417,11 @@ fn layout_in_flow_non_replaced_block_level<'a>(
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
inline_size, inline_size,
block_size, block_size,
mode: style.writing_mode(), style,
}; };
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
assert_eq!( assert_eq!(
containing_block.mode, containing_block_for_children.mode, containing_block.style.writing_mode, containing_block_for_children.style.writing_mode,
"Mixed writing modes are not supported yet" "Mixed writing modes are not supported yet"
); );
@ -493,7 +498,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
&mut flow_layout.fragments, &mut flow_layout.fragments,
&content_rect.size, &content_rect.size,
&padding, &padding,
containing_block_for_children.mode, style,
) )
} }
BoxFragment { BoxFragment {
@ -520,7 +525,7 @@ fn layout_in_flow_replaced_block_level<'a>(
let border = style.border_width(); let border = style.border_width();
let computed_margin = style.margin().percentages_relative_to(cbis); let computed_margin = style.margin().percentages_relative_to(cbis);
let pb = &padding + &border; let pb = &padding + &border;
let mode = style.writing_mode(); let mode = style.writing_mode;
// FIXME(nox): We shouldn't pretend we always have a fully known intrinsic size. // FIXME(nox): We shouldn't pretend we always have a fully known intrinsic size.
let intrinsic_size = replaced.intrinsic_size.size_to_flow_relative(mode); let intrinsic_size = replaced.intrinsic_size.size_to_flow_relative(mode);
// FIXME(nox): This can divide by zero. // FIXME(nox): This can divide by zero.

View file

@ -15,11 +15,12 @@ use crate::geom::flow_relative::Vec2;
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest; use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Direction, Display, DisplayGeneratingBox, DisplayInside, WritingMode}; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::{ContainingBlock, DefiniteContainingBlock}; use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
use script_layout_interface::wrapper_traits::LayoutNode; use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc; use servo_arc::Arc;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto}; use style::values::computed::{Length, LengthOrAuto};
use style::Zero; use style::Zero;
use style_traits::CSSPixel; use style_traits::CSSPixel;
@ -97,6 +98,7 @@ impl BoxTreeRoot {
layout_context: &LayoutContext, layout_context: &LayoutContext,
viewport: geom::Size<CSSPixel>, viewport: geom::Size<CSSPixel>,
) -> FragmentTreeRoot { ) -> FragmentTreeRoot {
let style = ComputedValues::initial_values();
let initial_containing_block_size = Vec2 { let initial_containing_block_size = Vec2 {
inline: Length::new(viewport.width), inline: Length::new(viewport.width),
block: Length::new(viewport.height), block: Length::new(viewport.height),
@ -107,7 +109,7 @@ impl BoxTreeRoot {
block_size: LengthOrAuto::LengthPercentage(initial_containing_block_size.block), block_size: LengthOrAuto::LengthPercentage(initial_containing_block_size.block),
// FIXME: use the documents mode: // FIXME: use the documents mode:
// https://drafts.csswg.org/css-writing-modes/#principal-flow // https://drafts.csswg.org/css-writing-modes/#principal-flow
mode: (WritingMode::HorizontalTb, Direction::Ltr), style,
}; };
let dummy_tree_rank = 0; let dummy_tree_rank = 0;
let mut absolutely_positioned_fragments = vec![]; let mut absolutely_positioned_fragments = vec![];
@ -120,7 +122,7 @@ impl BoxTreeRoot {
let initial_containing_block = DefiniteContainingBlock { let initial_containing_block = DefiniteContainingBlock {
size: initial_containing_block_size, size: initial_containing_block_size,
mode: initial_containing_block.mode, style,
}; };
independent_layout.fragments.par_extend( independent_layout.fragments.par_extend(
absolutely_positioned_fragments absolutely_positioned_fragments

View file

@ -2,11 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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 crate::style_ext::{Direction, WritingMode};
use gfx::text::glyph::GlyphStore; use gfx::text::glyph::GlyphStore;
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
use std::sync::Arc; use std::sync::Arc;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::Length;
use style::Zero; use style::Zero;
@ -51,12 +51,12 @@ pub(crate) struct CollapsedMargin {
pub(crate) struct AnonymousFragment { pub(crate) struct AnonymousFragment {
pub rect: Rect<Length>, pub rect: Rect<Length>,
pub children: Vec<Fragment>, pub children: Vec<Fragment>,
pub mode: (WritingMode, Direction), pub mode: WritingMode,
} }
pub(crate) struct TextFragment { pub(crate) struct TextFragment {
pub parent_style: ServoArc<ComputedValues>, pub parent_style: ServoArc<ComputedValues>,
pub content_rect: Rect<Length>, pub rect: Rect<Length>,
pub ascent: Length, pub ascent: Length,
pub font_key: FontInstanceKey, pub font_key: FontInstanceKey,
pub glyphs: Vec<Arc<GlyphStore>>, pub glyphs: Vec<Arc<GlyphStore>>,
@ -64,12 +64,23 @@ pub(crate) struct TextFragment {
pub(crate) struct ImageFragment { pub(crate) struct ImageFragment {
pub style: ServoArc<ComputedValues>, pub style: ServoArc<ComputedValues>,
pub content_rect: Rect<Length>, pub rect: Rect<Length>,
pub image_key: ImageKey, pub image_key: ImageKey,
} }
impl Fragment {
pub fn position_mut(&mut self) -> &mut Vec2<Length> {
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 { impl AnonymousFragment {
pub fn no_op(mode: (WritingMode, Direction)) -> Self { pub fn no_op(mode: WritingMode) -> Self {
Self { Self {
children: vec![], children: vec![],
rect: Rect::zero(), rect: Rect::zero(),

View file

@ -2,9 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::style_ext::{Direction, WritingMode};
use std::fmt; use std::fmt;
use std::ops::{Add, AddAssign, Sub}; use std::ops::{Add, AddAssign, Sub};
use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection};
use style::logical_geometry::{PhysicalCorner, WritingMode};
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::Zero; use style::Zero;
use style_traits::CSSPixel; use style_traits::CSSPixel;
@ -94,9 +95,9 @@ where
} }
impl<T: Clone> physical::Vec2<T> { impl<T: Clone> physical::Vec2<T> {
pub fn size_to_flow_relative(&self, mode: (WritingMode, Direction)) -> flow_relative::Vec2<T> { pub fn size_to_flow_relative(&self, mode: WritingMode) -> flow_relative::Vec2<T> {
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical // https://drafts.csswg.org/css-writing-modes/#logical-to-physical
let (i, b) = if let (WritingMode::HorizontalTb, _) = mode { let (i, b) = if mode.is_horizontal() {
(&self.x, &self.y) (&self.x, &self.y)
} else { } else {
(&self.y, &self.x) (&self.y, &self.x)
@ -160,9 +161,9 @@ impl flow_relative::Rect<Length> {
} }
impl<T: Clone> flow_relative::Vec2<T> { impl<T: Clone> flow_relative::Vec2<T> {
pub fn size_to_physical(&self, mode: (WritingMode, Direction)) -> physical::Vec2<T> { pub fn size_to_physical(&self, mode: WritingMode) -> physical::Vec2<T> {
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical // https://drafts.csswg.org/css-writing-modes/#logical-to-physical
let (x, y) = if let (WritingMode::HorizontalTb, _) = mode { let (x, y) = if mode.is_horizontal() {
(&self.inline, &self.block) (&self.inline, &self.block)
} else { } else {
(&self.block, &self.inline) (&self.block, &self.inline)
@ -181,21 +182,20 @@ impl From<physical::Vec2<Length>> for Point<CSSPixel> {
} }
impl<T: Clone> physical::Sides<T> { impl<T: Clone> physical::Sides<T> {
pub fn to_flow_relative(&self, mode: (WritingMode, Direction)) -> flow_relative::Sides<T> { pub fn to_flow_relative(&self, mode: WritingMode) -> flow_relative::Sides<T> {
use Direction::*;
use WritingMode::*;
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical // https://drafts.csswg.org/css-writing-modes/#logical-to-physical
let (bs, be) = match mode.0 { let block_flow = mode.block_flow_direction();
HorizontalTb => (&self.top, &self.bottom), let (bs, be) = match mode.block_flow_direction() {
VerticalRl => (&self.right, &self.left), BlockFlowDirection::TopToBottom => (&self.top, &self.bottom),
VerticalLr => (&self.left, &self.right), BlockFlowDirection::RightToLeft => (&self.right, &self.left),
BlockFlowDirection::LeftToRight => (&self.left, &self.right),
}; };
let (is, ie) = match mode { use BlockFlowDirection::TopToBottom;
(HorizontalTb, Ltr) => (&self.left, &self.right), let (is, ie) = match (block_flow, mode.inline_base_direction()) {
(HorizontalTb, Rtl) => (&self.right, &self.left), (TopToBottom, InlineBaseDirection::LeftToRight) => (&self.left, &self.right),
(VerticalRl, Ltr) | (VerticalLr, Ltr) => (&self.top, &self.bottom), (TopToBottom, InlineBaseDirection::RightToLeft) => (&self.right, &self.left),
(VerticalRl, Rtl) | (VerticalLr, Rtl) => (&self.bottom, &self.top), (_, InlineBaseDirection::LeftToRight) => (&self.top, &self.bottom),
(_, InlineBaseDirection::RightToLeft) => (&self.bottom, &self.top),
}; };
flow_relative::Sides { flow_relative::Sides {
inline_start: is.clone(), inline_start: is.clone(),
@ -298,7 +298,7 @@ impl<T> flow_relative::Rect<T> {
pub fn to_physical( pub fn to_physical(
&self, &self,
mode: (WritingMode, Direction), mode: WritingMode,
// Will be needed for other writing modes // Will be needed for other writing modes
// FIXME: what if the containing block has a different mode? // FIXME: what if the containing block has a different mode?
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
@ -308,10 +308,9 @@ impl<T> flow_relative::Rect<T> {
T: Clone, T: Clone,
{ {
// Top-left corner // Top-left corner
let (tl_x, tl_y) = if let (WritingMode::HorizontalTb, Direction::Ltr) = mode { let (tl_x, tl_y) = match mode.start_start_physical_corner() {
(&self.start_corner.inline, &self.start_corner.block) PhysicalCorner::TopLeft => (&self.start_corner.inline, &self.start_corner.block),
} else { _ => unimplemented!(),
unimplemented!()
}; };
physical::Rect { physical::Rect {
top_left: physical::Vec2 { top_left: physical::Vec2 {

View file

@ -27,20 +27,21 @@ pub mod wrapper;
pub use flow::{BoxTreeRoot, FragmentTreeRoot}; pub use flow::{BoxTreeRoot, FragmentTreeRoot};
use crate::geom::flow_relative::Vec2; use crate::geom::flow_relative::Vec2;
use crate::style_ext::{ComputedValuesExt, Direction, Position, WritingMode}; use crate::style_ext::ComputedValuesExt;
use style::computed_values::position::T as Position;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto}; use style::values::computed::{Length, LengthOrAuto};
use style::Zero; use style::Zero;
struct ContainingBlock { struct ContainingBlock<'a> {
inline_size: Length, inline_size: Length,
block_size: LengthOrAuto, block_size: LengthOrAuto,
mode: (WritingMode, Direction), style: &'a ComputedValues,
} }
struct DefiniteContainingBlock { struct DefiniteContainingBlock<'a> {
size: Vec2<Length>, size: Vec2<Length>,
mode: (WritingMode, Direction), style: &'a ComputedValues,
} }
/// https://drafts.csswg.org/css2/visuren.html#relative-positioning /// https://drafts.csswg.org/css2/visuren.html#relative-positioning

View file

@ -8,7 +8,7 @@ use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::sizing::ContentSizesRequest; use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, Direction, DisplayInside, WritingMode}; use crate::style_ext::{ComputedValuesExt, DisplayInside};
use crate::{ContainingBlock, DefiniteContainingBlock}; use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use servo_arc::Arc; use servo_arc::Arc;
@ -128,7 +128,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
fragments: &mut Vec<Fragment>, fragments: &mut Vec<Fragment>,
content_rect_size: &Vec2<Length>, content_rect_size: &Vec2<Length>,
padding: &Sides<Length>, padding: &Sides<Length>,
mode: (WritingMode, Direction), style: &ComputedValues,
) { ) {
if absolute.is_empty() { if absolute.is_empty() {
return; return;
@ -141,7 +141,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
.inflate(&padding); .inflate(&padding);
let containing_block = DefiniteContainingBlock { let containing_block = DefiniteContainingBlock {
size: padding_rect.size.clone(), size: padding_rect.size.clone(),
mode, style,
}; };
fragments.push(Fragment::Anonymous(AnonymousFragment { fragments.push(Fragment::Anonymous(AnonymousFragment {
children: absolute children: absolute
@ -149,7 +149,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
.map(|a| a.layout(layout_context, &containing_block)) .map(|a| a.layout(layout_context, &containing_block))
.collect(), .collect(),
rect: padding_rect, rect: padding_rect,
mode, mode: style.writing_mode,
})) }))
} }
@ -324,11 +324,12 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
inline_size, inline_size,
block_size, block_size,
mode: style.writing_mode(), style,
}; };
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
assert_eq!( assert_eq!(
containing_block.mode, containing_block_for_children.mode, containing_block.style.writing_mode,
containing_block_for_children.style.writing_mode,
"Mixed writing modes are not supported yet" "Mixed writing modes are not supported yet"
); );
let dummy_tree_rank = 0; let dummy_tree_rank = 0;
@ -369,7 +370,7 @@ impl<'a> AbsolutelyPositionedFragment<'a> {
&mut independent_layout.fragments, &mut independent_layout.fragments,
&content_rect.size, &content_rect.size,
&padding, &padding,
style.writing_mode(), style,
); );
Fragment::Box(BoxFragment { Fragment::Box(BoxFragment {

View file

@ -45,7 +45,7 @@ impl ReplacedContent {
.map(|image_key| { .map(|image_key| {
Fragment::Image(ImageFragment { Fragment::Image(ImageFragment {
style: style.clone(), style: style.clone(),
content_rect: flow_relative::Rect { rect: flow_relative::Rect {
start_corner: flow_relative::Vec2::zero(), start_corner: flow_relative::Vec2::zero(),
size, size,
}, },

View file

@ -9,10 +9,6 @@ use style::values::computed::{NonNegativeLengthPercentage, Size};
use style::values::generics::length::MaxSize; use style::values::generics::length::MaxSize;
use style::values::specified::box_ as stylo; use style::values::specified::box_ as stylo;
pub use style::computed_values::direction::T as Direction;
pub use style::computed_values::position::T as Position;
pub use style::computed_values::writing_mode::T as WritingMode;
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum Display { pub(crate) enum Display {
None, None,
@ -44,8 +40,6 @@ pub(crate) enum DisplayInside {
} }
pub(crate) trait ComputedValuesExt { pub(crate) trait ComputedValuesExt {
fn writing_mode(&self) -> (WritingMode, Direction);
fn writing_mode_is_horizontal(&self) -> bool;
fn inline_size_is_auto(&self) -> bool; fn inline_size_is_auto(&self) -> bool;
fn inline_box_offsets_are_both_non_auto(&self) -> bool; fn inline_box_offsets_are_both_non_auto(&self) -> bool;
fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto>; fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
@ -58,44 +52,24 @@ pub(crate) trait ComputedValuesExt {
} }
impl ComputedValuesExt for ComputedValues { impl ComputedValuesExt for ComputedValues {
fn writing_mode(&self) -> (WritingMode, Direction) {
let inherited_box = self.get_inherited_box();
let writing_mode = inherited_box.writing_mode;
let direction = inherited_box.direction;
(writing_mode, direction)
}
fn writing_mode_is_horizontal(&self) -> bool {
match self.get_inherited_box().writing_mode {
WritingMode::HorizontalTb => true,
WritingMode::VerticalLr | WritingMode::VerticalRl => false,
}
}
fn inline_size_is_auto(&self) -> bool { fn inline_size_is_auto(&self) -> bool {
let position = self.get_position(); let position = self.get_position();
let size = if self.writing_mode_is_horizontal() { let size = if self.writing_mode.is_horizontal() {
position.width position.width
} else { } else {
position.height position.height
}; };
matches!(size, Size::Auto) size == Size::Auto
} }
fn inline_box_offsets_are_both_non_auto(&self) -> bool { fn inline_box_offsets_are_both_non_auto(&self) -> bool {
let position = self.get_position(); let position = self.get_position();
let offsets = if self.writing_mode_is_horizontal() { let (a, b) = if self.writing_mode.is_horizontal() {
(position.left, position.right) (position.left, position.right)
} else { } else {
(position.top, position.bottom) (position.top, position.bottom)
}; };
matches!( a != LengthPercentageOrAuto::Auto && b != LengthPercentageOrAuto::Auto
offsets,
(
LengthPercentageOrAuto::LengthPercentage(_),
LengthPercentageOrAuto::LengthPercentage(_),
)
)
} }
#[inline] #[inline]
@ -107,7 +81,7 @@ impl ComputedValuesExt for ComputedValues {
bottom: position.bottom, bottom: position.bottom,
right: position.right, right: position.right,
} }
.to_flow_relative(self.writing_mode()) .to_flow_relative(self.writing_mode)
} }
#[inline] #[inline]
@ -117,7 +91,7 @@ impl ComputedValuesExt for ComputedValues {
x: size_to_length(position.width), x: size_to_length(position.width),
y: size_to_length(position.height), y: size_to_length(position.height),
} }
.size_to_flow_relative(self.writing_mode()) .size_to_flow_relative(self.writing_mode)
} }
#[inline] #[inline]
@ -127,7 +101,7 @@ impl ComputedValuesExt for ComputedValues {
x: size_to_length(position.min_width), x: size_to_length(position.min_width),
y: size_to_length(position.min_height), y: size_to_length(position.min_height),
} }
.size_to_flow_relative(self.writing_mode()) .size_to_flow_relative(self.writing_mode)
} }
#[inline] #[inline]
@ -141,7 +115,7 @@ impl ComputedValuesExt for ComputedValues {
x: unwrap(position.max_width), x: unwrap(position.max_width),
y: unwrap(position.max_height), y: unwrap(position.max_height),
} }
.size_to_flow_relative(self.writing_mode()) .size_to_flow_relative(self.writing_mode)
} }
#[inline] #[inline]
@ -153,7 +127,7 @@ impl ComputedValuesExt for ComputedValues {
bottom: padding.padding_bottom.0, bottom: padding.padding_bottom.0,
right: padding.padding_right.0, right: padding.padding_right.0,
} }
.to_flow_relative(self.writing_mode()) .to_flow_relative(self.writing_mode)
} }
fn border_width(&self) -> flow_relative::Sides<Length> { fn border_width(&self) -> flow_relative::Sides<Length> {
@ -164,7 +138,7 @@ impl ComputedValuesExt for ComputedValues {
bottom: border.border_bottom_width.0, bottom: border.border_bottom_width.0,
right: border.border_right_width.0, right: border.border_right_width.0,
} }
.to_flow_relative(self.writing_mode()) .to_flow_relative(self.writing_mode)
} }
fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> { fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
@ -175,7 +149,7 @@ impl ComputedValuesExt for ComputedValues {
bottom: margin.margin_bottom, bottom: margin.margin_bottom,
right: margin.margin_right, right: margin.margin_right,
} }
.to_flow_relative(self.writing_mode()) .to_flow_relative(self.writing_mode)
} }
} }

View file

@ -173,6 +173,11 @@ impl WritingMode {
self.intersects(WritingMode::VERTICAL) self.intersects(WritingMode::VERTICAL)
} }
#[inline]
pub fn is_horizontal(&self) -> bool {
!self.is_vertical()
}
/// Assuming .is_vertical(), does the block direction go left to right? /// Assuming .is_vertical(), does the block direction go left to right?
#[inline] #[inline]
pub fn is_vertical_lr(&self) -> bool { pub fn is_vertical_lr(&self) -> bool {
@ -201,6 +206,20 @@ impl WritingMode {
self.intersects(WritingMode::UPRIGHT) 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] #[inline]
pub fn inline_start_physical_side(&self) -> PhysicalSide { pub fn inline_start_physical_side(&self) -> PhysicalSide {
match (self.is_vertical(), self.is_inline_tb(), self.is_bidi_ltr()) { match (self.is_vertical(), self.is_inline_tb(), self.is_bidi_ltr()) {

View file

@ -156,7 +156,6 @@ ${helpers.predefined_type(
"TextAlign", "TextAlign",
"computed::TextAlign::Start", "computed::TextAlign::Start",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text/#propdef-text-align", spec="https://drafts.csswg.org/css-text/#propdef-text-align",
servo_restyle_damage = "reflow", servo_restyle_damage = "reflow",

View file

@ -2590,8 +2590,10 @@ pub mod style_structs {
/// The ${style_struct.name} style struct. /// The ${style_struct.name} style struct.
pub struct ${style_struct.name} { pub struct ${style_struct.name} {
% for longhand in style_struct.longhands: % for longhand in style_struct.longhands:
/// The ${longhand.name} computed value. % if not longhand.logical:
pub ${longhand.ident}: longhands::${longhand.ident}::computed_value::T, /// The ${longhand.name} computed value.
pub ${longhand.ident}: longhands::${longhand.ident}::computed_value::T,
% endif
% endfor % endfor
% if style_struct.name == "InheritedText": % if style_struct.name == "InheritedText":
/// The "used" text-decorations that apply to this box. /// The "used" text-decorations that apply to this box.
@ -3836,7 +3838,9 @@ mod lazy_static_module {
% for style_struct in data.active_style_structs(): % for style_struct in data.active_style_structs():
${style_struct.ident}: Arc::new(style_structs::${style_struct.name} { ${style_struct.ident}: Arc::new(style_structs::${style_struct.name} {
% for longhand in style_struct.longhands: % for longhand in style_struct.longhands:
${longhand.ident}: longhands::${longhand.ident}::get_initial_value(), % if not longhand.logical:
${longhand.ident}: longhands::${longhand.ident}::get_initial_value(),
% endif
% endfor % endfor
% if style_struct.name == "InheritedText": % if style_struct.name == "InheritedText":
text_decorations_in_effect: text_decorations_in_effect:

View file

@ -544,6 +544,7 @@ pub enum TextAlignKeyword {
Left, Left,
Right, Right,
Center, Center,
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
Justify, Justify,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozCenter, MozCenter,
@ -551,11 +552,11 @@ pub enum TextAlignKeyword {
MozLeft, MozLeft,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
MozRight, MozRight,
#[cfg(feature = "servo")] #[cfg(feature = "servo-layout-2013")]
ServoCenter, ServoCenter,
#[cfg(feature = "servo")] #[cfg(feature = "servo-layout-2013")]
ServoLeft, ServoLeft,
#[cfg(feature = "servo")] #[cfg(feature = "servo-layout-2013")]
ServoRight, ServoRight,
#[css(skip)] #[css(skip)]
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]