Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement `text-align` (except `justify`) #25203

Merged
merged 6 commits into from Dec 10, 2019
@@ -4,7 +4,6 @@

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

@@ -69,15 +70,16 @@ struct PartialInlineBoxFragment<'box_tree> {

struct InlineFormattingContextState<'box_tree, 'a> {
absolutely_positioned_fragments: &'a mut Vec<AbsolutelyPositionedFragment<'box_tree>>,
containing_block: &'a ContainingBlock,
line_boxes: LinesBoxes,
containing_block: &'a ContainingBlock<'a>,
lines: Lines,
inline_position: Length,
partial_inline_boxes_stack: Vec<PartialInlineBoxFragment<'box_tree>>,
current_nesting_level: InlineNestingLevelState<'box_tree>,
}

struct LinesBoxes {
boxes: Vec<Fragment>,
struct Lines {
// One anonymous fragment per line
fragments: Vec<Fragment>,
next_line_block_position: Length,
}

@@ -201,8 +203,8 @@ impl InlineFormattingContext {
absolutely_positioned_fragments,
containing_block,
partial_inline_boxes_stack: Vec::new(),
line_boxes: LinesBoxes {
boxes: Vec::new(),
lines: Lines {
fragments: Vec::new(),
next_line_block_position: Length::zero(),
},
inline_position: Length::zero(),
@@ -233,7 +235,7 @@ impl InlineFormattingContext {
DisplayOutside::Inline => ifc.inline_position,
DisplayOutside::Block => Length::zero(),
},
block: ifc.line_boxes.next_line_block_position,
block: ifc.lines.next_line_block_position,
},
Display::Contents => {
panic!("display:contents does not generate an abspos box")
@@ -259,40 +261,84 @@ impl InlineFormattingContext {
);
ifc.current_nesting_level = partial.parent_nesting_level
} else {
ifc.line_boxes
.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.line_boxes.boxes,
content_block_size: ifc.line_boxes.next_line_block_position,
fragments: ifc.lines.fragments,
content_block_size: ifc.lines.next_line_block_position,
collapsible_margins_in_children: CollapsedBlockMargins::zero(),
};
}
}
}
}

impl LinesBoxes {
impl Lines {
fn finish_line(
&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.boxes.push(Fragment::Anonymous(AnonymousFragment {
children: std::mem::take(&mut top_nesting_level.fragments_so_far),
self.fragments.push(Fragment::Anonymous(AnonymousFragment {
children: line_contents,
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 {
inline_size,
block_size,
mode: atomic.style.writing_mode(),
style: &atomic.style,
};
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"
);
// FIXME is this correct?
@@ -599,7 +646,7 @@ impl TextRun {
LineHeight::Number(n) => font_size * n.0,
LineHeight::Length(l) => l.0,
};
let content_rect = Rect {
let rect = Rect {
start_corner: Vec2 {
block: Length::zero(),
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
@@ -617,7 +664,7 @@ impl TextRun {
.fragments_so_far
.push(Fragment::Text(TextFragment {
parent_style: self.parent_style.clone(),
content_rect,
rect,
ascent: font_ascent.into(),
font_key,
glyphs,
@@ -637,8 +684,8 @@ impl TextRun {
partial.parent_nesting_level.inline_start = Length::zero();
nesting_level = &mut partial.parent_nesting_level;
}
ifc.line_boxes
.finish_line(nesting_level, ifc.containing_block);
ifc.lines
.finish_line(nesting_level, ifc.containing_block, ifc.inline_position);
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::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment};
use crate::replaced::ReplacedContent;
use crate::style_ext::{ComputedValuesExt, Position};
use crate::style_ext::ComputedValuesExt;
use crate::{relative_adjustement, ContainingBlock};
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc;
use style::computed_values::position::T as Position;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::values::generics::length::MaxSize;
@@ -323,11 +324,15 @@ impl BlockLevelBox {
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
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_) => {
// 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 {
inline_size,
block_size,
mode: style.writing_mode(),
style,
};
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
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"
);

@@ -493,7 +498,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
&mut flow_layout.fragments,
&content_rect.size,
&padding,
containing_block_for_children.mode,
style,
)
}
BoxFragment {
@@ -520,7 +525,7 @@ fn layout_in_flow_replaced_block_level<'a>(
let border = style.border_width();
let computed_margin = style.margin().percentages_relative_to(cbis);
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.
let intrinsic_size = replaced.intrinsic_size.size_to_flow_relative(mode);
// FIXME(nox): This can divide by zero.
@@ -15,11 +15,12 @@ use crate::geom::flow_relative::Vec2;
use crate::positioned::AbsolutelyPositionedBox;
use crate::replaced::ReplacedContent;
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 rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator};
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto};
use style::Zero;
use style_traits::CSSPixel;
@@ -97,6 +98,7 @@ impl BoxTreeRoot {
layout_context: &LayoutContext,
viewport: geom::Size<CSSPixel>,
) -> FragmentTreeRoot {
let style = ComputedValues::initial_values();
let initial_containing_block_size = Vec2 {
inline: Length::new(viewport.width),
block: Length::new(viewport.height),
@@ -107,7 +109,7 @@ impl BoxTreeRoot {
block_size: LengthOrAuto::LengthPercentage(initial_containing_block_size.block),
// FIXME: use the document’s mode:
// https://drafts.csswg.org/css-writing-modes/#principal-flow
mode: (WritingMode::HorizontalTb, Direction::Ltr),
style,
};
let dummy_tree_rank = 0;
let mut absolutely_positioned_fragments = vec![];
@@ -120,7 +122,7 @@ impl BoxTreeRoot {

let initial_containing_block = DefiniteContainingBlock {
size: initial_containing_block_size,
mode: initial_containing_block.mode,
style,
};
independent_layout.fragments.par_extend(
absolutely_positioned_fragments
@@ -2,11 +2,11 @@
* 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::style_ext::{Direction, WritingMode};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use gfx::text::glyph::GlyphStore;
use servo_arc::Arc as ServoArc;
use std::sync::Arc;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style::Zero;
@@ -51,25 +51,36 @@ pub(crate) struct CollapsedMargin {
pub(crate) struct AnonymousFragment {
pub rect: Rect<Length>,
pub children: Vec<Fragment>,
pub mode: (WritingMode, Direction),
pub mode: WritingMode,
}

pub(crate) struct TextFragment {
pub parent_style: ServoArc<ComputedValues>,
pub content_rect: Rect<Length>,
pub rect: Rect<Length>,
pub ascent: Length,
pub font_key: FontInstanceKey,
pub glyphs: Vec<Arc<GlyphStore>>,
}

pub(crate) struct ImageFragment {
pub style: ServoArc<ComputedValues>,
pub content_rect: Rect<Length>,
pub rect: Rect<Length>,
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 {
pub fn no_op(mode: (WritingMode, Direction)) -> Self {
pub fn no_op(mode: WritingMode) -> Self {
Self {
children: vec![],
rect: Rect::zero(),
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.