Auto merge of #25888 - ferjm:text.decoration.2020, r=nox

Partial text decoration support for layout 2020

- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #25166
- [X] There are tests for these changes
This commit is contained in:
bors-servo 2020-03-23 11:18:18 -04:00 committed by GitHub
commit acd14672e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
84 changed files with 743 additions and 53 deletions

View file

@ -19,6 +19,7 @@ use servo_arc::Arc;
use std::convert::{TryFrom, TryInto};
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
use style::values::specified::text::TextDecorationLine;
impl BlockFormattingContext {
pub fn construct<'dom>(
@ -27,9 +28,16 @@ impl BlockFormattingContext {
style: &Arc<ComputedValues>,
contents: NonReplacedContents,
content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) {
let (contents, contains_floats, inline_content_sizes) =
BlockContainer::construct(context, node, style, contents, content_sizes);
let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct(
context,
node,
style,
contents,
content_sizes,
propagated_text_decoration_line,
);
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
// https://dbaron.org/css/intrinsic/#intrinsic
let bfc = Self {
@ -52,6 +60,7 @@ enum BlockLevelCreator {
Independent {
display_inside: DisplayInside,
contents: Contents,
propagated_text_decoration_line: TextDecorationLine,
},
OutOfFlowAbsolutelyPositionedBox {
display_inside: DisplayInside,
@ -72,7 +81,7 @@ enum BlockLevelCreator {
/// Deferring allows using rayons `into_par_iter`.
enum IntermediateBlockContainer {
InlineFormattingContext(InlineFormattingContext),
Deferred(NonReplacedContents),
Deferred(NonReplacedContents, TextDecorationLine),
}
/// A builder for a block container.
@ -140,13 +149,16 @@ impl BlockContainer {
block_container_style: &Arc<ComputedValues>,
contents: NonReplacedContents,
content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
let text_decoration_line =
propagated_text_decoration_line | block_container_style.clone_text_decoration_line();
let mut builder = BlockContainerBuilder {
context,
root,
block_container_style,
block_level_boxes: Vec::new(),
ongoing_inline_formatting_context: InlineFormattingContext::default(),
ongoing_inline_formatting_context: InlineFormattingContext::new(text_decoration_line),
ongoing_inline_boxes_stack: Vec::new(),
anonymous_style: None,
contains_floats: ContainsFloats::No,
@ -439,6 +451,8 @@ where
display_inside,
contents,
ContentSizesRequest::inline_if(!style.inline_size_is_length()),
// Text decorations are not propagated to atomic inline-level descendants.
TextDecorationLine::NONE,
),
))
};
@ -494,6 +508,9 @@ where
.push(ArcRefCell::new(fragmented_inline));
}
let propagated_text_decoration_line =
self.ongoing_inline_formatting_context.text_decoration_line;
// We found a block level element, so the ongoing inline formatting
// context needs to be ended.
self.end_ongoing_inline_formatting_context();
@ -501,11 +518,12 @@ where
let kind = match contents.try_into() {
Ok(contents) => match display_inside {
DisplayInside::Flow => BlockLevelCreator::SameFormattingContextBlock(
IntermediateBlockContainer::Deferred(contents),
IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line),
),
_ => BlockLevelCreator::Independent {
display_inside,
contents: contents.into(),
propagated_text_decoration_line,
},
},
Err(contents) => {
@ -513,6 +531,7 @@ where
BlockLevelCreator::Independent {
display_inside,
contents,
propagated_text_decoration_line,
}
},
};
@ -680,6 +699,7 @@ where
BlockLevelCreator::Independent {
display_inside,
contents,
propagated_text_decoration_line,
} => {
let content_sizes = ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() &&
@ -692,6 +712,7 @@ where
display_inside,
contents,
content_sizes,
propagated_text_decoration_line,
);
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&contents.content_sizes.outer_inline(&contents.style))
@ -742,8 +763,15 @@ impl IntermediateBlockContainer {
content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
match self {
IntermediateBlockContainer::Deferred(contents) => {
BlockContainer::construct(context, node, style, contents, content_sizes)
IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => {
BlockContainer::construct(
context,
node,
style,
contents,
content_sizes,
propagated_text_decoration_line,
)
},
IntermediateBlockContainer::InlineFormattingContext(ifc) => {
let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));

View file

@ -9,6 +9,7 @@ use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside};
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::values::specified::text::TextDecorationLine;
#[derive(Debug, Serialize)]
pub(crate) struct FloatBox {
@ -43,6 +44,8 @@ impl FloatBox {
display_inside,
contents,
content_sizes,
// Text decorations are not propagated to any out-of-flow descendants
TextDecorationLine::NONE,
),
}
}

View file

@ -9,7 +9,7 @@ use crate::flow::FlowLayout;
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
DebugId, Fragment, TextFragment,
DebugId, FontMetrics, Fragment, TextFragment,
};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{
@ -26,12 +26,14 @@ use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::specified::text::TextAlignKeyword;
use style::values::specified::text::TextDecorationLine;
use style::Zero;
use webrender_api::FontInstanceKey;
#[derive(Debug, Default, Serialize)]
pub(crate) struct InlineFormattingContext {
pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>,
pub(super) text_decoration_line: TextDecorationLine,
}
#[derive(Debug, Serialize)]
@ -68,6 +70,11 @@ struct InlineNestingLevelState<'box_tree> {
inline_start: Length,
max_block_size_of_fragments_so_far: Length,
positioning_context: Option<PositioningContext>,
/// Indicates whether this nesting level have text decorations in effect.
/// From https://drafts.csswg.org/css-text-decor/#line-decoration
// "When specified on or propagated to a block container that establishes
// an IFC..."
text_decoration_line: TextDecorationLine,
}
struct PartialInlineBoxFragment<'box_tree> {
@ -122,6 +129,13 @@ struct Lines {
}
impl InlineFormattingContext {
pub(super) fn new(text_decoration_line: TextDecorationLine) -> InlineFormattingContext {
InlineFormattingContext {
inline_level_boxes: Default::default(),
text_decoration_line,
}
}
// This works on an already-constructed `InlineFormattingContext`,
// Which would have to change if/when
// `BlockContainer::construct` parallelize their construction.
@ -256,8 +270,10 @@ impl InlineFormattingContext {
inline_start: Length::zero(),
max_block_size_of_fragments_so_far: Length::zero(),
positioning_context: None,
text_decoration_line: self.text_decoration_line,
},
};
loop {
if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() {
match &*child.borrow() {
@ -385,6 +401,7 @@ impl Lines {
block: line_block_size,
};
self.next_line_block_position += size.block;
self.fragments
.push(Fragment::Anonymous(AnonymousFragment::new(
Rect { start_corner, size },
@ -423,6 +440,8 @@ impl InlineBox {
start_corner += &relative_adjustement(&style, ifc.containing_block)
}
let positioning_context = PositioningContext::new_for_style(&style);
let text_decoration_line =
ifc.current_nesting_level.text_decoration_line | style.clone_text_decoration_line();
PartialInlineBoxFragment {
tag: self.tag,
style,
@ -441,6 +460,7 @@ impl InlineBox {
inline_start: ifc.inline_position,
max_block_size_of_fragments_so_far: Length::zero(),
positioning_context,
text_decoration_line: text_decoration_line,
},
),
}
@ -631,8 +651,7 @@ fn layout_atomic(
}
struct BreakAndShapeResult {
font_ascent: Au,
font_line_gap: Au,
font_metrics: FontMetrics,
font_key: FontInstanceKey,
runs: Vec<GlyphRun>,
break_at_start: bool,
@ -699,8 +718,7 @@ impl TextRun {
);
BreakAndShapeResult {
font_ascent: font.metrics.ascent,
font_line_gap: font.metrics.line_gap,
font_metrics: (&font.metrics).into(),
font_key: font.font_key,
runs,
break_at_start,
@ -712,8 +730,7 @@ impl TextRun {
use style::values::generics::text::LineHeight;
let BreakAndShapeResult {
font_ascent,
font_line_gap,
font_metrics,
font_key,
runs,
break_at_start: _,
@ -750,7 +767,7 @@ impl TextRun {
}
}
let line_height = match self.parent_style.get_inherited_text().line_height {
LineHeight::Normal => font_line_gap.into(),
LineHeight::Normal => font_metrics.line_gap,
LineHeight::Number(n) => font_size * n.0,
LineHeight::Length(l) => l.0,
};
@ -775,9 +792,10 @@ impl TextRun {
debug_id: DebugId::new(),
parent_style: self.parent_style.clone(),
rect,
ascent: font_ascent.into(),
font_metrics,
font_key,
glyphs,
text_decoration_line: ifc.current_nesting_level.text_decoration_line,
}));
if runs.is_empty() {
break;

View file

@ -104,6 +104,7 @@ fn construct_for_root_element<'dom>(
))],
)
} else {
let propagated_text_decoration_line = style.clone_text_decoration_line();
(
ContainsFloats::No,
vec![ArcRefCell::new(BlockLevelBox::Independent(
@ -114,6 +115,7 @@ fn construct_for_root_element<'dom>(
display_inside,
contents,
ContentSizesRequest::None,
propagated_text_decoration_line,
),
))],
)