Implement text-align (except justify)

This commit is contained in:
Simon Sapin 2019-12-07 14:08:11 +01:00
parent 6d91d77fba
commit 9f4b1a0f14
5 changed files with 84 additions and 13 deletions

View file

@ -18,6 +18,7 @@ use gfx::text::text_run::GlyphRun;
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::specified::text::TextAlignKeyword;
use style::Zero;
use webrender_api::FontInstanceKey;
@ -260,8 +261,11 @@ impl InlineFormattingContext {
);
ifc.current_nesting_level = partial.parent_nesting_level
} else {
ifc.lines
.finish_line(&mut ifc.current_nesting_level, containing_block);
ifc.lines.finish_line(
&mut ifc.current_nesting_level,
containing_block,
ifc.inline_position,
);
return FlowLayout {
fragments: ifc.lines.fragments,
content_block_size: ifc.lines.next_line_block_position,
@ -277,21 +281,62 @@ impl Lines {
&mut self,
top_nesting_level: &mut InlineNestingLevelState,
containing_block: &ContainingBlock,
line_content_inline_size: Length,
) {
let mut line_contents = std::mem::take(&mut top_nesting_level.fragments_so_far);
let line_block_size = std::mem::replace(
&mut top_nesting_level.max_block_size_of_fragments_so_far,
Length::zero(),
);
enum TextAlign {
Start,
Center,
End,
}
let line_left_is_inline_start = containing_block
.style
.writing_mode
.line_left_is_inline_start();
let text_align = match containing_block.style.clone_text_align() {
TextAlignKeyword::Start => TextAlign::Start,
TextAlignKeyword::Center => TextAlign::Center,
TextAlignKeyword::End => TextAlign::End,
TextAlignKeyword::Left => {
if line_left_is_inline_start {
TextAlign::Start
} else {
TextAlign::End
}
},
TextAlignKeyword::Right => {
if line_left_is_inline_start {
TextAlign::End
} else {
TextAlign::Start
}
},
};
let move_by = match text_align {
TextAlign::Start => Length::zero(),
TextAlign::Center => (containing_block.inline_size - line_content_inline_size) / 2.,
TextAlign::End => containing_block.inline_size - line_content_inline_size,
};
if move_by > Length::zero() {
for fragment in &mut line_contents {
fragment.position_mut().inline += move_by;
}
}
let start_corner = Vec2 {
inline: Length::zero(),
block: self.next_line_block_position,
};
let size = Vec2 {
inline: containing_block.inline_size,
block: std::mem::replace(
&mut top_nesting_level.max_block_size_of_fragments_so_far,
Length::zero(),
),
block: line_block_size,
};
self.next_line_block_position += size.block;
self.fragments.push(Fragment::Anonymous(AnonymousFragment {
children: std::mem::take(&mut top_nesting_level.fragments_so_far),
children: line_contents,
rect: Rect { start_corner, size },
mode: containing_block.style.writing_mode,
}))
@ -639,7 +684,8 @@ impl TextRun {
partial.parent_nesting_level.inline_start = Length::zero();
nesting_level = &mut partial.parent_nesting_level;
}
ifc.lines.finish_line(nesting_level, ifc.containing_block);
ifc.lines
.finish_line(nesting_level, ifc.containing_block, ifc.inline_position);
ifc.inline_position = Length::zero();
}
}

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::geom::flow_relative::{Rect, Sides};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use gfx::text::glyph::GlyphStore;
use servo_arc::Arc as ServoArc;
use std::sync::Arc;
@ -68,6 +68,17 @@ pub(crate) struct ImageFragment {
pub image_key: ImageKey,
}
impl Fragment {
pub fn position_mut(&mut self) -> &mut Vec2<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) -> Self {
Self {

View file

@ -206,6 +206,20 @@ impl WritingMode {
self.intersects(WritingMode::UPRIGHT)
}
/// https://drafts.csswg.org/css-writing-modes/#logical-to-physical
///
/// | Return | line-left is… | line-right is… |
/// |---------|---------------|----------------|
/// | `true` | inline-start | inline-end |
/// | `false` | inline-end | inline-start |
#[inline]
pub fn line_left_is_inline_start(&self) -> bool {
// https://drafts.csswg.org/css-writing-modes/#inline-start
// “For boxes with a used direction value of ltr, this means the line-left side.
// For boxes with a used direction value of rtl, this means the line-right side.”
self.is_bidi_ltr()
}
#[inline]
pub fn inline_start_physical_side(&self) -> PhysicalSide {
match (self.is_vertical(), self.is_inline_tb(), self.is_bidi_ltr()) {

View file

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

View file

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