mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #25203 - servo:text-align, r=nox
Implement `text-align` (except `justify`)
This commit is contained in:
commit
64c9928b2e
14 changed files with 190 additions and 128 deletions
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 document’s mode:
|
// FIXME: use the document’s 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
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue