mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
layout: Move text decoration propagation to stacking context tree construction (#37069)
Text decorations have a special kind of propagation. Instead of propating these during box tree construction, move propagation to stacking context tree construction. This will allow for using a very easy type of incremental layout when text decorations change. For instance, when a link changes color during hovering over it, we can skip all of box and fragment tree construction. In addition, propagation works a bit better now and color and style properly move down from their originating `Fragment`s. This introduces three new failures, because now we are drawing the text-decoration with the correct color in more places, which exposes an issue we have with text-decorations not being drawn in relation to the baseline (taking into account `vertical-align`). Testing: There are tests for these changes. Fixes #31736. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
cebb1619ae
commit
9781f1241a
23 changed files with 152 additions and 142 deletions
|
@ -150,7 +150,6 @@ impl<'a, 'dom> ModernContainerBuilder<'a, 'dom> {
|
||||||
|
|
||||||
let inline_formatting_context = inline_formatting_context_builder.finish(
|
let inline_formatting_context = inline_formatting_context_builder.finish(
|
||||||
self.context,
|
self.context,
|
||||||
self.propagated_data,
|
|
||||||
true, /* has_first_formatted_line */
|
true, /* has_first_formatted_line */
|
||||||
false, /* is_single_line_text_box */
|
false, /* is_single_line_text_box */
|
||||||
self.info.style.writing_mode.to_bidi_level(),
|
self.info.style.writing_mode.to_bidi_level(),
|
||||||
|
|
|
@ -572,6 +572,7 @@ impl Fragment {
|
||||||
section: StackingContextSection,
|
section: StackingContextSection,
|
||||||
is_hit_test_for_scrollable_overflow: bool,
|
is_hit_test_for_scrollable_overflow: bool,
|
||||||
is_collapsed_table_borders: bool,
|
is_collapsed_table_borders: bool,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
let spatial_id = builder.spatial_id(builder.current_scroll_node_id);
|
let spatial_id = builder.spatial_id(builder.current_scroll_node_id);
|
||||||
let clip_chain_id = builder.clip_chain_id(builder.current_clip_id);
|
let clip_chain_id = builder.clip_chain_id(builder.current_clip_id);
|
||||||
|
@ -683,9 +684,12 @@ impl Fragment {
|
||||||
.get_inherited_box()
|
.get_inherited_box()
|
||||||
.visibility
|
.visibility
|
||||||
{
|
{
|
||||||
Visibility::Visible => {
|
Visibility::Visible => self.build_display_list_for_text_fragment(
|
||||||
self.build_display_list_for_text_fragment(text, builder, containing_block)
|
text,
|
||||||
},
|
builder,
|
||||||
|
containing_block,
|
||||||
|
text_decorations,
|
||||||
|
),
|
||||||
Visibility::Hidden => (),
|
Visibility::Hidden => (),
|
||||||
Visibility::Collapse => (),
|
Visibility::Collapse => (),
|
||||||
}
|
}
|
||||||
|
@ -723,6 +727,7 @@ impl Fragment {
|
||||||
fragment: &TextFragment,
|
fragment: &TextFragment,
|
||||||
builder: &mut DisplayListBuilder,
|
builder: &mut DisplayListBuilder,
|
||||||
containing_block: &PhysicalRect<Au>,
|
containing_block: &PhysicalRect<Au>,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
// NB: The order of painting text components (CSS Text Decoration Module Level 3) is:
|
// NB: The order of painting text components (CSS Text Decoration Module Level 3) is:
|
||||||
// shadows, underline, overline, text, text-emphasis, and then line-through.
|
// shadows, underline, overline, text, text-emphasis, and then line-through.
|
||||||
|
@ -774,23 +779,33 @@ impl Fragment {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if fragment
|
for text_decoration in text_decorations.iter() {
|
||||||
.text_decoration_line
|
if text_decoration.line.contains(TextDecorationLine::UNDERLINE) {
|
||||||
.contains(TextDecorationLine::UNDERLINE)
|
|
||||||
{
|
|
||||||
let mut rect = rect;
|
let mut rect = rect;
|
||||||
rect.origin.y += font_metrics.ascent - font_metrics.underline_offset;
|
rect.origin.y += font_metrics.ascent - font_metrics.underline_offset;
|
||||||
rect.size.height = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
rect.size.height =
|
||||||
self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
|
Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
||||||
|
self.build_display_list_for_text_decoration(
|
||||||
|
&parent_style,
|
||||||
|
builder,
|
||||||
|
&rect,
|
||||||
|
text_decoration,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fragment
|
for text_decoration in text_decorations.iter() {
|
||||||
.text_decoration_line
|
if text_decoration.line.contains(TextDecorationLine::OVERLINE) {
|
||||||
.contains(TextDecorationLine::OVERLINE)
|
|
||||||
{
|
|
||||||
let mut rect = rect;
|
let mut rect = rect;
|
||||||
rect.size.height = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
rect.size.height =
|
||||||
self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
|
Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
||||||
|
self.build_display_list_for_text_decoration(
|
||||||
|
&parent_style,
|
||||||
|
builder,
|
||||||
|
&rect,
|
||||||
|
text_decoration,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This caret/text selection implementation currently does not account for vertical text
|
// TODO: This caret/text selection implementation currently does not account for vertical text
|
||||||
|
@ -867,14 +882,22 @@ impl Fragment {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
if fragment
|
for text_decoration in text_decorations.iter() {
|
||||||
.text_decoration_line
|
if text_decoration
|
||||||
|
.line
|
||||||
.contains(TextDecorationLine::LINE_THROUGH)
|
.contains(TextDecorationLine::LINE_THROUGH)
|
||||||
{
|
{
|
||||||
let mut rect = rect;
|
let mut rect = rect;
|
||||||
rect.origin.y += font_metrics.ascent - font_metrics.strikeout_offset;
|
rect.origin.y += font_metrics.ascent - font_metrics.strikeout_offset;
|
||||||
rect.size.height = Au::from_f32_px(font_metrics.strikeout_size.to_nearest_pixel(dppx));
|
rect.size.height =
|
||||||
self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
|
Au::from_f32_px(font_metrics.strikeout_size.to_nearest_pixel(dppx));
|
||||||
|
self.build_display_list_for_text_decoration(
|
||||||
|
&parent_style,
|
||||||
|
builder,
|
||||||
|
&rect,
|
||||||
|
text_decoration,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !shadows.0.is_empty() {
|
if !shadows.0.is_empty() {
|
||||||
|
@ -887,15 +910,11 @@ impl Fragment {
|
||||||
parent_style: &ServoArc<ComputedValues>,
|
parent_style: &ServoArc<ComputedValues>,
|
||||||
builder: &mut DisplayListBuilder,
|
builder: &mut DisplayListBuilder,
|
||||||
rect: &PhysicalRect<Au>,
|
rect: &PhysicalRect<Au>,
|
||||||
color: &AbsoluteColor,
|
text_decoration: &FragmentTextDecoration,
|
||||||
) {
|
) {
|
||||||
let rect = rect.to_webrender();
|
let rect = rect.to_webrender();
|
||||||
let wavy_line_thickness = (0.33 * rect.size().height).ceil();
|
let wavy_line_thickness = (0.33 * rect.size().height).ceil();
|
||||||
let text_decoration_color = parent_style
|
if text_decoration.style == ComputedTextDecorationStyle::MozNone {
|
||||||
.clone_text_decoration_color()
|
|
||||||
.resolve_to_absolute(color);
|
|
||||||
let text_decoration_style = parent_style.clone_text_decoration_style();
|
|
||||||
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let common_properties = builder.common_properties(rect, parent_style);
|
let common_properties = builder.common_properties(rect, parent_style);
|
||||||
|
@ -904,8 +923,8 @@ impl Fragment {
|
||||||
&rect,
|
&rect,
|
||||||
wavy_line_thickness,
|
wavy_line_thickness,
|
||||||
wr::LineOrientation::Horizontal,
|
wr::LineOrientation::Horizontal,
|
||||||
&rgba(text_decoration_color),
|
&rgba(text_decoration.color),
|
||||||
text_decoration_style.to_webrender(),
|
text_decoration.style.to_webrender(),
|
||||||
);
|
);
|
||||||
// XXX(ferjm) support text-decoration-style: double
|
// XXX(ferjm) support text-decoration-style: double
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use core::f32;
|
use core::f32;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use base::id::ScrollTreeNodeId;
|
use base::id::ScrollTreeNodeId;
|
||||||
|
@ -18,13 +19,15 @@ use euclid::default::{Point2D, Rect, Size2D};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use servo_config::opts::DebugOptions;
|
use servo_config::opts::DebugOptions;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
|
use style::color::AbsoluteColor;
|
||||||
use style::computed_values::float::T as ComputedFloat;
|
use style::computed_values::float::T as ComputedFloat;
|
||||||
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
|
use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
|
||||||
use style::computed_values::overflow_x::T as ComputedOverflow;
|
use style::computed_values::overflow_x::T as ComputedOverflow;
|
||||||
use style::computed_values::position::T as ComputedPosition;
|
use style::computed_values::position::T as ComputedPosition;
|
||||||
|
use style::computed_values::text_decoration_style::T as TextDecorationStyle;
|
||||||
use style::values::computed::angle::Angle;
|
use style::values::computed::angle::Angle;
|
||||||
use style::values::computed::basic_shape::ClipPath;
|
use style::values::computed::basic_shape::ClipPath;
|
||||||
use style::values::computed::{ClipRectOrAuto, Length};
|
use style::values::computed::{ClipRectOrAuto, Length, TextDecorationLine};
|
||||||
use style::values::generics::box_::Perspective;
|
use style::values::generics::box_::Perspective;
|
||||||
use style::values::generics::transform::{self, GenericRotate, GenericScale, GenericTranslate};
|
use style::values::generics::transform::{self, GenericRotate, GenericScale, GenericTranslate};
|
||||||
use style::values::specified::box_::DisplayOutside;
|
use style::values::specified::box_::DisplayOutside;
|
||||||
|
@ -168,12 +171,14 @@ impl StackingContextTree {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut root_stacking_context = StackingContext::create_root(root_scroll_node_id, debug);
|
let mut root_stacking_context = StackingContext::create_root(root_scroll_node_id, debug);
|
||||||
|
let text_decorations = Default::default();
|
||||||
for fragment in &fragment_tree.root_fragments {
|
for fragment in &fragment_tree.root_fragments {
|
||||||
fragment.build_stacking_context_tree(
|
fragment.build_stacking_context_tree(
|
||||||
&mut stacking_context_tree,
|
&mut stacking_context_tree,
|
||||||
&containing_block_info,
|
&containing_block_info,
|
||||||
&mut root_stacking_context,
|
&mut root_stacking_context,
|
||||||
StackingContextBuildMode::SkipHoisted,
|
StackingContextBuildMode::SkipHoisted,
|
||||||
|
&text_decorations,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
root_stacking_context.sort();
|
root_stacking_context.sort();
|
||||||
|
@ -246,6 +251,14 @@ impl StackingContextTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The text decorations for a Fragment, collecting during [`StackingContextTree`] construction.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) struct FragmentTextDecoration {
|
||||||
|
pub line: TextDecorationLine,
|
||||||
|
pub color: AbsoluteColor,
|
||||||
|
pub style: TextDecorationStyle,
|
||||||
|
}
|
||||||
|
|
||||||
/// A piece of content that directly belongs to a section of a stacking context.
|
/// A piece of content that directly belongs to a section of a stacking context.
|
||||||
///
|
///
|
||||||
/// This is generally part of a fragment, like its borders or foreground, but it
|
/// This is generally part of a fragment, like its borders or foreground, but it
|
||||||
|
@ -261,6 +274,7 @@ pub(crate) enum StackingContextContent {
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
is_hit_test_for_scrollable_overflow: bool,
|
is_hit_test_for_scrollable_overflow: bool,
|
||||||
is_collapsed_table_borders: bool,
|
is_collapsed_table_borders: bool,
|
||||||
|
text_decorations: Arc<Vec<FragmentTextDecoration>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// An index into [StackingContext::atomic_inline_stacking_containers].
|
/// An index into [StackingContext::atomic_inline_stacking_containers].
|
||||||
|
@ -292,6 +306,7 @@ impl StackingContextContent {
|
||||||
fragment,
|
fragment,
|
||||||
is_hit_test_for_scrollable_overflow,
|
is_hit_test_for_scrollable_overflow,
|
||||||
is_collapsed_table_borders,
|
is_collapsed_table_borders,
|
||||||
|
text_decorations,
|
||||||
} => {
|
} => {
|
||||||
builder.current_scroll_node_id = *scroll_node_id;
|
builder.current_scroll_node_id = *scroll_node_id;
|
||||||
builder.current_reference_frame_scroll_node_id = *reference_frame_scroll_node_id;
|
builder.current_reference_frame_scroll_node_id = *reference_frame_scroll_node_id;
|
||||||
|
@ -302,6 +317,7 @@ impl StackingContextContent {
|
||||||
*section,
|
*section,
|
||||||
*is_hit_test_for_scrollable_overflow,
|
*is_hit_test_for_scrollable_overflow,
|
||||||
*is_collapsed_table_borders,
|
*is_collapsed_table_borders,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Self::AtomicInlineStackingContainer { index } => {
|
Self::AtomicInlineStackingContainer { index } => {
|
||||||
|
@ -800,6 +816,7 @@ impl Fragment {
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
stacking_context: &mut StackingContext,
|
stacking_context: &mut StackingContext,
|
||||||
mode: StackingContextBuildMode,
|
mode: StackingContextBuildMode,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
let containing_block = containing_block_info.get_containing_block_for_fragment(self);
|
let containing_block = containing_block_info.get_containing_block_for_fragment(self);
|
||||||
let fragment_clone = self.clone();
|
let fragment_clone = self.clone();
|
||||||
|
@ -812,6 +829,11 @@ impl Fragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let text_decorations = match self {
|
||||||
|
Fragment::Float(..) => &Default::default(),
|
||||||
|
_ => text_decorations,
|
||||||
|
};
|
||||||
|
|
||||||
// If this fragment has a transform applied that makes it take up no space
|
// If this fragment has a transform applied that makes it take up no space
|
||||||
// then we don't need to create any stacking contexts for it.
|
// then we don't need to create any stacking contexts for it.
|
||||||
let has_non_invertible_transform = fragment
|
let has_non_invertible_transform = fragment
|
||||||
|
@ -828,6 +850,7 @@ impl Fragment {
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Fragment::AbsoluteOrFixedPositioned(fragment) => {
|
Fragment::AbsoluteOrFixedPositioned(fragment) => {
|
||||||
|
@ -842,6 +865,7 @@ impl Fragment {
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
StackingContextBuildMode::IncludeHoisted,
|
StackingContextBuildMode::IncludeHoisted,
|
||||||
|
&Default::default(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Fragment::Positioning(fragment) => {
|
Fragment::Positioning(fragment) => {
|
||||||
|
@ -851,6 +875,7 @@ impl Fragment {
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => {
|
Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => {
|
||||||
|
@ -867,6 +892,7 @@ impl Fragment {
|
||||||
fragment: fragment_clone,
|
fragment: fragment_clone,
|
||||||
is_hit_test_for_scrollable_overflow: false,
|
is_hit_test_for_scrollable_overflow: false,
|
||||||
is_collapsed_table_borders: false,
|
is_collapsed_table_borders: false,
|
||||||
|
text_decorations: text_decorations.clone(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -929,6 +955,7 @@ impl BoxFragment {
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
parent_stacking_context: &mut StackingContext,
|
parent_stacking_context: &mut StackingContext,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
self.build_stacking_context_tree_maybe_creating_reference_frame(
|
self.build_stacking_context_tree_maybe_creating_reference_frame(
|
||||||
fragment,
|
fragment,
|
||||||
|
@ -936,6 +963,7 @@ impl BoxFragment {
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
parent_stacking_context,
|
parent_stacking_context,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,6 +974,7 @@ impl BoxFragment {
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
parent_stacking_context: &mut StackingContext,
|
parent_stacking_context: &mut StackingContext,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
let reference_frame_data =
|
let reference_frame_data =
|
||||||
match self.reference_frame_data_if_necessary(&containing_block.rect) {
|
match self.reference_frame_data_if_necessary(&containing_block.rect) {
|
||||||
|
@ -957,6 +986,7 @@ impl BoxFragment {
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
parent_stacking_context,
|
parent_stacking_context,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -999,6 +1029,7 @@ impl BoxFragment {
|
||||||
&adjusted_containing_block,
|
&adjusted_containing_block,
|
||||||
&new_containing_block_info,
|
&new_containing_block_info,
|
||||||
parent_stacking_context,
|
parent_stacking_context,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1009,6 +1040,7 @@ impl BoxFragment {
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
parent_stacking_context: &mut StackingContext,
|
parent_stacking_context: &mut StackingContext,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
let context_type = match self.get_stacking_context_type() {
|
let context_type = match self.get_stacking_context_type() {
|
||||||
Some(context_type) => context_type,
|
Some(context_type) => context_type,
|
||||||
|
@ -1019,6 +1051,7 @@ impl BoxFragment {
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
parent_stacking_context,
|
parent_stacking_context,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
@ -1072,6 +1105,7 @@ impl BoxFragment {
|
||||||
containing_block,
|
containing_block,
|
||||||
containing_block_info,
|
containing_block_info,
|
||||||
&mut child_stacking_context,
|
&mut child_stacking_context,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut stolen_children = vec![];
|
let mut stolen_children = vec![];
|
||||||
|
@ -1097,6 +1131,7 @@ impl BoxFragment {
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
stacking_context: &mut StackingContext,
|
stacking_context: &mut StackingContext,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
let mut new_scroll_node_id = containing_block.scroll_node_id;
|
let mut new_scroll_node_id = containing_block.scroll_node_id;
|
||||||
let mut new_clip_id = containing_block.clip_id;
|
let mut new_clip_id = containing_block.clip_id;
|
||||||
|
@ -1164,6 +1199,7 @@ impl BoxFragment {
|
||||||
fragment: fragment.clone(),
|
fragment: fragment.clone(),
|
||||||
is_hit_test_for_scrollable_overflow: false,
|
is_hit_test_for_scrollable_overflow: false,
|
||||||
is_collapsed_table_borders: false,
|
is_collapsed_table_borders: false,
|
||||||
|
text_decorations: text_decorations.clone(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1198,6 +1234,7 @@ impl BoxFragment {
|
||||||
fragment: fragment.clone(),
|
fragment: fragment.clone(),
|
||||||
is_hit_test_for_scrollable_overflow: true,
|
is_hit_test_for_scrollable_overflow: true,
|
||||||
is_collapsed_table_borders: false,
|
is_collapsed_table_borders: false,
|
||||||
|
text_decorations: text_decorations.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1239,12 +1276,46 @@ impl BoxFragment {
|
||||||
containing_block_info.new_for_non_absolute_descendants(&for_non_absolute_descendants)
|
containing_block_info.new_for_non_absolute_descendants(&for_non_absolute_descendants)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Text decorations are not propagated to atomic inline-level descendants.
|
||||||
|
// From https://drafts.csswg.org/css2/#lining-striking-props:
|
||||||
|
// > Note that text decorations are not propagated to floating and absolutely
|
||||||
|
// > positioned descendants, nor to the contents of atomic inline-level descendants
|
||||||
|
// > such as inline blocks and inline tables.
|
||||||
|
let text_decorations = match self.is_atomic_inline_level() ||
|
||||||
|
self.base
|
||||||
|
.flags
|
||||||
|
.contains(FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER)
|
||||||
|
{
|
||||||
|
true => &Default::default(),
|
||||||
|
false => text_decorations,
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_text_decoration;
|
||||||
|
let text_decorations = match self.style.clone_text_decoration_line() {
|
||||||
|
TextDecorationLine::NONE => text_decorations,
|
||||||
|
line => {
|
||||||
|
let mut new_vector = (**text_decorations).clone();
|
||||||
|
let color = &self.style.get_inherited_text().color;
|
||||||
|
new_vector.push(FragmentTextDecoration {
|
||||||
|
line,
|
||||||
|
color: self
|
||||||
|
.style
|
||||||
|
.clone_text_decoration_color()
|
||||||
|
.resolve_to_absolute(color),
|
||||||
|
style: self.style.clone_text_decoration_style(),
|
||||||
|
});
|
||||||
|
new_text_decoration = Arc::new(new_vector);
|
||||||
|
&new_text_decoration
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
child.build_stacking_context_tree(
|
child.build_stacking_context_tree(
|
||||||
stacking_context_tree,
|
stacking_context_tree,
|
||||||
&new_containing_block_info,
|
&new_containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
StackingContextBuildMode::SkipHoisted,
|
StackingContextBuildMode::SkipHoisted,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1263,6 +1334,7 @@ impl BoxFragment {
|
||||||
fragment: fragment.clone(),
|
fragment: fragment.clone(),
|
||||||
is_hit_test_for_scrollable_overflow: false,
|
is_hit_test_for_scrollable_overflow: false,
|
||||||
is_collapsed_table_borders: true,
|
is_collapsed_table_borders: true,
|
||||||
|
text_decorations: text_decorations.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1646,6 +1718,7 @@ impl PositioningFragment {
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_info: &ContainingBlockInfo,
|
containing_block_info: &ContainingBlockInfo,
|
||||||
stacking_context: &mut StackingContext,
|
stacking_context: &mut StackingContext,
|
||||||
|
text_decorations: &Arc<Vec<FragmentTextDecoration>>,
|
||||||
) {
|
) {
|
||||||
let rect = self
|
let rect = self
|
||||||
.rect
|
.rect
|
||||||
|
@ -1660,6 +1733,7 @@ impl PositioningFragment {
|
||||||
&new_containing_block_info,
|
&new_containing_block_info,
|
||||||
stacking_context,
|
stacking_context,
|
||||||
StackingContextBuildMode::SkipHoisted,
|
StackingContextBuildMode::SkipHoisted,
|
||||||
|
text_decorations,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,8 +105,7 @@ impl FlexContainer {
|
||||||
contents: NonReplacedContents,
|
contents: NonReplacedContents,
|
||||||
propagated_data: PropagatedBoxTreeData,
|
propagated_data: PropagatedBoxTreeData,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut builder =
|
let mut builder = ModernContainerBuilder::new(context, info, propagated_data);
|
||||||
ModernContainerBuilder::new(context, info, propagated_data.union(&info.style));
|
|
||||||
contents.traverse(context, info, &mut builder);
|
contents.traverse(context, info, &mut builder);
|
||||||
let items = builder.finish();
|
let items = builder.finish();
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
context,
|
context,
|
||||||
info,
|
info,
|
||||||
block_level_boxes: Vec::new(),
|
block_level_boxes: Vec::new(),
|
||||||
propagated_data: propagated_data.union(&info.style),
|
propagated_data,
|
||||||
have_already_seen_first_line_for_text_indent: false,
|
have_already_seen_first_line_for_text_indent: false,
|
||||||
anonymous_box_info: None,
|
anonymous_box_info: None,
|
||||||
anonymous_table_content: Vec::new(),
|
anonymous_table_content: Vec::new(),
|
||||||
|
@ -228,7 +228,6 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
fn finish_ongoing_inline_formatting_context(&mut self) -> Option<InlineFormattingContext> {
|
fn finish_ongoing_inline_formatting_context(&mut self) -> Option<InlineFormattingContext> {
|
||||||
self.inline_formatting_context_builder.take()?.finish(
|
self.inline_formatting_context_builder.take()?.finish(
|
||||||
self.context,
|
self.context,
|
||||||
self.propagated_data,
|
|
||||||
!self.have_already_seen_first_line_for_text_indent,
|
!self.have_already_seen_first_line_for_text_indent,
|
||||||
self.info.is_single_line_text_input(),
|
self.info.is_single_line_text_input(),
|
||||||
self.info.style.writing_mode.to_bidi_level(),
|
self.info.style.writing_mode.to_bidi_level(),
|
||||||
|
@ -280,16 +279,6 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
// creation of an inline table. It requires the parent to be an inline box.
|
// creation of an inline table. It requires the parent to be an inline box.
|
||||||
let inline_table = self.currently_processing_inline_box();
|
let inline_table = self.currently_processing_inline_box();
|
||||||
|
|
||||||
// Text decorations are not propagated to atomic inline-level descendants.
|
|
||||||
// From https://drafts.csswg.org/css2/#lining-striking-props:
|
|
||||||
// > Note that text decorations are not propagated to floating and absolutely
|
|
||||||
// > positioned descendants, nor to the contents of atomic inline-level descendants
|
|
||||||
// > such as inline blocks and inline tables.
|
|
||||||
let propagated_data = match inline_table {
|
|
||||||
true => self.propagated_data.without_text_decorations(),
|
|
||||||
false => self.propagated_data,
|
|
||||||
};
|
|
||||||
|
|
||||||
let contents: Vec<AnonymousTableContent<'dom>> =
|
let contents: Vec<AnonymousTableContent<'dom>> =
|
||||||
self.anonymous_table_content.drain(..).collect();
|
self.anonymous_table_content.drain(..).collect();
|
||||||
let last_text = match contents.last() {
|
let last_text = match contents.last() {
|
||||||
|
@ -298,7 +287,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let (table_info, ifc) =
|
let (table_info, ifc) =
|
||||||
Table::construct_anonymous(self.context, self.info, contents, propagated_data);
|
Table::construct_anonymous(self.context, self.info, contents, self.propagated_data);
|
||||||
|
|
||||||
if inline_table {
|
if inline_table {
|
||||||
self.ensure_inline_formatting_context_builder()
|
self.ensure_inline_formatting_context_builder()
|
||||||
|
@ -315,7 +304,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
info: table_info,
|
info: table_info,
|
||||||
box_slot: BoxSlot::dummy(),
|
box_slot: BoxSlot::dummy(),
|
||||||
kind: BlockLevelCreator::AnonymousTable { table_block },
|
kind: BlockLevelCreator::AnonymousTable { table_block },
|
||||||
propagated_data,
|
propagated_data: self.propagated_data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +453,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
contents,
|
contents,
|
||||||
list_item_style,
|
list_item_style,
|
||||||
},
|
},
|
||||||
propagated_data: self.propagated_data.without_text_decorations(),
|
propagated_data: self.propagated_data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,15 +469,14 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
else {
|
else {
|
||||||
// If this inline element is an atomic, handle it and return.
|
// If this inline element is an atomic, handle it and return.
|
||||||
let context = self.context;
|
let context = self.context;
|
||||||
let propagaged_data = self.propagated_data.without_text_decorations();
|
let propagated_data = self.propagated_data;
|
||||||
let atomic = self.ensure_inline_formatting_context_builder().push_atomic(
|
let atomic = self.ensure_inline_formatting_context_builder().push_atomic(
|
||||||
IndependentFormattingContext::construct(
|
IndependentFormattingContext::construct(
|
||||||
context,
|
context,
|
||||||
info,
|
info,
|
||||||
display_inside,
|
display_inside,
|
||||||
contents,
|
contents,
|
||||||
// Text decorations are not propagated to atomic inline-level descendants.
|
propagated_data,
|
||||||
propagaged_data,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
box_slot.set(LayoutBox::InlineLevel(vec![atomic]));
|
box_slot.set(LayoutBox::InlineLevel(vec![atomic]));
|
||||||
|
@ -550,7 +538,6 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
.and_then(|builder| {
|
.and_then(|builder| {
|
||||||
builder.split_around_block_and_finish(
|
builder.split_around_block_and_finish(
|
||||||
self.context,
|
self.context,
|
||||||
self.propagated_data,
|
|
||||||
!self.have_already_seen_first_line_for_text_indent,
|
!self.have_already_seen_first_line_for_text_indent,
|
||||||
self.info.style.writing_mode.to_bidi_level(),
|
self.info.style.writing_mode.to_bidi_level(),
|
||||||
)
|
)
|
||||||
|
@ -631,7 +618,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
info: info.clone(),
|
info: info.clone(),
|
||||||
box_slot,
|
box_slot,
|
||||||
kind,
|
kind,
|
||||||
propagated_data: self.propagated_data.without_text_decorations(),
|
propagated_data: self.propagated_data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +651,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
info: info.clone(),
|
info: info.clone(),
|
||||||
box_slot,
|
box_slot,
|
||||||
kind,
|
kind,
|
||||||
propagated_data: self.propagated_data.without_text_decorations(),
|
propagated_data: self.propagated_data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,7 +741,7 @@ impl BlockLevelJob<'_> {
|
||||||
context,
|
context,
|
||||||
info,
|
info,
|
||||||
contents,
|
contents,
|
||||||
self.propagated_data.without_text_decorations(),
|
self.propagated_data,
|
||||||
false, /* is_list_item */
|
false, /* is_list_item */
|
||||||
);
|
);
|
||||||
ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker {
|
ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker {
|
||||||
|
|
|
@ -897,8 +897,7 @@ impl FloatBox {
|
||||||
info,
|
info,
|
||||||
display_inside,
|
display_inside,
|
||||||
contents,
|
contents,
|
||||||
// Text decorations are not propagated to any out-of-flow descendants
|
propagated_data,
|
||||||
propagated_data.without_text_decorations(),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ use super::{
|
||||||
InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext, InlineItem,
|
InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext, InlineItem,
|
||||||
SharedInlineStyles,
|
SharedInlineStyles,
|
||||||
};
|
};
|
||||||
use crate::PropagatedBoxTreeData;
|
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::dom_traversal::NodeAndStyleInfo;
|
use crate::dom_traversal::NodeAndStyleInfo;
|
||||||
|
@ -344,7 +343,6 @@ impl InlineFormattingContextBuilder {
|
||||||
pub(crate) fn split_around_block_and_finish(
|
pub(crate) fn split_around_block_and_finish(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
propagated_data: PropagatedBoxTreeData,
|
|
||||||
has_first_formatted_line: bool,
|
has_first_formatted_line: bool,
|
||||||
default_bidi_level: Level,
|
default_bidi_level: Level,
|
||||||
) -> Option<InlineFormattingContext> {
|
) -> Option<InlineFormattingContext> {
|
||||||
|
@ -386,7 +384,6 @@ impl InlineFormattingContextBuilder {
|
||||||
|
|
||||||
inline_builder_from_before_split.finish(
|
inline_builder_from_before_split.finish(
|
||||||
layout_context,
|
layout_context,
|
||||||
propagated_data,
|
|
||||||
has_first_formatted_line,
|
has_first_formatted_line,
|
||||||
/* is_single_line_text_input = */ false,
|
/* is_single_line_text_input = */ false,
|
||||||
default_bidi_level,
|
default_bidi_level,
|
||||||
|
@ -397,7 +394,6 @@ impl InlineFormattingContextBuilder {
|
||||||
pub(crate) fn finish(
|
pub(crate) fn finish(
|
||||||
self,
|
self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
propagated_data: PropagatedBoxTreeData,
|
|
||||||
has_first_formatted_line: bool,
|
has_first_formatted_line: bool,
|
||||||
is_single_line_text_input: bool,
|
is_single_line_text_input: bool,
|
||||||
default_bidi_level: Level,
|
default_bidi_level: Level,
|
||||||
|
@ -410,7 +406,6 @@ impl InlineFormattingContextBuilder {
|
||||||
Some(InlineFormattingContext::new_with_builder(
|
Some(InlineFormattingContext::new_with_builder(
|
||||||
self,
|
self,
|
||||||
layout_context,
|
layout_context,
|
||||||
propagated_data,
|
|
||||||
has_first_formatted_line,
|
has_first_formatted_line,
|
||||||
is_single_line_text_input,
|
is_single_line_text_input,
|
||||||
default_bidi_level,
|
default_bidi_level,
|
||||||
|
|
|
@ -256,13 +256,7 @@ impl InlineBoxContainerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
base: InlineContainerState::new(
|
base: InlineContainerState::new(style, flags, Some(parent_container), font_metrics),
|
||||||
style,
|
|
||||||
flags,
|
|
||||||
Some(parent_container),
|
|
||||||
parent_container.text_decoration_line,
|
|
||||||
font_metrics,
|
|
||||||
),
|
|
||||||
identifier: inline_box.identifier,
|
identifier: inline_box.identifier,
|
||||||
base_fragment_info: inline_box.base.base_fragment_info,
|
base_fragment_info: inline_box.base.base_fragment_info,
|
||||||
pbm,
|
pbm,
|
||||||
|
|
|
@ -15,7 +15,6 @@ use style::values::generics::box_::{GenericVerticalAlign, VerticalAlignKeyword};
|
||||||
use style::values::generics::font::LineHeight;
|
use style::values::generics::font::LineHeight;
|
||||||
use style::values::specified::align::AlignFlags;
|
use style::values::specified::align::AlignFlags;
|
||||||
use style::values::specified::box_::DisplayOutside;
|
use style::values::specified::box_::DisplayOutside;
|
||||||
use style::values::specified::text::TextDecorationLine;
|
|
||||||
use unicode_bidi::{BidiInfo, Level};
|
use unicode_bidi::{BidiInfo, Level};
|
||||||
use webrender_api::FontInstanceKey;
|
use webrender_api::FontInstanceKey;
|
||||||
|
|
||||||
|
@ -572,7 +571,6 @@ impl LineItemLayout<'_, '_> {
|
||||||
font_metrics: text_item.font_metrics,
|
font_metrics: text_item.font_metrics,
|
||||||
font_key: text_item.font_key,
|
font_key: text_item.font_key,
|
||||||
glyphs: text_item.text,
|
glyphs: text_item.text,
|
||||||
text_decoration_line: text_item.text_decoration_line,
|
|
||||||
justification_adjustment: self.justification_adjustment,
|
justification_adjustment: self.justification_adjustment,
|
||||||
selection_range: text_item.selection_range,
|
selection_range: text_item.selection_range,
|
||||||
})),
|
})),
|
||||||
|
@ -765,7 +763,6 @@ pub(super) struct TextRunLineItem {
|
||||||
pub text: Vec<std::sync::Arc<GlyphStore>>,
|
pub text: Vec<std::sync::Arc<GlyphStore>>,
|
||||||
pub font_metrics: FontMetrics,
|
pub font_metrics: FontMetrics,
|
||||||
pub font_key: FontInstanceKey,
|
pub font_key: FontInstanceKey,
|
||||||
pub text_decoration_line: TextDecorationLine,
|
|
||||||
/// The BiDi level of this [`TextRunLineItem`] to enable reordering.
|
/// The BiDi level of this [`TextRunLineItem`] to enable reordering.
|
||||||
pub bidi_level: Level,
|
pub bidi_level: Level,
|
||||||
pub selection_range: Option<Range<ByteIndex>>,
|
pub selection_range: Option<Range<ByteIndex>>,
|
||||||
|
|
|
@ -103,7 +103,7 @@ use style::properties::style_structs::InheritedText;
|
||||||
use style::values::generics::box_::VerticalAlignKeyword;
|
use style::values::generics::box_::VerticalAlignKeyword;
|
||||||
use style::values::generics::font::LineHeight;
|
use style::values::generics::font::LineHeight;
|
||||||
use style::values::specified::box_::BaselineSource;
|
use style::values::specified::box_::BaselineSource;
|
||||||
use style::values::specified::text::{TextAlignKeyword, TextDecorationLine};
|
use style::values::specified::text::TextAlignKeyword;
|
||||||
use style::values::specified::{TextAlignLast, TextJustify};
|
use style::values::specified::{TextAlignLast, TextJustify};
|
||||||
use text_run::{
|
use text_run::{
|
||||||
TextRun, XI_LINE_BREAKING_CLASS_GL, XI_LINE_BREAKING_CLASS_WJ, XI_LINE_BREAKING_CLASS_ZWJ,
|
TextRun, XI_LINE_BREAKING_CLASS_GL, XI_LINE_BREAKING_CLASS_WJ, XI_LINE_BREAKING_CLASS_ZWJ,
|
||||||
|
@ -134,7 +134,7 @@ use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||||
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
||||||
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
|
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
|
||||||
use crate::{ConstraintSpace, ContainingBlock, PropagatedBoxTreeData, SharedStyle};
|
use crate::{ConstraintSpace, ContainingBlock, SharedStyle};
|
||||||
|
|
||||||
// From gfxFontConstants.h in Firefox.
|
// From gfxFontConstants.h in Firefox.
|
||||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||||
|
@ -163,8 +163,6 @@ pub(crate) struct InlineFormattingContext {
|
||||||
/// share styles with all [`TextRun`] children.
|
/// share styles with all [`TextRun`] children.
|
||||||
pub(super) shared_inline_styles: SharedInlineStyles,
|
pub(super) shared_inline_styles: SharedInlineStyles,
|
||||||
|
|
||||||
pub(super) text_decoration_line: TextDecorationLine,
|
|
||||||
|
|
||||||
/// Whether this IFC contains the 1st formatted line of an element:
|
/// Whether this IFC contains the 1st formatted line of an element:
|
||||||
/// <https://www.w3.org/TR/css-pseudo-4/#first-formatted-line>.
|
/// <https://www.w3.org/TR/css-pseudo-4/#first-formatted-line>.
|
||||||
pub(super) has_first_formatted_line: bool,
|
pub(super) has_first_formatted_line: bool,
|
||||||
|
@ -628,12 +626,6 @@ pub(super) struct InlineContainerState {
|
||||||
/// this inline box on the current line OR any previous line.
|
/// this inline box on the current line OR any previous line.
|
||||||
has_content: RefCell<bool>,
|
has_content: RefCell<bool>,
|
||||||
|
|
||||||
/// 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,
|
|
||||||
|
|
||||||
/// The block size contribution of this container's default font ie the size of the
|
/// The block size contribution of this container's default font ie the size of the
|
||||||
/// "strut." Whether this is integrated into the [`Self::nested_strut_block_sizes`]
|
/// "strut." Whether this is integrated into the [`Self::nested_strut_block_sizes`]
|
||||||
/// depends on the line-height quirk described in
|
/// depends on the line-height quirk described in
|
||||||
|
@ -1461,7 +1453,6 @@ impl InlineFormattingContextLayout<'_> {
|
||||||
inline_styles: text_run.inline_styles.clone(),
|
inline_styles: text_run.inline_styles.clone(),
|
||||||
font_metrics,
|
font_metrics,
|
||||||
font_key: ifc_font_info.key,
|
font_key: ifc_font_info.key,
|
||||||
text_decoration_line: self.current_inline_container_state().text_decoration_line,
|
|
||||||
bidi_level,
|
bidi_level,
|
||||||
selection_range,
|
selection_range,
|
||||||
},
|
},
|
||||||
|
@ -1655,7 +1646,6 @@ impl InlineFormattingContext {
|
||||||
pub(super) fn new_with_builder(
|
pub(super) fn new_with_builder(
|
||||||
builder: InlineFormattingContextBuilder,
|
builder: InlineFormattingContextBuilder,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
propagated_data: PropagatedBoxTreeData,
|
|
||||||
has_first_formatted_line: bool,
|
has_first_formatted_line: bool,
|
||||||
is_single_line_text_input: bool,
|
is_single_line_text_input: bool,
|
||||||
starting_bidi_level: Level,
|
starting_bidi_level: Level,
|
||||||
|
@ -1711,7 +1701,6 @@ impl InlineFormattingContext {
|
||||||
.last()
|
.last()
|
||||||
.expect("Should have at least one SharedInlineStyle for the root of an IFC")
|
.expect("Should have at least one SharedInlineStyle for the root of an IFC")
|
||||||
.clone(),
|
.clone(),
|
||||||
text_decoration_line: propagated_data.text_decoration,
|
|
||||||
has_first_formatted_line,
|
has_first_formatted_line,
|
||||||
contains_floats: builder.contains_floats,
|
contains_floats: builder.contains_floats,
|
||||||
is_single_line_text_input,
|
is_single_line_text_input,
|
||||||
|
@ -1781,7 +1770,6 @@ impl InlineFormattingContext {
|
||||||
style.to_arc(),
|
style.to_arc(),
|
||||||
inline_container_state_flags,
|
inline_container_state_flags,
|
||||||
None, /* parent_container */
|
None, /* parent_container */
|
||||||
self.text_decoration_line,
|
|
||||||
default_font_metrics.as_ref(),
|
default_font_metrics.as_ref(),
|
||||||
),
|
),
|
||||||
inline_box_state_stack: Vec::new(),
|
inline_box_state_stack: Vec::new(),
|
||||||
|
@ -1879,10 +1867,8 @@ impl InlineContainerState {
|
||||||
style: Arc<ComputedValues>,
|
style: Arc<ComputedValues>,
|
||||||
flags: InlineContainerStateFlags,
|
flags: InlineContainerStateFlags,
|
||||||
parent_container: Option<&InlineContainerState>,
|
parent_container: Option<&InlineContainerState>,
|
||||||
parent_text_decoration_line: TextDecorationLine,
|
|
||||||
font_metrics: Option<&FontMetrics>,
|
font_metrics: Option<&FontMetrics>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let text_decoration_line = parent_text_decoration_line | style.clone_text_decoration_line();
|
|
||||||
let font_metrics = font_metrics.cloned().unwrap_or_else(FontMetrics::empty);
|
let font_metrics = font_metrics.cloned().unwrap_or_else(FontMetrics::empty);
|
||||||
let line_height = line_height(
|
let line_height = line_height(
|
||||||
&style,
|
&style,
|
||||||
|
@ -1919,7 +1905,6 @@ impl InlineContainerState {
|
||||||
style,
|
style,
|
||||||
flags,
|
flags,
|
||||||
has_content: RefCell::new(false),
|
has_content: RefCell::new(false),
|
||||||
text_decoration_line,
|
|
||||||
nested_strut_block_sizes: nested_block_sizes,
|
nested_strut_block_sizes: nested_block_sizes,
|
||||||
strut_block_sizes,
|
strut_block_sizes,
|
||||||
baseline_offset,
|
baseline_offset,
|
||||||
|
|
|
@ -314,7 +314,7 @@ fn construct_for_root_element(
|
||||||
let contents = ReplacedContents::for_element(root_element, context)
|
let contents = ReplacedContents::for_element(root_element, context)
|
||||||
.map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced);
|
.map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced);
|
||||||
|
|
||||||
let propagated_data = PropagatedBoxTreeData::default().union(&info.style);
|
let propagated_data = PropagatedBoxTreeData::default();
|
||||||
let root_box = if box_style.position.is_absolutely_positioned() {
|
let root_box = if box_style.position.is_absolutely_positioned() {
|
||||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(ArcRefCell::new(
|
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(ArcRefCell::new(
|
||||||
AbsolutelyPositionedBox::construct(context, &info, display_inside, contents),
|
AbsolutelyPositionedBox::construct(context, &info, display_inside, contents),
|
||||||
|
|
|
@ -14,7 +14,6 @@ use range::Range as ServoRange;
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::specified::text::TextDecorationLine;
|
|
||||||
use webrender_api::{FontInstanceKey, ImageKey};
|
use webrender_api::{FontInstanceKey, ImageKey};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -72,9 +71,6 @@ pub(crate) struct TextFragment {
|
||||||
#[conditional_malloc_size_of]
|
#[conditional_malloc_size_of]
|
||||||
pub glyphs: Vec<Arc<GlyphStore>>,
|
pub glyphs: Vec<Arc<GlyphStore>>,
|
||||||
|
|
||||||
/// A flag that represents the _used_ value of the text-decoration property.
|
|
||||||
pub text_decoration_line: TextDecorationLine,
|
|
||||||
|
|
||||||
/// Extra space to add for each justification opportunity.
|
/// Extra space to add for each justification opportunity.
|
||||||
pub justification_adjustment: Au,
|
pub justification_adjustment: Au,
|
||||||
pub selection_range: Option<ServoRange<ByteIndex>>,
|
pub selection_range: Option<ServoRange<ByteIndex>>,
|
||||||
|
|
|
@ -41,7 +41,6 @@ use malloc_size_of_derive::MallocSizeOf;
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use style::logical_geometry::WritingMode;
|
use style::logical_geometry::WritingMode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::TextDecorationLine;
|
|
||||||
|
|
||||||
use crate::geom::{LogicalVec2, SizeConstraint};
|
use crate::geom::{LogicalVec2, SizeConstraint};
|
||||||
use crate::style_ext::AspectRatio;
|
use crate::style_ext::AspectRatio;
|
||||||
|
@ -163,39 +162,20 @@ impl<'a> From<&'_ DefiniteContainingBlock<'a>> for ContainingBlock<'a> {
|
||||||
/// propoagation, but only during `BoxTree` construction.
|
/// propoagation, but only during `BoxTree` construction.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct PropagatedBoxTreeData {
|
struct PropagatedBoxTreeData {
|
||||||
text_decoration: TextDecorationLine,
|
|
||||||
allow_percentage_column_in_tables: bool,
|
allow_percentage_column_in_tables: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PropagatedBoxTreeData {
|
impl Default for PropagatedBoxTreeData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
text_decoration: Default::default(),
|
|
||||||
allow_percentage_column_in_tables: true,
|
allow_percentage_column_in_tables: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropagatedBoxTreeData {
|
impl PropagatedBoxTreeData {
|
||||||
pub(crate) fn union(&self, style: &ComputedValues) -> Self {
|
|
||||||
Self {
|
|
||||||
// FIXME(#31736): This is only taking into account the line style and not the decoration
|
|
||||||
// color. This should collect information about both so that they can be rendered properly.
|
|
||||||
text_decoration: self.text_decoration | style.clone_text_decoration_line(),
|
|
||||||
allow_percentage_column_in_tables: self.allow_percentage_column_in_tables,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn without_text_decorations(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
text_decoration: TextDecorationLine::NONE,
|
|
||||||
allow_percentage_column_in_tables: self.allow_percentage_column_in_tables,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disallowing_percentage_table_columns(&self) -> PropagatedBoxTreeData {
|
fn disallowing_percentage_table_columns(&self) -> PropagatedBoxTreeData {
|
||||||
Self {
|
Self {
|
||||||
text_decoration: self.text_decoration,
|
|
||||||
allow_percentage_column_in_tables: false,
|
allow_percentage_column_in_tables: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,12 +81,7 @@ impl Table {
|
||||||
contents: NonReplacedContents,
|
contents: NonReplacedContents,
|
||||||
propagated_data: PropagatedBoxTreeData,
|
propagated_data: PropagatedBoxTreeData,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut traversal = TableBuilderTraversal::new(
|
let mut traversal = TableBuilderTraversal::new(context, info, grid_style, propagated_data);
|
||||||
context,
|
|
||||||
info,
|
|
||||||
grid_style,
|
|
||||||
propagated_data.union(&info.style),
|
|
||||||
);
|
|
||||||
contents.traverse(context, info, &mut traversal);
|
contents.traverse(context, info, &mut traversal);
|
||||||
traversal.finish()
|
traversal.finish()
|
||||||
}
|
}
|
||||||
|
@ -771,9 +766,6 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
|
||||||
});
|
});
|
||||||
self.builder.table.row_groups.push(row_group.clone());
|
self.builder.table.row_groups.push(row_group.clone());
|
||||||
|
|
||||||
let previous_propagated_data = self.current_propagated_data;
|
|
||||||
self.current_propagated_data = self.current_propagated_data.union(&info.style);
|
|
||||||
|
|
||||||
let new_row_group_index = self.builder.table.row_groups.len() - 1;
|
let new_row_group_index = self.builder.table.row_groups.len() - 1;
|
||||||
self.current_row_group_index = Some(new_row_group_index);
|
self.current_row_group_index = Some(new_row_group_index);
|
||||||
|
|
||||||
|
@ -785,7 +777,6 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
|
||||||
self.finish_anonymous_row_if_needed();
|
self.finish_anonymous_row_if_needed();
|
||||||
|
|
||||||
self.current_row_group_index = None;
|
self.current_row_group_index = None;
|
||||||
self.current_propagated_data = previous_propagated_data;
|
|
||||||
self.builder.incoming_rowspans.clear();
|
self.builder.incoming_rowspans.clear();
|
||||||
|
|
||||||
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
|
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
|
||||||
|
@ -936,7 +927,7 @@ impl<'style, 'builder, 'dom, 'a> TableRowBuilder<'style, 'builder, 'dom, 'a> {
|
||||||
table_traversal,
|
table_traversal,
|
||||||
info,
|
info,
|
||||||
current_anonymous_cell_content: Vec::new(),
|
current_anonymous_cell_content: Vec::new(),
|
||||||
propagated_data: propagated_data.union(&info.style),
|
propagated_data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ impl TaffyContainer {
|
||||||
contents: NonReplacedContents,
|
contents: NonReplacedContents,
|
||||||
propagated_data: PropagatedBoxTreeData,
|
propagated_data: PropagatedBoxTreeData,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut builder =
|
let mut builder = ModernContainerBuilder::new(context, info, propagated_data);
|
||||||
ModernContainerBuilder::new(context, info, propagated_data.union(&info.style));
|
|
||||||
contents.traverse(context, info, &mut builder);
|
contents.traverse(context, info, &mut builder);
|
||||||
let items = builder.finish();
|
let items = builder.finish();
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[content-070.xht]
|
|
||||||
expected: FAIL
|
|
2
tests/wpt/meta/css/CSS2/text/text-decoration-va-length-001.xht.ini
vendored
Normal file
2
tests/wpt/meta/css/CSS2/text/text-decoration-va-length-001.xht.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[text-decoration-va-length-001.xht]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/css/CSS2/text/text-decoration-va-length-002.xht.ini
vendored
Normal file
2
tests/wpt/meta/css/CSS2/text/text-decoration-va-length-002.xht.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[text-decoration-va-length-002.xht]
|
||||||
|
expected: FAIL
|
2
tests/wpt/meta/css/css-text-decor/text-decoration-decorating-box-001.html.ini
vendored
Normal file
2
tests/wpt/meta/css/css-text-decor/text-decoration-decorating-box-001.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[text-decoration-decorating-box-001.html]
|
||||||
|
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
||||||
[text-decoration-dotted-002.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[text-decoration-propagation-display-contents.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[text-decoration-style-multiple.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[decorations-multiple-zorder.html]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue