mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
layout: Share styles to inline box children via SharedInlineStyles
(#36896)
`TextRun`s use their parent style to render. Previously, these styles were cloned and stored directly in the box tree `TextRun` and resulting `TextFragment`s. This presents a problem for incremental layout. Wrapping the style in another layer of shared ownership and mutability will allow updating all `TextFragment`s during repaint-only incremental layout by simply updating the box tree styles of the original text parents. This adds a new set of borrows when accessing text styles, but also makes it so that during box tree block construction `InlineFormattingContext`s are created lazily and now `InlineFormattingContextBuilder::finish` consumes the builder, making the API make a bit more sense. This should also improve performance of box tree block construction slightly. Testing: This should not change observable behavior and thus is covered by existing WPT tests. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
db83601b62
commit
a0dd2c1beb
24 changed files with 369 additions and 187 deletions
|
@ -142,7 +142,7 @@ impl<'a, 'dom> ModernContainerBuilder<'a, 'dom> {
|
||||||
.filter_map(|job| match job {
|
.filter_map(|job| match job {
|
||||||
ModernContainerJob::TextRuns(runs) => {
|
ModernContainerJob::TextRuns(runs) => {
|
||||||
let mut inline_formatting_context_builder =
|
let mut inline_formatting_context_builder =
|
||||||
InlineFormattingContextBuilder::new();
|
InlineFormattingContextBuilder::new(self.info);
|
||||||
for flex_text_run in runs.into_iter() {
|
for flex_text_run in runs.into_iter() {
|
||||||
inline_formatting_context_builder
|
inline_formatting_context_builder
|
||||||
.push_text(flex_text_run.text, &flex_text_run.info);
|
.push_text(flex_text_run.text, &flex_text_run.info);
|
||||||
|
|
|
@ -14,6 +14,7 @@ use euclid::{Point2D, SideOffsets2D, Size2D, UnknownUnit};
|
||||||
use fonts::GlyphStore;
|
use fonts::GlyphStore;
|
||||||
use gradient::WebRenderGradient;
|
use gradient::WebRenderGradient;
|
||||||
use range::Range as ServoRange;
|
use range::Range as ServoRange;
|
||||||
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_geometry::MaxRect;
|
use servo_geometry::MaxRect;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use style::color::{AbsoluteColor, ColorSpace};
|
use style::color::{AbsoluteColor, ColorSpace};
|
||||||
|
@ -544,7 +545,13 @@ impl Fragment {
|
||||||
},
|
},
|
||||||
Fragment::Text(text) => {
|
Fragment::Text(text) => {
|
||||||
let text = &*text.borrow();
|
let text = &*text.borrow();
|
||||||
match text.parent_style.get_inherited_box().visibility {
|
match text
|
||||||
|
.inline_styles
|
||||||
|
.style
|
||||||
|
.borrow()
|
||||||
|
.get_inherited_box()
|
||||||
|
.visibility
|
||||||
|
{
|
||||||
Visibility::Visible => {
|
Visibility::Visible => {
|
||||||
self.build_display_list_for_text_fragment(text, builder, containing_block)
|
self.build_display_list_for_text_fragment(text, builder, containing_block)
|
||||||
},
|
},
|
||||||
|
@ -604,22 +611,23 @@ impl Fragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let parent_style = fragment.inline_styles.style.borrow();
|
||||||
self.maybe_push_hit_test_for_style_and_tag(
|
self.maybe_push_hit_test_for_style_and_tag(
|
||||||
builder,
|
builder,
|
||||||
&fragment.parent_style,
|
&parent_style,
|
||||||
fragment.base.tag,
|
fragment.base.tag,
|
||||||
rect,
|
rect,
|
||||||
Cursor::Text,
|
Cursor::Text,
|
||||||
);
|
);
|
||||||
|
|
||||||
let color = fragment.parent_style.clone_color();
|
let color = parent_style.clone_color();
|
||||||
let font_metrics = &fragment.font_metrics;
|
let font_metrics = &fragment.font_metrics;
|
||||||
let dppx = builder.context.style_context.device_pixel_ratio().get();
|
let dppx = builder.context.style_context.device_pixel_ratio().get();
|
||||||
let common = builder.common_properties(rect.to_webrender(), &fragment.parent_style);
|
let common = builder.common_properties(rect.to_webrender(), &parent_style);
|
||||||
|
|
||||||
// Shadows. According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front to
|
// Shadows. According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front to
|
||||||
// back).
|
// back).
|
||||||
let shadows = &fragment.parent_style.get_inherited_text().text_shadow;
|
let shadows = &parent_style.get_inherited_text().text_shadow;
|
||||||
for shadow in shadows.0.iter().rev() {
|
for shadow in shadows.0.iter().rev() {
|
||||||
builder.wr().push_shadow(
|
builder.wr().push_shadow(
|
||||||
&wr::SpaceAndClipInfo {
|
&wr::SpaceAndClipInfo {
|
||||||
|
@ -642,7 +650,7 @@ impl Fragment {
|
||||||
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 = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
||||||
self.build_display_list_for_text_decoration(fragment, builder, &rect, &color);
|
self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if fragment
|
if fragment
|
||||||
|
@ -651,7 +659,7 @@ impl Fragment {
|
||||||
{
|
{
|
||||||
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 = Au::from_f32_px(font_metrics.underline_size.to_nearest_pixel(dppx));
|
||||||
self.build_display_list_for_text_decoration(fragment, builder, &rect, &color);
|
self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -678,12 +686,13 @@ impl Fragment {
|
||||||
Point2D::new(end.x.to_f32_px(), containing_block.max_y().to_f32_px()),
|
Point2D::new(end.x.to_f32_px(), containing_block.max_y().to_f32_px()),
|
||||||
);
|
);
|
||||||
if let Some(selection_color) = fragment
|
if let Some(selection_color) = fragment
|
||||||
.selected_style
|
.inline_styles
|
||||||
|
.selected
|
||||||
|
.borrow()
|
||||||
.clone_background_color()
|
.clone_background_color()
|
||||||
.as_absolute()
|
.as_absolute()
|
||||||
{
|
{
|
||||||
let selection_common =
|
let selection_common = builder.common_properties(selection_rect, &parent_style);
|
||||||
builder.common_properties(selection_rect, &fragment.parent_style);
|
|
||||||
builder.wr().push_rect(
|
builder.wr().push_rect(
|
||||||
&selection_common,
|
&selection_common,
|
||||||
selection_rect,
|
selection_rect,
|
||||||
|
@ -709,7 +718,7 @@ impl Fragment {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
let insertion_point_common =
|
let insertion_point_common =
|
||||||
builder.common_properties(insertion_point_rect, &fragment.parent_style);
|
builder.common_properties(insertion_point_rect, &parent_style);
|
||||||
// TODO: The color of the caret is currently hardcoded to the text color.
|
// TODO: The color of the caret is currently hardcoded to the text color.
|
||||||
// We should be retrieving the caret color from the style properly.
|
// We should be retrieving the caret color from the style properly.
|
||||||
builder
|
builder
|
||||||
|
@ -734,7 +743,7 @@ impl Fragment {
|
||||||
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 = Au::from_f32_px(font_metrics.strikeout_size.to_nearest_pixel(dppx));
|
||||||
self.build_display_list_for_text_decoration(fragment, builder, &rect, &color);
|
self.build_display_list_for_text_decoration(&parent_style, builder, &rect, &color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !shadows.0.is_empty() {
|
if !shadows.0.is_empty() {
|
||||||
|
@ -744,23 +753,22 @@ impl Fragment {
|
||||||
|
|
||||||
fn build_display_list_for_text_decoration(
|
fn build_display_list_for_text_decoration(
|
||||||
&self,
|
&self,
|
||||||
fragment: &TextFragment,
|
parent_style: &ServoArc<ComputedValues>,
|
||||||
builder: &mut DisplayListBuilder,
|
builder: &mut DisplayListBuilder,
|
||||||
rect: &PhysicalRect<Au>,
|
rect: &PhysicalRect<Au>,
|
||||||
color: &AbsoluteColor,
|
color: &AbsoluteColor,
|
||||||
) {
|
) {
|
||||||
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 = fragment
|
let text_decoration_color = parent_style
|
||||||
.parent_style
|
|
||||||
.clone_text_decoration_color()
|
.clone_text_decoration_color()
|
||||||
.resolve_to_absolute(color);
|
.resolve_to_absolute(color);
|
||||||
let text_decoration_style = fragment.parent_style.clone_text_decoration_style();
|
let text_decoration_style = parent_style.clone_text_decoration_style();
|
||||||
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
|
if text_decoration_style == ComputedTextDecorationStyle::MozNone {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
builder.display_list.wr.push_line(
|
builder.display_list.wr.push_line(
|
||||||
&builder.common_properties(rect, &fragment.parent_style),
|
&builder.common_properties(rect, parent_style),
|
||||||
&rect,
|
&rect,
|
||||||
wavy_line_thickness,
|
wavy_line_thickness,
|
||||||
wr::LineOrientation::Horizontal,
|
wr::LineOrientation::Horizontal,
|
||||||
|
@ -1026,7 +1034,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
||||||
for extra_background in extra_backgrounds {
|
for extra_background in extra_backgrounds {
|
||||||
let positioning_area = extra_background.rect;
|
let positioning_area = extra_background.rect;
|
||||||
let painter = BackgroundPainter {
|
let painter = BackgroundPainter {
|
||||||
style: &extra_background.style.borrow_mut().0,
|
style: &extra_background.style.borrow_mut(),
|
||||||
painting_area_override: None,
|
painting_area_override: None,
|
||||||
positioning_area_override: Some(
|
positioning_area_override: Some(
|
||||||
positioning_area
|
positioning_area
|
||||||
|
|
|
@ -26,7 +26,7 @@ use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::flexbox::FlexLevelBox;
|
use crate::flexbox::FlexLevelBox;
|
||||||
use crate::flow::BlockLevelBox;
|
use crate::flow::BlockLevelBox;
|
||||||
use crate::flow::inline::InlineItem;
|
use crate::flow::inline::{InlineItem, SharedInlineStyles};
|
||||||
use crate::fragment_tree::Fragment;
|
use crate::fragment_tree::Fragment;
|
||||||
use crate::geom::PhysicalSize;
|
use crate::geom::PhysicalSize;
|
||||||
use crate::replaced::CanvasInfo;
|
use crate::replaced::CanvasInfo;
|
||||||
|
@ -59,7 +59,7 @@ impl InnerDOMLayoutData {
|
||||||
/// A box that is stored in one of the `DOMLayoutData` slots.
|
/// A box that is stored in one of the `DOMLayoutData` slots.
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub(super) enum LayoutBox {
|
pub(super) enum LayoutBox {
|
||||||
DisplayContents,
|
DisplayContents(SharedInlineStyles),
|
||||||
BlockLevel(ArcRefCell<BlockLevelBox>),
|
BlockLevel(ArcRefCell<BlockLevelBox>),
|
||||||
InlineLevel(Vec<ArcRefCell<InlineItem>>),
|
InlineLevel(Vec<ArcRefCell<InlineItem>>),
|
||||||
FlexLevel(ArcRefCell<FlexLevelBox>),
|
FlexLevel(ArcRefCell<FlexLevelBox>),
|
||||||
|
@ -70,7 +70,7 @@ pub(super) enum LayoutBox {
|
||||||
impl LayoutBox {
|
impl LayoutBox {
|
||||||
fn invalidate_cached_fragment(&self) {
|
fn invalidate_cached_fragment(&self) {
|
||||||
match self {
|
match self {
|
||||||
LayoutBox::DisplayContents => {},
|
LayoutBox::DisplayContents(..) => {},
|
||||||
LayoutBox::BlockLevel(block_level_box) => {
|
LayoutBox::BlockLevel(block_level_box) => {
|
||||||
block_level_box.borrow().invalidate_cached_fragment()
|
block_level_box.borrow().invalidate_cached_fragment()
|
||||||
},
|
},
|
||||||
|
@ -91,7 +91,7 @@ impl LayoutBox {
|
||||||
|
|
||||||
pub(crate) fn fragments(&self) -> Vec<Fragment> {
|
pub(crate) fn fragments(&self) -> Vec<Fragment> {
|
||||||
match self {
|
match self {
|
||||||
LayoutBox::DisplayContents => vec![],
|
LayoutBox::DisplayContents(..) => vec![],
|
||||||
LayoutBox::BlockLevel(block_level_box) => block_level_box.borrow().fragments(),
|
LayoutBox::BlockLevel(block_level_box) => block_level_box.borrow().fragments(),
|
||||||
LayoutBox::InlineLevel(inline_items) => inline_items
|
LayoutBox::InlineLevel(inline_items) => inline_items
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -23,6 +23,7 @@ use style::values::specified::Quotes;
|
||||||
|
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::dom::{BoxSlot, LayoutBox, NodeExt};
|
use crate::dom::{BoxSlot, LayoutBox, NodeExt};
|
||||||
|
use crate::flow::inline::SharedInlineStyles;
|
||||||
use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags, Tag};
|
use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags, Tag};
|
||||||
use crate::quotes::quotes_for_lang;
|
use crate::quotes::quotes_for_lang;
|
||||||
use crate::replaced::ReplacedContents;
|
use crate::replaced::ReplacedContents;
|
||||||
|
@ -185,6 +186,12 @@ pub(super) trait TraversalHandler<'dom> {
|
||||||
contents: Contents,
|
contents: Contents,
|
||||||
box_slot: BoxSlot<'dom>,
|
box_slot: BoxSlot<'dom>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Notify the handler that we are about to recurse into a `display: contents` element.
|
||||||
|
fn enter_display_contents(&mut self, _: SharedInlineStyles) {}
|
||||||
|
|
||||||
|
/// Notify the handler that we have finished a `display: contents` element.
|
||||||
|
fn leave_display_contents(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn traverse_children_of<'dom>(
|
fn traverse_children_of<'dom>(
|
||||||
|
@ -254,8 +261,15 @@ fn traverse_element<'dom>(
|
||||||
// <https://drafts.csswg.org/css-display-3/#valdef-display-contents>
|
// <https://drafts.csswg.org/css-display-3/#valdef-display-contents>
|
||||||
element.unset_all_boxes()
|
element.unset_all_boxes()
|
||||||
} else {
|
} else {
|
||||||
element.element_box_slot().set(LayoutBox::DisplayContents);
|
let shared_inline_styles: SharedInlineStyles =
|
||||||
traverse_children_of(element, context, handler)
|
(&NodeAndStyleInfo::new(element, style)).into();
|
||||||
|
element
|
||||||
|
.element_box_slot()
|
||||||
|
.set(LayoutBox::DisplayContents(shared_inline_styles.clone()));
|
||||||
|
|
||||||
|
handler.enter_display_contents(shared_inline_styles);
|
||||||
|
traverse_children_of(element, context, handler);
|
||||||
|
handler.leave_display_contents();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Display::GeneratingBox(display) => {
|
Display::GeneratingBox(display) => {
|
||||||
|
@ -308,8 +322,12 @@ fn traverse_eager_pseudo_element<'dom>(
|
||||||
Display::Contents => {
|
Display::Contents => {
|
||||||
let items = generate_pseudo_element_content(&info.style, node, context);
|
let items = generate_pseudo_element_content(&info.style, node, context);
|
||||||
let box_slot = node.pseudo_element_box_slot(pseudo_element_type);
|
let box_slot = node.pseudo_element_box_slot(pseudo_element_type);
|
||||||
box_slot.set(LayoutBox::DisplayContents);
|
let shared_inline_styles: SharedInlineStyles = (&info).into();
|
||||||
|
box_slot.set(LayoutBox::DisplayContents(shared_inline_styles.clone()));
|
||||||
|
|
||||||
|
handler.enter_display_contents(shared_inline_styles);
|
||||||
traverse_pseudo_element_contents(&info, context, handler, items);
|
traverse_pseudo_element_contents(&info, context, handler, items);
|
||||||
|
handler.leave_display_contents();
|
||||||
},
|
},
|
||||||
Display::GeneratingBox(display) => {
|
Display::GeneratingBox(display) => {
|
||||||
let items = generate_pseudo_element_content(&info.style, node, context);
|
let items = generate_pseudo_element_content(&info.style, node, context);
|
||||||
|
|
|
@ -90,7 +90,6 @@ impl FlexContainerConfig {
|
||||||
pub(crate) struct FlexContainer {
|
pub(crate) struct FlexContainer {
|
||||||
children: Vec<ArcRefCell<FlexLevelBox>>,
|
children: Vec<ArcRefCell<FlexLevelBox>>,
|
||||||
|
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
style: ServoArc<ComputedValues>,
|
style: ServoArc<ComputedValues>,
|
||||||
|
|
||||||
/// The configuration of this [`FlexContainer`].
|
/// The configuration of this [`FlexContainer`].
|
||||||
|
|
|
@ -13,9 +13,9 @@ use style::selector_parser::PseudoElement;
|
||||||
use style::str::char_is_whitespace;
|
use style::str::char_is_whitespace;
|
||||||
|
|
||||||
use super::OutsideMarker;
|
use super::OutsideMarker;
|
||||||
use super::inline::InlineFormattingContext;
|
|
||||||
use super::inline::construct::InlineFormattingContextBuilder;
|
use super::inline::construct::InlineFormattingContextBuilder;
|
||||||
use super::inline::inline_box::InlineBox;
|
use super::inline::inline_box::InlineBox;
|
||||||
|
use super::inline::{InlineFormattingContext, SharedInlineStyles};
|
||||||
use crate::PropagatedBoxTreeData;
|
use crate::PropagatedBoxTreeData;
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
|
@ -137,16 +137,25 @@ pub(crate) struct BlockContainerBuilder<'dom, 'style> {
|
||||||
/// The propagated data to use for BoxTree construction.
|
/// The propagated data to use for BoxTree construction.
|
||||||
propagated_data: PropagatedBoxTreeData,
|
propagated_data: PropagatedBoxTreeData,
|
||||||
|
|
||||||
inline_formatting_context_builder: InlineFormattingContextBuilder,
|
/// The [`InlineFormattingContextBuilder`] if we have encountered any inline items,
|
||||||
|
/// otherwise None.
|
||||||
|
///
|
||||||
|
/// TODO: This can be `OnceCell` once `OnceCell::get_mut_or_init` is stabilized.
|
||||||
|
inline_formatting_context_builder: Option<InlineFormattingContextBuilder>,
|
||||||
|
|
||||||
/// The [`NodeAndStyleInfo`] to use for anonymous block boxes pushed to the list of
|
/// The [`NodeAndStyleInfo`] to use for anonymous block boxes pushed to the list of
|
||||||
/// block-level boxes, lazily initialized (see `end_ongoing_inline_formatting_context`).
|
/// block-level boxes, lazily initialized.
|
||||||
anonymous_box_info: Option<NodeAndStyleInfo<'dom>>,
|
anonymous_box_info: Option<NodeAndStyleInfo<'dom>>,
|
||||||
|
|
||||||
/// A collection of content that is being added to an anonymous table. This is
|
/// A collection of content that is being added to an anonymous table. This is
|
||||||
/// composed of any sequence of internal table elements or table captions that
|
/// composed of any sequence of internal table elements or table captions that
|
||||||
/// are found outside of a table.
|
/// are found outside of a table.
|
||||||
anonymous_table_content: Vec<AnonymousTableContent<'dom>>,
|
anonymous_table_content: Vec<AnonymousTableContent<'dom>>,
|
||||||
|
|
||||||
|
/// Any [`InlineFormattingContexts`] created need to know about the ongoing `display: contents`
|
||||||
|
/// ancestors that have been processed. This `Vec` allows passing those into new
|
||||||
|
/// [`InlineFormattingContext`]s that we create.
|
||||||
|
display_contents_shared_styles: Vec<SharedInlineStyles>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockContainer {
|
impl BlockContainer {
|
||||||
|
@ -194,26 +203,44 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
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(),
|
||||||
inline_formatting_context_builder: InlineFormattingContextBuilder::new(),
|
inline_formatting_context_builder: None,
|
||||||
|
display_contents_shared_styles: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn finish(mut self) -> BlockContainer {
|
fn currently_processing_inline_box(&self) -> bool {
|
||||||
debug_assert!(
|
self.inline_formatting_context_builder
|
||||||
!self
|
.as_ref()
|
||||||
.inline_formatting_context_builder
|
.is_some_and(InlineFormattingContextBuilder::currently_processing_inline_box)
|
||||||
.currently_processing_inline_box()
|
}
|
||||||
);
|
|
||||||
|
|
||||||
self.finish_anonymous_table_if_needed();
|
fn ensure_inline_formatting_context_builder(&mut self) -> &mut InlineFormattingContextBuilder {
|
||||||
|
self.inline_formatting_context_builder
|
||||||
|
.get_or_insert_with(|| {
|
||||||
|
let mut builder = InlineFormattingContextBuilder::new(self.info);
|
||||||
|
for shared_inline_styles in self.display_contents_shared_styles.iter() {
|
||||||
|
builder.enter_display_contents(shared_inline_styles.clone());
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish(
|
fn finish_ongoing_inline_formatting_context(&mut self) -> Option<InlineFormattingContext> {
|
||||||
|
self.inline_formatting_context_builder.take()?.finish(
|
||||||
self.context,
|
self.context,
|
||||||
self.propagated_data,
|
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(),
|
||||||
) {
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn finish(mut self) -> BlockContainer {
|
||||||
|
debug_assert!(!self.currently_processing_inline_box());
|
||||||
|
|
||||||
|
self.finish_anonymous_table_if_needed();
|
||||||
|
|
||||||
|
if let Some(inline_formatting_context) = self.finish_ongoing_inline_formatting_context() {
|
||||||
// There are two options here. This block was composed of both one or more inline formatting contexts
|
// There are two options here. This block was composed of both one or more inline formatting contexts
|
||||||
// and child blocks OR this block was a single inline formatting context. In the latter case, we
|
// and child blocks OR this block was a single inline formatting context. In the latter case, we
|
||||||
// just return the inline formatting context as the block itself.
|
// just return the inline formatting context as the block itself.
|
||||||
|
@ -251,9 +278,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
//
|
//
|
||||||
// Note that text content in the inline formatting context isn't enough to force the
|
// Note that text content in the inline formatting context isn't enough to force the
|
||||||
// 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
|
let inline_table = self.currently_processing_inline_box();
|
||||||
.inline_formatting_context_builder
|
|
||||||
.currently_processing_inline_box();
|
|
||||||
|
|
||||||
// Text decorations are not propagated to atomic inline-level descendants.
|
// Text decorations are not propagated to atomic inline-level descendants.
|
||||||
// From https://drafts.csswg.org/css2/#lining-striking-props:
|
// From https://drafts.csswg.org/css2/#lining-striking-props:
|
||||||
|
@ -276,10 +301,16 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
|
||||||
Table::construct_anonymous(self.context, self.info, contents, propagated_data);
|
Table::construct_anonymous(self.context, self.info, contents, propagated_data);
|
||||||
|
|
||||||
if inline_table {
|
if inline_table {
|
||||||
self.inline_formatting_context_builder.push_atomic(ifc);
|
self.ensure_inline_formatting_context_builder()
|
||||||
|
.push_atomic(ifc);
|
||||||
} else {
|
} else {
|
||||||
let table_block = ArcRefCell::new(BlockLevelBox::Independent(ifc));
|
let table_block = ArcRefCell::new(BlockLevelBox::Independent(ifc));
|
||||||
self.end_ongoing_inline_formatting_context();
|
|
||||||
|
if let Some(inline_formatting_context) = self.finish_ongoing_inline_formatting_context()
|
||||||
|
{
|
||||||
|
self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
|
||||||
|
}
|
||||||
|
|
||||||
self.block_level_boxes.push(BlockLevelJob {
|
self.block_level_boxes.push(BlockLevelJob {
|
||||||
info: table_info,
|
info: table_info,
|
||||||
box_slot: BoxSlot::dummy(),
|
box_slot: BoxSlot::dummy(),
|
||||||
|
@ -363,7 +394,22 @@ impl<'dom> TraversalHandler<'dom> for BlockContainerBuilder<'dom, '_> {
|
||||||
self.finish_anonymous_table_if_needed();
|
self.finish_anonymous_table_if_needed();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inline_formatting_context_builder.push_text(text, info);
|
self.ensure_inline_formatting_context_builder()
|
||||||
|
.push_text(text, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter_display_contents(&mut self, styles: SharedInlineStyles) {
|
||||||
|
self.display_contents_shared_styles.push(styles.clone());
|
||||||
|
if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
|
||||||
|
builder.enter_display_contents(styles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave_display_contents(&mut self) {
|
||||||
|
self.display_contents_shared_styles.pop();
|
||||||
|
if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
|
||||||
|
builder.leave_display_contents();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,14 +479,16 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
(display_inside, contents.is_replaced())
|
(display_inside, contents.is_replaced())
|
||||||
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 atomic = self.inline_formatting_context_builder.push_atomic(
|
let context = self.context;
|
||||||
|
let propagaged_data = self.propagated_data.without_text_decorations();
|
||||||
|
let atomic = self.ensure_inline_formatting_context_builder().push_atomic(
|
||||||
IndependentFormattingContext::construct(
|
IndependentFormattingContext::construct(
|
||||||
self.context,
|
context,
|
||||||
info,
|
info,
|
||||||
display_inside,
|
display_inside,
|
||||||
contents,
|
contents,
|
||||||
// Text decorations are not propagated to atomic inline-level descendants.
|
// Text decorations are not propagated to atomic inline-level descendants.
|
||||||
self.propagated_data.without_text_decorations(),
|
propagaged_data,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
box_slot.set(LayoutBox::InlineLevel(vec![atomic]));
|
box_slot.set(LayoutBox::InlineLevel(vec![atomic]));
|
||||||
|
@ -449,7 +497,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
|
|
||||||
// Otherwise, this is just a normal inline box. Whatever happened before, all we need to do
|
// Otherwise, this is just a normal inline box. Whatever happened before, all we need to do
|
||||||
// before recurring is to remember this ongoing inline level box.
|
// before recurring is to remember this ongoing inline level box.
|
||||||
self.inline_formatting_context_builder
|
self.ensure_inline_formatting_context_builder()
|
||||||
.start_inline_box(InlineBox::new(info), None);
|
.start_inline_box(InlineBox::new(info), None);
|
||||||
|
|
||||||
if is_list_item {
|
if is_list_item {
|
||||||
|
@ -476,7 +524,10 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
// `InlineFormattingContextBuilder::end_inline_box()` is returning all of those box tree
|
// `InlineFormattingContextBuilder::end_inline_box()` is returning all of those box tree
|
||||||
// items.
|
// items.
|
||||||
box_slot.set(LayoutBox::InlineLevel(
|
box_slot.set(LayoutBox::InlineLevel(
|
||||||
self.inline_formatting_context_builder.end_inline_box(),
|
self.inline_formatting_context_builder
|
||||||
|
.as_mut()
|
||||||
|
.expect("Should be building an InlineFormattingContext")
|
||||||
|
.end_inline_box(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,12 +546,15 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
// that we want to have after we push the block below.
|
// that we want to have after we push the block below.
|
||||||
if let Some(inline_formatting_context) = self
|
if let Some(inline_formatting_context) = self
|
||||||
.inline_formatting_context_builder
|
.inline_formatting_context_builder
|
||||||
.split_around_block_and_finish(
|
.as_mut()
|
||||||
self.context,
|
.and_then(|builder| {
|
||||||
self.propagated_data,
|
builder.split_around_block_and_finish(
|
||||||
!self.have_already_seen_first_line_for_text_indent,
|
self.context,
|
||||||
self.info.style.writing_mode.to_bidi_level(),
|
self.propagated_data,
|
||||||
)
|
!self.have_already_seen_first_line_for_text_indent,
|
||||||
|
self.info.style.writing_mode.to_bidi_level(),
|
||||||
|
)
|
||||||
|
})
|
||||||
{
|
{
|
||||||
self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
|
self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
|
||||||
}
|
}
|
||||||
|
@ -555,17 +609,18 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
contents: Contents,
|
contents: Contents,
|
||||||
box_slot: BoxSlot<'dom>,
|
box_slot: BoxSlot<'dom>,
|
||||||
) {
|
) {
|
||||||
if !self.inline_formatting_context_builder.is_empty() {
|
if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
|
||||||
let inline_level_box = self
|
if !builder.is_empty() {
|
||||||
.inline_formatting_context_builder
|
let inline_level_box =
|
||||||
.push_absolutely_positioned_box(AbsolutelyPositionedBox::construct(
|
builder.push_absolutely_positioned_box(AbsolutelyPositionedBox::construct(
|
||||||
self.context,
|
self.context,
|
||||||
info,
|
info,
|
||||||
display_inside,
|
display_inside,
|
||||||
contents,
|
contents,
|
||||||
));
|
));
|
||||||
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
|
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let kind = BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
|
let kind = BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
|
||||||
|
@ -587,18 +642,18 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
contents: Contents,
|
contents: Contents,
|
||||||
box_slot: BoxSlot<'dom>,
|
box_slot: BoxSlot<'dom>,
|
||||||
) {
|
) {
|
||||||
if !self.inline_formatting_context_builder.is_empty() {
|
if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
|
||||||
let inline_level_box =
|
if !builder.is_empty() {
|
||||||
self.inline_formatting_context_builder
|
let inline_level_box = builder.push_float_box(FloatBox::construct(
|
||||||
.push_float_box(FloatBox::construct(
|
self.context,
|
||||||
self.context,
|
info,
|
||||||
info,
|
display_inside,
|
||||||
display_inside,
|
contents,
|
||||||
contents,
|
self.propagated_data,
|
||||||
self.propagated_data,
|
));
|
||||||
));
|
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
|
||||||
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let kind = BlockLevelCreator::OutOfFlowFloatBox {
|
let kind = BlockLevelCreator::OutOfFlowFloatBox {
|
||||||
|
@ -613,18 +668,6 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_ongoing_inline_formatting_context(&mut self) {
|
|
||||||
if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish(
|
|
||||||
self.context,
|
|
||||||
self.propagated_data,
|
|
||||||
!self.have_already_seen_first_line_for_text_indent,
|
|
||||||
self.info.is_single_line_text_input(),
|
|
||||||
self.info.style.writing_mode.to_bidi_level(),
|
|
||||||
) {
|
|
||||||
self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_block_level_job_for_inline_formatting_context(
|
fn push_block_level_job_for_inline_formatting_context(
|
||||||
&mut self,
|
&mut self,
|
||||||
inline_formatting_context: InlineFormattingContext,
|
inline_formatting_context: InlineFormattingContext,
|
||||||
|
|
|
@ -13,7 +13,10 @@ use style::values::specified::text::TextTransformCase;
|
||||||
use unicode_bidi::Level;
|
use unicode_bidi::Level;
|
||||||
|
|
||||||
use super::text_run::TextRun;
|
use super::text_run::TextRun;
|
||||||
use super::{InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext, InlineItem};
|
use super::{
|
||||||
|
InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext, InlineItem,
|
||||||
|
SharedInlineStyles,
|
||||||
|
};
|
||||||
use crate::PropagatedBoxTreeData;
|
use crate::PropagatedBoxTreeData;
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
|
@ -25,6 +28,12 @@ use crate::style_ext::ComputedValuesExt;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct InlineFormattingContextBuilder {
|
pub(crate) struct InlineFormattingContextBuilder {
|
||||||
|
/// A stack of [`SharedInlineStyles`] including one for the root, one for each inline box on the
|
||||||
|
/// inline box stack, and importantly, one for every `display: contents` element that we are
|
||||||
|
/// currently processing. Normally `display: contents` elements don't affect the structure of
|
||||||
|
/// the [`InlineFormattingContext`], but the styles they provide do style their children.
|
||||||
|
shared_inline_styles_stack: Vec<SharedInlineStyles>,
|
||||||
|
|
||||||
/// The collection of text strings that make up this [`InlineFormattingContext`] under
|
/// The collection of text strings that make up this [`InlineFormattingContext`] under
|
||||||
/// construction.
|
/// construction.
|
||||||
pub text_segments: Vec<String>,
|
pub text_segments: Vec<String>,
|
||||||
|
@ -63,7 +72,7 @@ pub(crate) struct InlineFormattingContextBuilder {
|
||||||
/// The traversal is at all times as deep in the tree as this stack is,
|
/// The traversal is at all times as deep in the tree as this stack is,
|
||||||
/// which is why the code doesn't need to keep track of the actual
|
/// which is why the code doesn't need to keep track of the actual
|
||||||
/// container root (see `handle_inline_level_element`).
|
/// container root (see `handle_inline_level_element`).
|
||||||
///
|
//_
|
||||||
/// When an inline box ends, it's removed from this stack.
|
/// When an inline box ends, it's removed from this stack.
|
||||||
inline_box_stack: Vec<InlineBoxIdentifier>,
|
inline_box_stack: Vec<InlineBoxIdentifier>,
|
||||||
|
|
||||||
|
@ -83,10 +92,17 @@ pub(crate) struct InlineFormattingContextBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineFormattingContextBuilder {
|
impl InlineFormattingContextBuilder {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new(info: &NodeAndStyleInfo) -> Self {
|
||||||
// For the purposes of `text-transform: capitalize` the start of the IFC is a word boundary.
|
Self::new_for_shared_styles(vec![info.into()])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_for_shared_styles(
|
||||||
|
shared_inline_styles_stack: Vec<SharedInlineStyles>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
// For the purposes of `text-transform: capitalize` the start of the IFC is a word boundary.
|
||||||
on_word_boundary: true,
|
on_word_boundary: true,
|
||||||
|
shared_inline_styles_stack,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,6 +116,13 @@ impl InlineFormattingContextBuilder {
|
||||||
self.current_text_offset += string_to_push.len();
|
self.current_text_offset += string_to_push.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shared_inline_styles(&self) -> SharedInlineStyles {
|
||||||
|
self.shared_inline_styles_stack
|
||||||
|
.last()
|
||||||
|
.expect("Should always have at least one SharedInlineStyles")
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return true if this [`InlineFormattingContextBuilder`] is empty for the purposes of ignoring
|
/// Return true if this [`InlineFormattingContextBuilder`] is empty for the purposes of ignoring
|
||||||
/// during box tree construction. An IFC is empty if it only contains TextRuns with
|
/// during box tree construction. An IFC is empty if it only contains TextRuns with
|
||||||
/// completely collapsible whitespace. When that happens it can be ignored completely.
|
/// completely collapsible whitespace. When that happens it can be ignored completely.
|
||||||
|
@ -179,6 +202,14 @@ impl InlineFormattingContextBuilder {
|
||||||
) {
|
) {
|
||||||
self.push_control_character_string(inline_box.base.style.bidi_control_chars().0);
|
self.push_control_character_string(inline_box.base.style.bidi_control_chars().0);
|
||||||
|
|
||||||
|
// Don't push a `SharedInlineStyles` if we are pushing this box when splitting
|
||||||
|
// an IFC for a block-in-inline split. Shared styles are pushed as part of setting
|
||||||
|
// up the second split of the IFC.
|
||||||
|
if inline_box.is_first_split {
|
||||||
|
self.shared_inline_styles_stack
|
||||||
|
.push(inline_box.shared_inline_styles.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let (identifier, inline_box) = self.inline_boxes.start_inline_box(inline_box);
|
let (identifier, inline_box) = self.inline_boxes.start_inline_box(inline_box);
|
||||||
let inline_level_box = ArcRefCell::new(InlineItem::StartInlineBox(inline_box));
|
let inline_level_box = ArcRefCell::new(InlineItem::StartInlineBox(inline_box));
|
||||||
self.inline_items.push(inline_level_box.clone());
|
self.inline_items.push(inline_level_box.clone());
|
||||||
|
@ -194,6 +225,8 @@ impl InlineFormattingContextBuilder {
|
||||||
/// a single box tree items may be produced for a single inline box when that inline
|
/// a single box tree items may be produced for a single inline box when that inline
|
||||||
/// box is split around a block-level element.
|
/// box is split around a block-level element.
|
||||||
pub(crate) fn end_inline_box(&mut self) -> Vec<ArcRefCell<InlineItem>> {
|
pub(crate) fn end_inline_box(&mut self) -> Vec<ArcRefCell<InlineItem>> {
|
||||||
|
self.shared_inline_styles_stack.pop();
|
||||||
|
|
||||||
let (identifier, block_in_inline_splits) = self.end_inline_box_internal();
|
let (identifier, block_in_inline_splits) = self.end_inline_box_internal();
|
||||||
let inline_level_box = self.inline_boxes.get(&identifier);
|
let inline_level_box = self.inline_boxes.get(&identifier);
|
||||||
{
|
{
|
||||||
|
@ -272,8 +305,6 @@ impl InlineFormattingContextBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
let selection_range = info.get_selection_range();
|
let selection_range = info.get_selection_range();
|
||||||
let selected_style = info.get_selected_style();
|
|
||||||
|
|
||||||
if let Some(last_character) = new_text.chars().next_back() {
|
if let Some(last_character) = new_text.chars().next_back() {
|
||||||
self.on_word_boundary = last_character.is_whitespace();
|
self.on_word_boundary = last_character.is_whitespace();
|
||||||
self.last_inline_box_ended_with_collapsible_white_space =
|
self.last_inline_box_ended_with_collapsible_white_space =
|
||||||
|
@ -295,14 +326,21 @@ impl InlineFormattingContextBuilder {
|
||||||
.push(ArcRefCell::new(InlineItem::TextRun(ArcRefCell::new(
|
.push(ArcRefCell::new(InlineItem::TextRun(ArcRefCell::new(
|
||||||
TextRun::new(
|
TextRun::new(
|
||||||
info.into(),
|
info.into(),
|
||||||
info.style.clone(),
|
self.shared_inline_styles(),
|
||||||
new_range,
|
new_range,
|
||||||
selection_range,
|
selection_range,
|
||||||
selected_style,
|
|
||||||
),
|
),
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enter_display_contents(&mut self, shared_inline_styles: SharedInlineStyles) {
|
||||||
|
self.shared_inline_styles_stack.push(shared_inline_styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn leave_display_contents(&mut self) {
|
||||||
|
self.shared_inline_styles_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -318,7 +356,8 @@ impl InlineFormattingContextBuilder {
|
||||||
// context. It has the same inline box structure as this builder, except the boxes are
|
// context. It has the same inline box structure as this builder, except the boxes are
|
||||||
// marked as not being the first fragment. No inline content is carried over to this new
|
// marked as not being the first fragment. No inline content is carried over to this new
|
||||||
// builder.
|
// builder.
|
||||||
let mut new_builder = InlineFormattingContextBuilder::new();
|
let mut new_builder = Self::new_for_shared_styles(self.shared_inline_styles_stack.clone());
|
||||||
|
|
||||||
let block_in_inline_splits = std::mem::take(&mut self.block_in_inline_splits);
|
let block_in_inline_splits = std::mem::take(&mut self.block_in_inline_splits);
|
||||||
for (identifier, historical_inline_boxes) in
|
for (identifier, historical_inline_boxes) in
|
||||||
izip!(self.inline_box_stack.iter(), block_in_inline_splits)
|
izip!(self.inline_box_stack.iter(), block_in_inline_splits)
|
||||||
|
@ -356,7 +395,7 @@ impl InlineFormattingContextBuilder {
|
||||||
|
|
||||||
/// Finish the current inline formatting context, returning [`None`] if the context was empty.
|
/// Finish the current inline formatting context, returning [`None`] if the context was empty.
|
||||||
pub(crate) fn finish(
|
pub(crate) fn finish(
|
||||||
&mut self,
|
self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
propagated_data: PropagatedBoxTreeData,
|
propagated_data: PropagatedBoxTreeData,
|
||||||
has_first_formatted_line: bool,
|
has_first_formatted_line: bool,
|
||||||
|
@ -367,11 +406,9 @@ impl InlineFormattingContextBuilder {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_builder = std::mem::replace(self, InlineFormattingContextBuilder::new());
|
assert!(self.inline_box_stack.is_empty());
|
||||||
assert!(old_builder.inline_box_stack.is_empty());
|
|
||||||
|
|
||||||
Some(InlineFormattingContext::new_with_builder(
|
Some(InlineFormattingContext::new_with_builder(
|
||||||
old_builder,
|
self,
|
||||||
layout_context,
|
layout_context,
|
||||||
propagated_data,
|
propagated_data,
|
||||||
has_first_formatted_line,
|
has_first_formatted_line,
|
||||||
|
|
|
@ -8,7 +8,10 @@ use app_units::Au;
|
||||||
use fonts::FontMetrics;
|
use fonts::FontMetrics;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
|
|
||||||
use super::{InlineContainerState, InlineContainerStateFlags, inline_container_needs_strut};
|
use super::{
|
||||||
|
InlineContainerState, InlineContainerStateFlags, SharedInlineStyles,
|
||||||
|
inline_container_needs_strut,
|
||||||
|
};
|
||||||
use crate::ContainingBlock;
|
use crate::ContainingBlock;
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
|
@ -20,6 +23,9 @@ use crate::style_ext::{LayoutStyle, PaddingBorderMargin};
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub(crate) struct InlineBox {
|
pub(crate) struct InlineBox {
|
||||||
pub base: LayoutBoxBase,
|
pub base: LayoutBoxBase,
|
||||||
|
/// The [`SharedInlineStyles`] for this [`InlineBox`] that are used to share styles
|
||||||
|
/// with all [`super::TextRun`] children.
|
||||||
|
pub(super) shared_inline_styles: SharedInlineStyles,
|
||||||
/// The identifier of this inline box in the containing [`super::InlineFormattingContext`].
|
/// The identifier of this inline box in the containing [`super::InlineFormattingContext`].
|
||||||
pub(super) identifier: InlineBoxIdentifier,
|
pub(super) identifier: InlineBoxIdentifier,
|
||||||
/// Whether or not this is the first instance of an [`InlineBox`] before a possible
|
/// Whether or not this is the first instance of an [`InlineBox`] before a possible
|
||||||
|
@ -37,6 +43,7 @@ impl InlineBox {
|
||||||
pub(crate) fn new(info: &NodeAndStyleInfo) -> Self {
|
pub(crate) fn new(info: &NodeAndStyleInfo) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
||||||
|
shared_inline_styles: info.into(),
|
||||||
// This will be assigned later, when the box is actually added to the IFC.
|
// This will be assigned later, when the box is actually added to the IFC.
|
||||||
identifier: InlineBoxIdentifier::default(),
|
identifier: InlineBoxIdentifier::default(),
|
||||||
is_first_split: true,
|
is_first_split: true,
|
||||||
|
@ -48,6 +55,7 @@ impl InlineBox {
|
||||||
pub(crate) fn split_around_block(&self) -> Self {
|
pub(crate) fn split_around_block(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base: LayoutBoxBase::new(self.base.base_fragment_info, self.base.style.clone()),
|
base: LayoutBoxBase::new(self.base.base_fragment_info, self.base.style.clone()),
|
||||||
|
shared_inline_styles: self.shared_inline_styles.clone(),
|
||||||
is_first_split: false,
|
is_first_split: false,
|
||||||
is_last_split: false,
|
is_last_split: false,
|
||||||
..*self
|
..*self
|
||||||
|
|
|
@ -7,7 +7,6 @@ use bitflags::bitflags;
|
||||||
use fonts::{ByteIndex, FontMetrics, GlyphStore};
|
use fonts::{ByteIndex, FontMetrics, GlyphStore};
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use range::Range;
|
use range::Range;
|
||||||
use servo_arc::Arc;
|
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use style::computed_values::position::T as Position;
|
use style::computed_values::position::T as Position;
|
||||||
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
|
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
|
||||||
|
@ -21,7 +20,7 @@ use unicode_bidi::{BidiInfo, Level};
|
||||||
use webrender_api::FontInstanceKey;
|
use webrender_api::FontInstanceKey;
|
||||||
|
|
||||||
use super::inline_box::{InlineBoxContainerState, InlineBoxIdentifier, InlineBoxTreePathToken};
|
use super::inline_box::{InlineBoxContainerState, InlineBoxIdentifier, InlineBoxTreePathToken};
|
||||||
use super::{InlineFormattingContextLayout, LineBlockSizes};
|
use super::{InlineFormattingContextLayout, LineBlockSizes, SharedInlineStyles};
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, TextFragment};
|
use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, TextFragment};
|
||||||
use crate::geom::{LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
|
use crate::geom::{LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
|
||||||
|
@ -568,7 +567,7 @@ impl LineItemLayout<'_, '_> {
|
||||||
self.current_state.fragments.push((
|
self.current_state.fragments.push((
|
||||||
Fragment::Text(ArcRefCell::new(TextFragment {
|
Fragment::Text(ArcRefCell::new(TextFragment {
|
||||||
base: text_item.base_fragment_info.into(),
|
base: text_item.base_fragment_info.into(),
|
||||||
parent_style: text_item.parent_style,
|
inline_styles: text_item.inline_styles.clone(),
|
||||||
rect: PhysicalRect::zero(),
|
rect: PhysicalRect::zero(),
|
||||||
font_metrics: text_item.font_metrics,
|
font_metrics: text_item.font_metrics,
|
||||||
font_key: text_item.font_key,
|
font_key: text_item.font_key,
|
||||||
|
@ -576,7 +575,6 @@ impl LineItemLayout<'_, '_> {
|
||||||
text_decoration_line: text_item.text_decoration_line,
|
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,
|
||||||
selected_style: text_item.selected_style,
|
|
||||||
})),
|
})),
|
||||||
content_rect,
|
content_rect,
|
||||||
));
|
));
|
||||||
|
@ -763,7 +761,7 @@ impl LineItem {
|
||||||
|
|
||||||
pub(super) struct TextRunLineItem {
|
pub(super) struct TextRunLineItem {
|
||||||
pub base_fragment_info: BaseFragmentInfo,
|
pub base_fragment_info: BaseFragmentInfo,
|
||||||
pub parent_style: Arc<ComputedValues>,
|
pub inline_styles: SharedInlineStyles,
|
||||||
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,
|
||||||
|
@ -771,13 +769,16 @@ pub(super) struct TextRunLineItem {
|
||||||
/// 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>>,
|
||||||
pub selected_style: Arc<ComputedValues>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextRunLineItem {
|
impl TextRunLineItem {
|
||||||
fn trim_whitespace_at_end(&mut self, whitespace_trimmed: &mut Au) -> bool {
|
fn trim_whitespace_at_end(&mut self, whitespace_trimmed: &mut Au) -> bool {
|
||||||
if matches!(
|
if matches!(
|
||||||
self.parent_style.get_inherited_text().white_space_collapse,
|
self.inline_styles
|
||||||
|
.style
|
||||||
|
.borrow()
|
||||||
|
.get_inherited_text()
|
||||||
|
.white_space_collapse,
|
||||||
WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
|
WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -803,7 +804,11 @@ impl TextRunLineItem {
|
||||||
|
|
||||||
fn trim_whitespace_at_start(&mut self, whitespace_trimmed: &mut Au) -> bool {
|
fn trim_whitespace_at_start(&mut self, whitespace_trimmed: &mut Au) -> bool {
|
||||||
if matches!(
|
if matches!(
|
||||||
self.parent_style.get_inherited_text().white_space_collapse,
|
self.inline_styles
|
||||||
|
.style
|
||||||
|
.borrow()
|
||||||
|
.get_inherited_text()
|
||||||
|
.white_space_collapse,
|
||||||
WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
|
WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -118,6 +118,7 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
|
use crate::dom_traversal::NodeAndStyleInfo;
|
||||||
use crate::flow::CollapsibleWithParentStartMargin;
|
use crate::flow::CollapsibleWithParentStartMargin;
|
||||||
use crate::flow::float::{FloatBox, SequentialLayoutState};
|
use crate::flow::float::{FloatBox, SequentialLayoutState};
|
||||||
use crate::formatting_contexts::{
|
use crate::formatting_contexts::{
|
||||||
|
@ -131,7 +132,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};
|
use crate::{ConstraintSpace, ContainingBlock, PropagatedBoxTreeData, 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;
|
||||||
|
@ -173,6 +174,25 @@ pub(crate) struct InlineFormattingContext {
|
||||||
pub(super) has_right_to_left_content: bool,
|
pub(super) has_right_to_left_content: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [`TextRun`] and `TextFragment`s need a handle on their parent inline box (or inline
|
||||||
|
/// formatting context root)'s style. In order to implement incremental layout, these are
|
||||||
|
/// wrapped in [`SharedStyle`]. This allows updating the parent box tree element without
|
||||||
|
/// updating every single descendant box tree node and fragment.
|
||||||
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
|
pub(crate) struct SharedInlineStyles {
|
||||||
|
pub style: SharedStyle,
|
||||||
|
pub selected: SharedStyle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&NodeAndStyleInfo<'_>> for SharedInlineStyles {
|
||||||
|
fn from(info: &NodeAndStyleInfo) -> Self {
|
||||||
|
Self {
|
||||||
|
style: SharedStyle::new(info.style.clone()),
|
||||||
|
selected: SharedStyle::new(info.get_selected_style()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A collection of data used to cache [`FontMetrics`] in the [`InlineFormattingContext`]
|
/// A collection of data used to cache [`FontMetrics`] in the [`InlineFormattingContext`]
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub(crate) struct FontKeyAndMetrics {
|
pub(crate) struct FontKeyAndMetrics {
|
||||||
|
@ -1313,7 +1333,7 @@ impl InlineFormattingContextLayout<'_> {
|
||||||
) {
|
) {
|
||||||
let inline_advance = glyph_store.total_advance();
|
let inline_advance = glyph_store.total_advance();
|
||||||
let flags = if glyph_store.is_whitespace() {
|
let flags = if glyph_store.is_whitespace() {
|
||||||
SegmentContentFlags::from(text_run.parent_style.get_inherited_text())
|
SegmentContentFlags::from(text_run.inline_styles.style.borrow().get_inherited_text())
|
||||||
} else {
|
} else {
|
||||||
SegmentContentFlags::empty()
|
SegmentContentFlags::empty()
|
||||||
};
|
};
|
||||||
|
@ -1398,13 +1418,12 @@ impl InlineFormattingContextLayout<'_> {
|
||||||
TextRunLineItem {
|
TextRunLineItem {
|
||||||
text: vec![glyph_store],
|
text: vec![glyph_store],
|
||||||
base_fragment_info: text_run.base_fragment_info,
|
base_fragment_info: text_run.base_fragment_info,
|
||||||
parent_style: text_run.parent_style.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,
|
text_decoration_line: self.current_inline_container_state().text_decoration_line,
|
||||||
bidi_level,
|
bidi_level,
|
||||||
selection_range,
|
selection_range,
|
||||||
selected_style: text_run.selected_style.clone(),
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -2363,8 +2382,9 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
||||||
},
|
},
|
||||||
InlineItem::TextRun(text_run) => {
|
InlineItem::TextRun(text_run) => {
|
||||||
let text_run = &*text_run.borrow();
|
let text_run = &*text_run.borrow();
|
||||||
|
let parent_style = text_run.inline_styles.style.borrow();
|
||||||
for segment in text_run.shaped_text.iter() {
|
for segment in text_run.shaped_text.iter() {
|
||||||
let style_text = text_run.parent_style.get_inherited_text();
|
let style_text = parent_style.get_inherited_text();
|
||||||
let can_wrap = style_text.text_wrap_mode == TextWrapMode::Wrap;
|
let can_wrap = style_text.text_wrap_mode == TextWrapMode::Wrap;
|
||||||
|
|
||||||
// TODO: This should take account whether or not the first and last character prevent
|
// TODO: This should take account whether or not the first and last character prevent
|
||||||
|
|
|
@ -26,7 +26,7 @@ use unicode_script::Script;
|
||||||
use xi_unicode::linebreak_property;
|
use xi_unicode::linebreak_property;
|
||||||
|
|
||||||
use super::line_breaker::LineBreaker;
|
use super::line_breaker::LineBreaker;
|
||||||
use super::{FontKeyAndMetrics, InlineFormattingContextLayout};
|
use super::{FontKeyAndMetrics, InlineFormattingContextLayout, SharedInlineStyles};
|
||||||
use crate::fragment_tree::BaseFragmentInfo;
|
use crate::fragment_tree::BaseFragmentInfo;
|
||||||
|
|
||||||
// These constants are the xi-unicode line breaking classes that are defined in
|
// These constants are the xi-unicode line breaking classes that are defined in
|
||||||
|
@ -37,22 +37,6 @@ pub(crate) const XI_LINE_BREAKING_CLASS_ZW: u8 = 28;
|
||||||
pub(crate) const XI_LINE_BREAKING_CLASS_WJ: u8 = 30;
|
pub(crate) const XI_LINE_BREAKING_CLASS_WJ: u8 = 30;
|
||||||
pub(crate) const XI_LINE_BREAKING_CLASS_ZWJ: u8 = 42;
|
pub(crate) const XI_LINE_BREAKING_CLASS_ZWJ: u8 = 42;
|
||||||
|
|
||||||
/// <https://www.w3.org/TR/css-display-3/#css-text-run>
|
|
||||||
#[derive(Debug, MallocSizeOf)]
|
|
||||||
pub(crate) struct TextRun {
|
|
||||||
pub base_fragment_info: BaseFragmentInfo,
|
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub parent_style: Arc<ComputedValues>,
|
|
||||||
pub text_range: Range<usize>,
|
|
||||||
|
|
||||||
/// The text of this [`TextRun`] with a font selected, broken into unbreakable
|
|
||||||
/// segments, and shaped.
|
|
||||||
pub shaped_text: Vec<TextRunSegment>,
|
|
||||||
pub selection_range: Option<ServoRange<ByteIndex>>,
|
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub selected_style: Arc<ComputedValues>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are two reasons why we might want to break at the start:
|
// There are two reasons why we might want to break at the start:
|
||||||
//
|
//
|
||||||
// 1. The line breaker told us that a break was necessary between two separate
|
// 1. The line breaker told us that a break was necessary between two separate
|
||||||
|
@ -334,21 +318,49 @@ impl TextRunSegment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single [`TextRun`] for the box tree. These are all descendants of
|
||||||
|
/// [`super::InlineBox`] or the root of the [`super::InlineFormattingContext`]. During
|
||||||
|
/// box tree construction, text is split into [`TextRun`]s based on their font, script,
|
||||||
|
/// etc. When these are created text is already shaped.
|
||||||
|
///
|
||||||
|
/// <https://www.w3.org/TR/css-display-3/#css-text-run>
|
||||||
|
#[derive(Debug, MallocSizeOf)]
|
||||||
|
pub(crate) struct TextRun {
|
||||||
|
/// The [`BaseFragmentInfo`] for this [`TextRun`]. Usually this comes from the
|
||||||
|
/// original text node in the DOM for the text.
|
||||||
|
pub base_fragment_info: BaseFragmentInfo,
|
||||||
|
|
||||||
|
/// The [`crate::SharedStyle`] from this [`TextRun`]s parent element. This is
|
||||||
|
/// shared so that incremental layout can simply update the parent element and
|
||||||
|
/// this [`TextRun`] will be updated automatically.
|
||||||
|
pub inline_styles: SharedInlineStyles,
|
||||||
|
|
||||||
|
/// The range of text in [`super::InlineFormattingContext::text_content`] of the
|
||||||
|
/// [`super::InlineFormattingContext`] that owns this [`TextRun`]. These are UTF-8 offsets.
|
||||||
|
pub text_range: Range<usize>,
|
||||||
|
|
||||||
|
/// The text of this [`TextRun`] with a font selected, broken into unbreakable
|
||||||
|
/// segments, and shaped.
|
||||||
|
pub shaped_text: Vec<TextRunSegment>,
|
||||||
|
|
||||||
|
/// The selection range for the DOM text node that originated this [`TextRun`]. This
|
||||||
|
/// comes directly from the DOM.
|
||||||
|
pub selection_range: Option<ServoRange<ByteIndex>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl TextRun {
|
impl TextRun {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
base_fragment_info: BaseFragmentInfo,
|
base_fragment_info: BaseFragmentInfo,
|
||||||
parent_style: Arc<ComputedValues>,
|
inline_styles: SharedInlineStyles,
|
||||||
text_range: Range<usize>,
|
text_range: Range<usize>,
|
||||||
selection_range: Option<ServoRange<ByteIndex>>,
|
selection_range: Option<ServoRange<ByteIndex>>,
|
||||||
selected_style: Arc<ComputedValues>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_fragment_info,
|
base_fragment_info,
|
||||||
parent_style,
|
inline_styles,
|
||||||
text_range,
|
text_range,
|
||||||
shaped_text: Vec::new(),
|
shaped_text: Vec::new(),
|
||||||
selection_range,
|
selection_range,
|
||||||
selected_style,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,11 +372,12 @@ impl TextRun {
|
||||||
font_cache: &mut Vec<FontKeyAndMetrics>,
|
font_cache: &mut Vec<FontKeyAndMetrics>,
|
||||||
bidi_info: &BidiInfo,
|
bidi_info: &BidiInfo,
|
||||||
) {
|
) {
|
||||||
let inherited_text_style = self.parent_style.get_inherited_text().clone();
|
let parent_style = self.inline_styles.style.borrow().clone();
|
||||||
|
let inherited_text_style = parent_style.get_inherited_text().clone();
|
||||||
let letter_spacing = inherited_text_style
|
let letter_spacing = inherited_text_style
|
||||||
.letter_spacing
|
.letter_spacing
|
||||||
.0
|
.0
|
||||||
.resolve(self.parent_style.clone_font().font_size.computed_size());
|
.resolve(parent_style.clone_font().font_size.computed_size());
|
||||||
let letter_spacing = if letter_spacing.px() != 0. {
|
let letter_spacing = if letter_spacing.px() != 0. {
|
||||||
Some(app_units::Au::from(letter_spacing))
|
Some(app_units::Au::from(letter_spacing))
|
||||||
} else {
|
} else {
|
||||||
|
@ -384,7 +397,13 @@ impl TextRun {
|
||||||
let style_word_spacing: Option<Au> = specified_word_spacing.to_length().map(|l| l.into());
|
let style_word_spacing: Option<Au> = specified_word_spacing.to_length().map(|l| l.into());
|
||||||
|
|
||||||
let segments = self
|
let segments = self
|
||||||
.segment_text_by_font(formatting_context_text, font_context, font_cache, bidi_info)
|
.segment_text_by_font(
|
||||||
|
formatting_context_text,
|
||||||
|
font_context,
|
||||||
|
font_cache,
|
||||||
|
bidi_info,
|
||||||
|
&parent_style,
|
||||||
|
)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(mut segment, font)| {
|
.map(|(mut segment, font)| {
|
||||||
let word_spacing = style_word_spacing.unwrap_or_else(|| {
|
let word_spacing = style_word_spacing.unwrap_or_else(|| {
|
||||||
|
@ -407,7 +426,7 @@ impl TextRun {
|
||||||
};
|
};
|
||||||
|
|
||||||
segment.shape_text(
|
segment.shape_text(
|
||||||
&self.parent_style,
|
&parent_style,
|
||||||
formatting_context_text,
|
formatting_context_text,
|
||||||
linebreaker,
|
linebreaker,
|
||||||
&shaping_options,
|
&shaping_options,
|
||||||
|
@ -430,8 +449,9 @@ impl TextRun {
|
||||||
font_context: &FontContext,
|
font_context: &FontContext,
|
||||||
font_cache: &mut Vec<FontKeyAndMetrics>,
|
font_cache: &mut Vec<FontKeyAndMetrics>,
|
||||||
bidi_info: &BidiInfo,
|
bidi_info: &BidiInfo,
|
||||||
|
parent_style: &Arc<ComputedValues>,
|
||||||
) -> Vec<(TextRunSegment, FontRef)> {
|
) -> Vec<(TextRunSegment, FontRef)> {
|
||||||
let font_group = font_context.font_group(self.parent_style.clone_font());
|
let font_group = font_context.font_group(parent_style.clone_font());
|
||||||
let mut current: Option<(TextRunSegment, FontRef)> = None;
|
let mut current: Option<(TextRunSegment, FontRef)> = None;
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,6 @@ pub(crate) struct CollapsibleWithParentStartMargin(bool);
|
||||||
/// for a list that has `list-style-position: outside`.
|
/// for a list that has `list-style-position: outside`.
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub(crate) struct OutsideMarker {
|
pub(crate) struct OutsideMarker {
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub list_item_style: Arc<ComputedValues>,
|
pub list_item_style: Arc<ComputedValues>,
|
||||||
pub base: LayoutBoxBase,
|
pub base: LayoutBoxBase,
|
||||||
pub block_container: BlockContainer,
|
pub block_container: BlockContainer,
|
||||||
|
|
|
@ -174,7 +174,7 @@ impl BoxTree {
|
||||||
|
|
||||||
let update_point =
|
let update_point =
|
||||||
match &*AtomicRef::filter_map(layout_data.self_box.borrow(), Option::as_ref)? {
|
match &*AtomicRef::filter_map(layout_data.self_box.borrow(), Option::as_ref)? {
|
||||||
LayoutBox::DisplayContents => return None,
|
LayoutBox::DisplayContents(..) => return None,
|
||||||
LayoutBox::BlockLevel(block_level_box) => match &*block_level_box.borrow() {
|
LayoutBox::BlockLevel(block_level_box) => match &*block_level_box.borrow() {
|
||||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_)
|
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_)
|
||||||
if box_style.position.is_absolutely_positioned() =>
|
if box_style.position.is_absolutely_positioned() =>
|
||||||
|
|
|
@ -17,7 +17,7 @@ use style::properties::ComputedValues;
|
||||||
use style::values::specified::box_::DisplayOutside;
|
use style::values::specified::box_::DisplayOutside;
|
||||||
|
|
||||||
use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment, FragmentFlags};
|
use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment, FragmentFlags};
|
||||||
use crate::ArcRefCell;
|
use crate::SharedStyle;
|
||||||
use crate::display_list::ToWebRender;
|
use crate::display_list::ToWebRender;
|
||||||
use crate::formatting_contexts::Baselines;
|
use crate::formatting_contexts::Baselines;
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
|
@ -40,15 +40,9 @@ pub(crate) enum BackgroundMode {
|
||||||
/// Draw the background normally, getting information from the Fragment style.
|
/// Draw the background normally, getting information from the Fragment style.
|
||||||
Normal,
|
Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, MallocSizeOf)]
|
|
||||||
pub(crate) struct BackgroundStyle(#[conditional_malloc_size_of] pub ServoArc<ComputedValues>);
|
|
||||||
|
|
||||||
pub(crate) type SharedBackgroundStyle = ArcRefCell<BackgroundStyle>;
|
|
||||||
|
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub(crate) struct ExtraBackground {
|
pub(crate) struct ExtraBackground {
|
||||||
pub style: SharedBackgroundStyle,
|
pub style: SharedStyle,
|
||||||
pub rect: PhysicalRect<Au>,
|
pub rect: PhysicalRect<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +58,6 @@ pub(crate) enum SpecificLayoutInfo {
|
||||||
pub(crate) struct BoxFragment {
|
pub(crate) struct BoxFragment {
|
||||||
pub base: BaseFragment,
|
pub base: BaseFragment,
|
||||||
|
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub style: ServoArc<ComputedValues>,
|
pub style: ServoArc<ComputedValues>,
|
||||||
pub children: Vec<Fragment>,
|
pub children: Vec<Fragment>,
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use super::{
|
||||||
Tag,
|
Tag,
|
||||||
};
|
};
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
|
use crate::flow::inline::SharedInlineStyles;
|
||||||
use crate::geom::{LogicalSides, PhysicalPoint, PhysicalRect};
|
use crate::geom::{LogicalSides, PhysicalPoint, PhysicalRect};
|
||||||
use crate::style_ext::ComputedValuesExt;
|
use crate::style_ext::ComputedValuesExt;
|
||||||
|
|
||||||
|
@ -64,8 +65,7 @@ pub(crate) struct CollapsedMargin {
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub(crate) struct TextFragment {
|
pub(crate) struct TextFragment {
|
||||||
pub base: BaseFragment,
|
pub base: BaseFragment,
|
||||||
#[conditional_malloc_size_of]
|
pub inline_styles: SharedInlineStyles,
|
||||||
pub parent_style: ServoArc<ComputedValues>,
|
|
||||||
pub rect: PhysicalRect<Au>,
|
pub rect: PhysicalRect<Au>,
|
||||||
pub font_metrics: FontMetrics,
|
pub font_metrics: FontMetrics,
|
||||||
pub font_key: FontInstanceKey,
|
pub font_key: FontInstanceKey,
|
||||||
|
@ -78,14 +78,11 @@ pub(crate) struct TextFragment {
|
||||||
/// 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>>,
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub selected_style: ServoArc<ComputedValues>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub(crate) struct ImageFragment {
|
pub(crate) struct ImageFragment {
|
||||||
pub base: BaseFragment,
|
pub base: BaseFragment,
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub style: ServoArc<ComputedValues>,
|
pub style: ServoArc<ComputedValues>,
|
||||||
pub rect: PhysicalRect<Au>,
|
pub rect: PhysicalRect<Au>,
|
||||||
pub clip: PhysicalRect<Au>,
|
pub clip: PhysicalRect<Au>,
|
||||||
|
@ -97,7 +94,6 @@ pub(crate) struct IFrameFragment {
|
||||||
pub base: BaseFragment,
|
pub base: BaseFragment,
|
||||||
pub pipeline_id: PipelineId,
|
pub pipeline_id: PipelineId,
|
||||||
pub rect: PhysicalRect<Au>,
|
pub rect: PhysicalRect<Au>,
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub style: ServoArc<ComputedValues>,
|
pub style: ServoArc<ComputedValues>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ pub(crate) struct PositioningFragment {
|
||||||
pub scrollable_overflow: PhysicalRect<Au>,
|
pub scrollable_overflow: PhysicalRect<Au>,
|
||||||
|
|
||||||
/// If this fragment was created with a style, the style of the fragment.
|
/// If this fragment was created with a style, the style of the fragment.
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub style: Option<ServoArc<ComputedValues>>,
|
pub style: Option<ServoArc<ComputedValues>>,
|
||||||
|
|
||||||
/// This [`PositioningFragment`]'s containing block rectangle in coordinates relative to
|
/// This [`PositioningFragment`]'s containing block rectangle in coordinates relative to
|
||||||
|
|
|
@ -27,7 +27,6 @@ use crate::{ConstraintSpace, ContainingBlockSize};
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
pub(crate) struct LayoutBoxBase {
|
pub(crate) struct LayoutBoxBase {
|
||||||
pub base_fragment_info: BaseFragmentInfo,
|
pub base_fragment_info: BaseFragmentInfo,
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub style: Arc<ComputedValues>,
|
pub style: Arc<ComputedValues>,
|
||||||
pub cached_inline_content_size:
|
pub cached_inline_content_size:
|
||||||
AtomicRefCell<Option<Box<(SizeConstraint, InlineContentSizesResult)>>>,
|
AtomicRefCell<Option<Box<(SizeConstraint, InlineContentSizesResult)>>>,
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub use flow::BoxTree;
|
||||||
pub use fragment_tree::FragmentTree;
|
pub use fragment_tree::FragmentTree;
|
||||||
pub use layout_impl::LayoutFactoryImpl;
|
pub use layout_impl::LayoutFactoryImpl;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
|
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 style::values::computed::TextDecorationLine;
|
||||||
|
@ -45,6 +46,16 @@ 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;
|
||||||
|
|
||||||
|
/// At times, a style is "owned" by more than one layout object. For example, text
|
||||||
|
/// fragments need a handle on their parent inline box's style. In order to make
|
||||||
|
/// incremental layout easier to implement, another layer of shared ownership is added via
|
||||||
|
/// [`SharedStyle`]. This allows updating the style in originating layout object and
|
||||||
|
/// having all "depdendent" objects update automatically.
|
||||||
|
///
|
||||||
|
/// Note that this is not a cost-free data structure, so should only be
|
||||||
|
/// used when necessary.
|
||||||
|
pub(crate) type SharedStyle = ArcRefCell<ServoArc<ComputedValues>>;
|
||||||
|
|
||||||
/// Represents the set of constraints that we use when computing the min-content
|
/// Represents the set of constraints that we use when computing the min-content
|
||||||
/// and max-content inline sizes of an element.
|
/// and max-content inline sizes of an element.
|
||||||
pub(crate) struct ConstraintSpace {
|
pub(crate) struct ConstraintSpace {
|
||||||
|
|
|
@ -19,7 +19,6 @@ use super::{
|
||||||
Table, TableCaption, TableLevelBox, TableSlot, TableSlotCell, TableSlotCoordinates,
|
Table, TableCaption, TableLevelBox, TableSlot, TableSlotCell, TableSlotCoordinates,
|
||||||
TableSlotOffset, TableTrack, TableTrackGroup, TableTrackGroupType,
|
TableSlotOffset, TableTrack, TableTrackGroup, TableTrackGroupType,
|
||||||
};
|
};
|
||||||
use crate::PropagatedBoxTreeData;
|
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::dom::{BoxSlot, LayoutBox};
|
use crate::dom::{BoxSlot, LayoutBox};
|
||||||
|
@ -29,9 +28,10 @@ use crate::formatting_contexts::{
|
||||||
IndependentFormattingContext, IndependentFormattingContextContents,
|
IndependentFormattingContext, IndependentFormattingContextContents,
|
||||||
IndependentNonReplacedContents,
|
IndependentNonReplacedContents,
|
||||||
};
|
};
|
||||||
use crate::fragment_tree::{BackgroundStyle, BaseFragmentInfo, SharedBackgroundStyle};
|
use crate::fragment_tree::BaseFragmentInfo;
|
||||||
use crate::layout_box_base::LayoutBoxBase;
|
use crate::layout_box_base::LayoutBoxBase;
|
||||||
use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal};
|
use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal};
|
||||||
|
use crate::{PropagatedBoxTreeData, SharedStyle};
|
||||||
|
|
||||||
/// A reference to a slot and its coordinates in the table
|
/// A reference to a slot and its coordinates in the table
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -725,7 +725,7 @@ impl<'style, 'dom> TableBuilderTraversal<'style, 'dom> {
|
||||||
base: LayoutBoxBase::new((&anonymous_info).into(), style.clone()),
|
base: LayoutBoxBase::new((&anonymous_info).into(), style.clone()),
|
||||||
group_index: self.current_row_group_index,
|
group_index: self.current_row_group_index,
|
||||||
is_anonymous: true,
|
is_anonymous: true,
|
||||||
shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(style)),
|
shared_background_style: SharedStyle::new(style),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,9 +767,7 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
|
||||||
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
||||||
group_type: internal.into(),
|
group_type: internal.into(),
|
||||||
track_range: next_row_index..next_row_index,
|
track_range: next_row_index..next_row_index,
|
||||||
shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
|
shared_background_style: SharedStyle::new(info.style.clone()),
|
||||||
info.style.clone(),
|
|
||||||
)),
|
|
||||||
});
|
});
|
||||||
self.builder.table.row_groups.push(row_group.clone());
|
self.builder.table.row_groups.push(row_group.clone());
|
||||||
|
|
||||||
|
@ -812,9 +810,7 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
|
||||||
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
||||||
group_index: self.current_row_group_index,
|
group_index: self.current_row_group_index,
|
||||||
is_anonymous: false,
|
is_anonymous: false,
|
||||||
shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
|
shared_background_style: SharedStyle::new(info.style.clone()),
|
||||||
info.style.clone(),
|
|
||||||
)),
|
|
||||||
});
|
});
|
||||||
self.push_table_row(row.clone());
|
self.push_table_row(row.clone());
|
||||||
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(row)));
|
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(row)));
|
||||||
|
@ -860,9 +856,7 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
|
||||||
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
base: LayoutBoxBase::new(info.into(), info.style.clone()),
|
||||||
group_type: internal.into(),
|
group_type: internal.into(),
|
||||||
track_range: first_column..self.builder.table.columns.len(),
|
track_range: first_column..self.builder.table.columns.len(),
|
||||||
shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
|
shared_background_style: SharedStyle::new(info.style.clone()),
|
||||||
info.style.clone(),
|
|
||||||
)),
|
|
||||||
});
|
});
|
||||||
self.builder.table.column_groups.push(column_group.clone());
|
self.builder.table.column_groups.push(column_group.clone());
|
||||||
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
|
box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
|
||||||
|
@ -1145,9 +1139,7 @@ fn add_column(
|
||||||
base: LayoutBoxBase::new(column_info.into(), column_info.style.clone()),
|
base: LayoutBoxBase::new(column_info.into(), column_info.style.clone()),
|
||||||
group_index,
|
group_index,
|
||||||
is_anonymous,
|
is_anonymous,
|
||||||
shared_background_style: SharedBackgroundStyle::new(BackgroundStyle(
|
shared_background_style: SharedStyle::new(column_info.style.clone()),
|
||||||
column_info.style.clone(),
|
|
||||||
)),
|
|
||||||
});
|
});
|
||||||
collection.extend(repeat(column.clone()).take(span as usize));
|
collection.extend(repeat(column.clone()).take(span as usize));
|
||||||
column
|
column
|
||||||
|
|
|
@ -82,10 +82,11 @@ use style::properties::style_structs::Font;
|
||||||
use style_traits::dom::OpaqueNode;
|
use style_traits::dom::OpaqueNode;
|
||||||
|
|
||||||
use super::flow::BlockFormattingContext;
|
use super::flow::BlockFormattingContext;
|
||||||
|
use crate::SharedStyle;
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::flow::BlockContainer;
|
use crate::flow::BlockContainer;
|
||||||
use crate::formatting_contexts::IndependentFormattingContext;
|
use crate::formatting_contexts::IndependentFormattingContext;
|
||||||
use crate::fragment_tree::{BaseFragmentInfo, Fragment, SharedBackgroundStyle};
|
use crate::fragment_tree::{BaseFragmentInfo, Fragment};
|
||||||
use crate::geom::PhysicalVec;
|
use crate::geom::PhysicalVec;
|
||||||
use crate::layout_box_base::LayoutBoxBase;
|
use crate::layout_box_base::LayoutBoxBase;
|
||||||
use crate::style_ext::BorderStyleColor;
|
use crate::style_ext::BorderStyleColor;
|
||||||
|
@ -98,12 +99,10 @@ pub struct Table {
|
||||||
/// The style of this table. These are the properties that apply to the "wrapper" ie the element
|
/// The style of this table. These are the properties that apply to the "wrapper" ie the element
|
||||||
/// that contains both the grid and the captions. Not all properties are actually used on the
|
/// that contains both the grid and the captions. Not all properties are actually used on the
|
||||||
/// wrapper though, such as background and borders, which apply to the grid.
|
/// wrapper though, such as background and borders, which apply to the grid.
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
style: Arc<ComputedValues>,
|
style: Arc<ComputedValues>,
|
||||||
|
|
||||||
/// The style of this table's grid. This is an anonymous style based on the table's style, but
|
/// The style of this table's grid. This is an anonymous style based on the table's style, but
|
||||||
/// eliminating all the properties handled by the "wrapper."
|
/// eliminating all the properties handled by the "wrapper."
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
grid_style: Arc<ComputedValues>,
|
grid_style: Arc<ComputedValues>,
|
||||||
|
|
||||||
/// The [`BaseFragmentInfo`] for this table's grid. This is necessary so that when the
|
/// The [`BaseFragmentInfo`] for this table's grid. This is necessary so that when the
|
||||||
|
@ -292,7 +291,7 @@ pub struct TableTrack {
|
||||||
/// A shared container for this track's style, used to share the style for the purposes
|
/// A shared container for this track's style, used to share the style for the purposes
|
||||||
/// of drawing backgrounds in individual cells. This allows updating the style in a
|
/// of drawing backgrounds in individual cells. This allows updating the style in a
|
||||||
/// single place and having it affect all cell `Fragment`s.
|
/// single place and having it affect all cell `Fragment`s.
|
||||||
shared_background_style: SharedBackgroundStyle,
|
shared_background_style: SharedStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, MallocSizeOf, PartialEq)]
|
#[derive(Debug, MallocSizeOf, PartialEq)]
|
||||||
|
@ -317,7 +316,7 @@ pub struct TableTrackGroup {
|
||||||
/// A shared container for this track's style, used to share the style for the purposes
|
/// A shared container for this track's style, used to share the style for the purposes
|
||||||
/// of drawing backgrounds in individual cells. This allows updating the style in a
|
/// of drawing backgrounds in individual cells. This allows updating the style in a
|
||||||
/// single place and having it affect all cell `Fragment`s.
|
/// single place and having it affect all cell `Fragment`s.
|
||||||
shared_background_style: SharedBackgroundStyle,
|
shared_background_style: SharedStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableTrackGroup {
|
impl TableTrackGroup {
|
||||||
|
|
|
@ -24,7 +24,6 @@ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub(crate) struct TaffyContainer {
|
pub(crate) struct TaffyContainer {
|
||||||
children: Vec<ArcRefCell<TaffyItemBox>>,
|
children: Vec<ArcRefCell<TaffyItemBox>>,
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
style: Arc<ComputedValues>,
|
style: Arc<ComputedValues>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +75,6 @@ pub(crate) struct TaffyItemBox {
|
||||||
pub(crate) taffy_layout: taffy::Layout,
|
pub(crate) taffy_layout: taffy::Layout,
|
||||||
pub(crate) child_fragments: Vec<Fragment>,
|
pub(crate) child_fragments: Vec<Fragment>,
|
||||||
pub(crate) positioning_context: PositioningContext,
|
pub(crate) positioning_context: PositioningContext,
|
||||||
#[conditional_malloc_size_of]
|
|
||||||
pub(crate) style: Arc<ComputedValues>,
|
pub(crate) style: Arc<ComputedValues>,
|
||||||
pub(crate) taffy_level_box: TaffyItemBoxInner,
|
pub(crate) taffy_level_box: TaffyItemBoxInner,
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use style::properties::ComputedValues;
|
||||||
use style::values::generics::length::GenericLengthPercentageOrAuto;
|
use style::values::generics::length::GenericLengthPercentageOrAuto;
|
||||||
pub use stylo_malloc_size_of::MallocSizeOfOps;
|
pub use stylo_malloc_size_of::MallocSizeOfOps;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -750,6 +751,12 @@ impl<T: MallocSizeOf> MallocSizeOf for accountable_refcell::RefCell<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MallocSizeOf for servo_arc::Arc<ComputedValues> {
|
||||||
|
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
self.conditional_size_of(ops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
malloc_size_of_hash_map!(indexmap::IndexMap<K, V, S>);
|
malloc_size_of_hash_map!(indexmap::IndexMap<K, V, S>);
|
||||||
malloc_size_of_hash_set!(indexmap::IndexSet<T, S>);
|
malloc_size_of_hash_set!(indexmap::IndexSet<T, S>);
|
||||||
|
|
||||||
|
|
13
tests/wpt/meta/MANIFEST.json
vendored
13
tests/wpt/meta/MANIFEST.json
vendored
|
@ -167223,6 +167223,19 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"display-contents-inline-002.html": [
|
||||||
|
"f40a34129f348aca37fca83f70598053cf22785b",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/css-display/display-contents-pass-no-red-ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"display-contents-inline-flex-001.html": [
|
"display-contents-inline-flex-001.html": [
|
||||||
"43b502731aefbaa348671e32171f0e1eb4bca04b",
|
"43b502731aefbaa348671e32171f0e1eb4bca04b",
|
||||||
[
|
[
|
||||||
|
|
18
tests/wpt/tests/css/css-display/display-contents-inline-002.html
vendored
Normal file
18
tests/wpt/tests/css/css-display/display-contents-inline-002.html
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Display: display:contents in inline layout should affect style of descendants</title>
|
||||||
|
<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
|
||||||
|
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-contents">
|
||||||
|
<link rel="match" href="display-contents-pass-no-red-ref.html">
|
||||||
|
<style>
|
||||||
|
#contents {
|
||||||
|
display: contents;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.red { color: red; }
|
||||||
|
</style>
|
||||||
|
<p>You should see the word PASS and no red below.</p>
|
||||||
|
<span>
|
||||||
|
P<span class="red"><div id="contents">AS</div></span>S
|
||||||
|
</span>
|
Loading…
Add table
Add a link
Reference in a new issue