diff options
Diffstat (limited to 'components/layout')
-rw-r--r-- | components/layout/display_list/mod.rs | 22 | ||||
-rw-r--r-- | components/layout/dom.rs | 71 | ||||
-rw-r--r-- | components/layout/dom_traversal.rs | 9 | ||||
-rw-r--r-- | components/layout/flexbox/mod.rs | 22 | ||||
-rw-r--r-- | components/layout/flow/inline/construct.rs | 6 | ||||
-rw-r--r-- | components/layout/flow/inline/inline_box.rs | 14 | ||||
-rw-r--r-- | components/layout/flow/inline/mod.rs | 55 | ||||
-rw-r--r-- | components/layout/flow/mod.rs | 57 | ||||
-rw-r--r-- | components/layout/flow/root.rs | 6 | ||||
-rw-r--r-- | components/layout/formatting_contexts.rs | 28 | ||||
-rw-r--r-- | components/layout/fragment_tree/fragment.rs | 19 | ||||
-rw-r--r-- | components/layout/fragment_tree/positioning_fragment.rs | 16 | ||||
-rw-r--r-- | components/layout/layout_box_base.rs | 7 | ||||
-rw-r--r-- | components/layout/layout_impl.rs | 10 | ||||
-rw-r--r-- | components/layout/positioned.rs | 287 | ||||
-rw-r--r-- | components/layout/table/layout.rs | 1 | ||||
-rw-r--r-- | components/layout/table/mod.rs | 50 | ||||
-rw-r--r-- | components/layout/taffy/mod.rs | 22 | ||||
-rw-r--r-- | components/layout/traversal.rs | 82 |
19 files changed, 568 insertions, 216 deletions
diff --git a/components/layout/display_list/mod.rs b/components/layout/display_list/mod.rs index 9990528911c..f017642908d 100644 --- a/components/layout/display_list/mod.rs +++ b/components/layout/display_list/mod.rs @@ -471,18 +471,16 @@ impl Fragment { Fragment::AbsoluteOrFixedPositioned(_) => {}, Fragment::Positioning(positioning_fragment) => { let positioning_fragment = positioning_fragment.borrow(); - if let Some(style) = positioning_fragment.style.as_ref() { - let rect = positioning_fragment - .rect - .translate(containing_block.origin.to_vector()); - self.maybe_push_hit_test_for_style_and_tag( - builder, - style, - positioning_fragment.base.tag, - rect, - Cursor::Default, - ); - } + let rect = positioning_fragment + .rect + .translate(containing_block.origin.to_vector()); + self.maybe_push_hit_test_for_style_and_tag( + builder, + &positioning_fragment.style, + positioning_fragment.base.tag, + rect, + Cursor::Default, + ); }, Fragment::Image(image) => { let image = image.borrow(); diff --git a/components/layout/dom.rs b/components/layout/dom.rs index faedf608749..e3a22eb5197 100644 --- a/components/layout/dom.rs +++ b/components/layout/dom.rs @@ -19,11 +19,11 @@ use script_layout_interface::{ GenericLayoutDataTrait, LayoutElementType, LayoutNodeType as ScriptLayoutNodeType, }; use servo_arc::Arc as ServoArc; +use style::context::SharedStyleContext; use style::properties::ComputedValues; use style::selector_parser::PseudoElement; use crate::cell::ArcRefCell; -use crate::context::LayoutContext; use crate::flexbox::FlexLevelBox; use crate::flow::BlockLevelBox; use crate::flow::inline::{InlineItem, SharedInlineStyles}; @@ -102,6 +102,41 @@ impl LayoutBox { LayoutBox::TableLevelBox(table_box) => table_box.fragments(), } } + + fn repair_style( + &self, + context: &SharedStyleContext, + node: &ServoLayoutNode, + new_style: &ServoArc<ComputedValues>, + ) { + match self { + LayoutBox::DisplayContents(inline_shared_styles) => { + *inline_shared_styles.style.borrow_mut() = new_style.clone(); + *inline_shared_styles.selected.borrow_mut() = node.to_threadsafe().selected_style(); + }, + LayoutBox::BlockLevel(block_level_box) => { + block_level_box + .borrow_mut() + .repair_style(context, node, new_style); + }, + LayoutBox::InlineLevel(inline_items) => { + for inline_item in inline_items { + inline_item + .borrow_mut() + .repair_style(context, node, new_style); + } + }, + LayoutBox::FlexLevel(flex_level_box) => { + flex_level_box.borrow_mut().repair_style(context, new_style) + }, + LayoutBox::TableLevelBox(table_level_box) => { + table_level_box.repair_style(context, new_style) + }, + LayoutBox::TaffyItemBox(taffy_item_box) => { + taffy_item_box.borrow_mut().repair_style(context, new_style) + }, + } + } } /// A wrapper for [`InnerDOMLayoutData`]. This is necessary to give the entire data @@ -167,7 +202,7 @@ pub(crate) trait NodeExt<'dom> { fn as_iframe(&self) -> Option<(PipelineId, BrowsingContextId)>; fn as_video(&self) -> Option<(Option<webrender_api::ImageKey>, Option<PhysicalSize<f64>>)>; fn as_typeless_object_with_data_attribute(&self) -> Option<String>; - fn style(&self, context: &LayoutContext) -> ServoArc<ComputedValues>; + fn style(&self, context: &SharedStyleContext) -> ServoArc<ComputedValues>; fn layout_data_mut(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>; fn layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>; @@ -180,6 +215,8 @@ pub(crate) trait NodeExt<'dom> { fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>; fn invalidate_cached_fragment(&self); + + fn repair_style(&self, context: &SharedStyleContext); } impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> { @@ -253,8 +290,8 @@ impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> { .map(|string| string.to_owned()) } - fn style(&self, context: &LayoutContext) -> ServoArc<ComputedValues> { - self.to_threadsafe().style(context.shared_context()) + fn style(&self, context: &SharedStyleContext) -> ServoArc<ComputedValues> { + self.to_threadsafe().style(context) } fn layout_data_mut(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> { @@ -339,4 +376,30 @@ impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> { }) .unwrap_or_default() } + + fn repair_style(&self, context: &SharedStyleContext) { + let data = self.layout_data_mut(); + if let Some(layout_object) = &*data.self_box.borrow() { + let style = self.to_threadsafe().style(context); + layout_object.repair_style(context, self, &style); + } + + if let Some(layout_object) = &*data.pseudo_before_box.borrow() { + if let Some(node) = self.to_threadsafe().with_pseudo(PseudoElement::Before) { + layout_object.repair_style(context, self, &node.style(context)); + } + } + + if let Some(layout_object) = &*data.pseudo_after_box.borrow() { + if let Some(node) = self.to_threadsafe().with_pseudo(PseudoElement::After) { + layout_object.repair_style(context, self, &node.style(context)); + } + } + + if let Some(layout_object) = &*data.pseudo_marker_box.borrow() { + if let Some(node) = self.to_threadsafe().with_pseudo(PseudoElement::Marker) { + layout_object.repair_style(context, self, &node.style(context)); + } + } + } } diff --git a/components/layout/dom_traversal.rs b/components/layout/dom_traversal.rs index d9019bbf8e0..0201d72dbe2 100644 --- a/components/layout/dom_traversal.rs +++ b/components/layout/dom_traversal.rs @@ -212,7 +212,10 @@ fn traverse_children_of<'dom>( ); if is_text_input_element || is_textarea_element { - let info = NodeAndStyleInfo::new(parent_element, parent_element.style(context)); + let info = NodeAndStyleInfo::new( + parent_element, + parent_element.style(context.shared_context()), + ); let node_text_content = parent_element.to_threadsafe().node_text_content(); if node_text_content.is_empty() { // The addition of zero-width space here forces the text input to have an inline formatting @@ -231,7 +234,7 @@ fn traverse_children_of<'dom>( if !is_text_input_element && !is_textarea_element { for child in iter_child_nodes(parent_element) { if child.is_text_node() { - let info = NodeAndStyleInfo::new(child, child.style(context)); + let info = NodeAndStyleInfo::new(child, child.style(context.shared_context())); handler.handle_text(&info, child.to_threadsafe().node_text_content()); } else if child.is_element() { traverse_element(child, context, handler); @@ -252,7 +255,7 @@ fn traverse_element<'dom>( element.unset_pseudo_element_box(PseudoElement::Marker); let replaced = ReplacedContents::for_element(element, context); - let style = element.style(context); + let style = element.style(context.shared_context()); match Display::from(style.get_box().display) { Display::None => element.unset_all_boxes(), Display::Contents => { diff --git a/components/layout/flexbox/mod.rs b/components/layout/flexbox/mod.rs index 737b15de25b..91a12b31812 100644 --- a/components/layout/flexbox/mod.rs +++ b/components/layout/flexbox/mod.rs @@ -5,6 +5,7 @@ use geom::{FlexAxis, MainStartCrossStart}; use malloc_size_of_derive::MallocSizeOf; use servo_arc::Arc as ServoArc; +use style::context::SharedStyleContext; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; use style::properties::longhands::align_items::computed_value::T as AlignItems; @@ -136,6 +137,11 @@ impl FlexContainer { config: FlexContainerConfig::new(&info.style), } } + + pub(crate) fn repair_style(&mut self, new_style: &ServoArc<ComputedValues>) { + self.config = FlexContainerConfig::new(new_style); + self.style = new_style.clone(); + } } #[derive(Debug, MallocSizeOf)] @@ -145,6 +151,22 @@ pub(crate) enum FlexLevelBox { } impl FlexLevelBox { + pub(crate) fn repair_style( + &mut self, + context: &SharedStyleContext, + new_style: &ServoArc<ComputedValues>, + ) { + match self { + FlexLevelBox::FlexItem(flex_item_box) => flex_item_box + .independent_formatting_context + .repair_style(context, new_style), + FlexLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box + .borrow_mut() + .context + .repair_style(context, new_style), + } + } + pub(crate) fn invalidate_cached_fragment(&self) { match self { FlexLevelBox::FlexItem(flex_item_box) => flex_item_box diff --git a/components/layout/flow/inline/construct.rs b/components/layout/flow/inline/construct.rs index 42d80059ab2..a99de1679a4 100644 --- a/components/layout/flow/inline/construct.rs +++ b/components/layout/flow/inline/construct.rs @@ -7,7 +7,6 @@ use std::char::{ToLowercase, ToUppercase}; use icu_segmenter::WordSegmenter; use itertools::izip; -use servo_arc::Arc; use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse; use style::values::specified::text::TextTransformCase; use unicode_bidi::Level; @@ -158,7 +157,7 @@ impl InlineFormattingContextBuilder { independent_formatting_context: IndependentFormattingContext, ) -> ArcRefCell<InlineItem> { let inline_level_box = ArcRefCell::new(InlineItem::Atomic( - Arc::new(independent_formatting_context), + ArcRefCell::new(independent_formatting_context), self.current_text_offset, Level::ltr(), /* This will be assigned later if necessary. */ )); @@ -189,7 +188,8 @@ impl InlineFormattingContextBuilder { } pub(crate) fn push_float_box(&mut self, float_box: FloatBox) -> ArcRefCell<InlineItem> { - let inline_level_box = ArcRefCell::new(InlineItem::OutOfFlowFloatBox(Arc::new(float_box))); + let inline_level_box = + ArcRefCell::new(InlineItem::OutOfFlowFloatBox(ArcRefCell::new(float_box))); self.inline_items.push(inline_level_box.clone()); self.contains_floats = true; inline_level_box diff --git a/components/layout/flow/inline/inline_box.rs b/components/layout/flow/inline/inline_box.rs index 0ff58b6a6f3..b547f3b5935 100644 --- a/components/layout/flow/inline/inline_box.rs +++ b/components/layout/flow/inline/inline_box.rs @@ -7,6 +7,10 @@ use std::vec::IntoIter; use app_units::Au; use fonts::FontMetrics; use malloc_size_of_derive::MallocSizeOf; +use script::layout_dom::ServoLayoutNode; +use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; +use servo_arc::Arc as ServoArc; +use style::properties::ComputedValues; use super::{ InlineContainerState, InlineContainerStateFlags, SharedInlineStyles, @@ -66,6 +70,16 @@ impl InlineBox { pub(crate) fn layout_style(&self) -> LayoutStyle { LayoutStyle::Default(&self.base.style) } + + pub(crate) fn repair_style( + &mut self, + node: &ServoLayoutNode, + new_style: &ServoArc<ComputedValues>, + ) { + self.base.repair_style(new_style); + *self.shared_inline_styles.style.borrow_mut() = new_style.clone(); + *self.shared_inline_styles.selected.borrow_mut() = node.to_threadsafe().selected_style(); + } } #[derive(Debug, Default, MallocSizeOf)] diff --git a/components/layout/flow/inline/mod.rs b/components/layout/flow/inline/mod.rs index d623eb4a3d8..7e69aa1aaae 100644 --- a/components/layout/flow/inline/mod.rs +++ b/components/layout/flow/inline/mod.rs @@ -90,12 +90,13 @@ use line::{ use line_breaker::LineBreaker; use malloc_size_of_derive::MallocSizeOf; use range::Range; +use script::layout_dom::ServoLayoutNode; use servo_arc::Arc; use style::Zero; use style::computed_values::text_wrap_mode::T as TextWrapMode; use style::computed_values::vertical_align::T as VerticalAlign; use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse; -use style::context::QuirksMode; +use style::context::{QuirksMode, SharedStyleContext}; use style::properties::ComputedValues; use style::properties::style_structs::InheritedText; use style::values::generics::box_::VerticalAlignKeyword; @@ -210,15 +211,41 @@ pub(crate) enum InlineItem { ArcRefCell<AbsolutelyPositionedBox>, usize, /* offset_in_text */ ), - OutOfFlowFloatBox(#[conditional_malloc_size_of] Arc<FloatBox>), + OutOfFlowFloatBox(ArcRefCell<FloatBox>), Atomic( - #[conditional_malloc_size_of] Arc<IndependentFormattingContext>, + ArcRefCell<IndependentFormattingContext>, usize, /* offset_in_text */ Level, /* bidi_level */ ), } impl InlineItem { + pub(crate) fn repair_style( + &self, + context: &SharedStyleContext, + node: &ServoLayoutNode, + new_style: &Arc<ComputedValues>, + ) { + match self { + InlineItem::StartInlineBox(inline_box) => { + inline_box.borrow_mut().repair_style(node, new_style); + }, + InlineItem::EndInlineBox => {}, + // TextRun holds a handle the `InlineSharedStyles` which is updated when repairing inline box + // and `display: contents` styles. + InlineItem::TextRun(..) => {}, + InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => positioned_box + .borrow_mut() + .context + .repair_style(context, new_style), + InlineItem::OutOfFlowFloatBox(float_box) => float_box + .borrow_mut() + .contents + .repair_style(context, new_style), + InlineItem::Atomic(atomic, ..) => atomic.borrow_mut().repair_style(context, new_style), + } + } + pub(crate) fn invalidate_cached_fragment(&self) { match self { InlineItem::StartInlineBox(inline_box) => { @@ -232,11 +259,14 @@ impl InlineItem { .base .invalidate_cached_fragment(); }, - InlineItem::OutOfFlowFloatBox(float_box) => { - float_box.contents.base.invalidate_cached_fragment() - }, + InlineItem::OutOfFlowFloatBox(float_box) => float_box + .borrow() + .contents + .base + .invalidate_cached_fragment(), InlineItem::Atomic(independent_formatting_context, ..) => { independent_formatting_context + .borrow() .base .invalidate_cached_fragment(); }, @@ -252,9 +282,11 @@ impl InlineItem { InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => { positioned_box.borrow().context.base.fragments() }, - InlineItem::OutOfFlowFloatBox(float_box) => float_box.contents.base.fragments(), + InlineItem::OutOfFlowFloatBox(float_box) => { + float_box.borrow().contents.base.fragments() + }, InlineItem::Atomic(independent_formatting_context, ..) => { - independent_formatting_context.base.fragments() + independent_formatting_context.borrow().base.fragments() }, } } @@ -978,6 +1010,7 @@ impl InlineFormattingContextLayout<'_> { .as_physical(Some(self.containing_block)); self.fragments .push(Fragment::Positioning(PositioningFragment::new_anonymous( + self.root_nesting_level.style.clone(), physical_line_rect, fragments, ))); @@ -1770,7 +1803,7 @@ impl InlineFormattingContext { InlineItem::EndInlineBox => layout.finish_inline_box(), InlineItem::TextRun(run) => run.borrow().layout_into_line_items(&mut layout), InlineItem::Atomic(atomic_formatting_context, offset_in_text, bidi_level) => { - atomic_formatting_context.layout_into_line_items( + atomic_formatting_context.borrow().layout_into_line_items( &mut layout, *offset_in_text, *bidi_level, @@ -1785,7 +1818,7 @@ impl InlineFormattingContext { )); }, InlineItem::OutOfFlowFloatBox(float_box) => { - float_box.layout_into_line_items(&mut layout); + float_box.borrow().layout_into_line_items(&mut layout); }, } } @@ -2448,7 +2481,7 @@ impl<'layout_data> ContentSizesComputation<'layout_data> { let InlineContentSizesResult { sizes: outer, depends_on_block_constraints, - } = atomic.outer_inline_content_sizes( + } = atomic.borrow().outer_inline_content_sizes( self.layout_context, &self.constraint_space.into(), &LogicalVec2::zero(), diff --git a/components/layout/flow/mod.rs b/components/layout/flow/mod.rs index 17a952d24cb..6adb63153d6 100644 --- a/components/layout/flow/mod.rs +++ b/components/layout/flow/mod.rs @@ -9,9 +9,11 @@ use app_units::{Au, MAX_AU}; use inline::InlineFormattingContext; use malloc_size_of_derive::MallocSizeOf; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; +use script::layout_dom::ServoLayoutNode; use servo_arc::Arc; use style::Zero; use style::computed_values::clear::T as StyleClear; +use style::context::SharedStyleContext; use style::logical_geometry::Direction; use style::properties::ComputedValues; use style::servo::selector_parser::PseudoElement; @@ -21,6 +23,7 @@ use style::values::specified::{Display, TextAlignKeyword}; use crate::cell::ArcRefCell; use crate::context::LayoutContext; +use crate::dom::NodeExt; use crate::flow::float::{ Clear, ContainingBlockPositionInfo, FloatBox, FloatSide, PlacementAmongFloats, SequentialLayoutState, @@ -91,6 +94,36 @@ pub(crate) enum BlockLevelBox { } impl BlockLevelBox { + pub(crate) fn repair_style( + &mut self, + context: &SharedStyleContext, + node: &ServoLayoutNode, + new_style: &Arc<ComputedValues>, + ) { + self.with_base_mut(|base| { + base.repair_style(new_style); + }); + + match self { + BlockLevelBox::Independent(independent_formatting_context) => { + independent_formatting_context.repair_style(context, new_style) + }, + BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box + .borrow_mut() + .context + .repair_style(context, new_style), + BlockLevelBox::OutOfFlowFloatBox(float_box) => { + float_box.contents.repair_style(context, new_style) + }, + BlockLevelBox::OutsideMarker(outside_marker) => { + outside_marker.repair_style(context, node, new_style) + }, + BlockLevelBox::SameFormattingContextBlock { base, .. } => { + base.repair_style(new_style); + }, + } + } + pub(crate) fn invalidate_cached_fragment(&self) { self.with_base(LayoutBoxBase::invalidate_cached_fragment); } @@ -113,6 +146,20 @@ impl BlockLevelBox { } } + pub(crate) fn with_base_mut<T>(&mut self, callback: impl Fn(&mut LayoutBoxBase) -> T) -> T { + match self { + BlockLevelBox::Independent(independent_formatting_context) => { + callback(&mut independent_formatting_context.base) + }, + BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => { + callback(&mut positioned_box.borrow_mut().context.base) + }, + BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&mut float_box.contents.base), + BlockLevelBox::OutsideMarker(outside_marker) => callback(&mut outside_marker.base), + BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base), + } + } + fn contains_floats(&self) -> bool { match self { BlockLevelBox::SameFormattingContextBlock { @@ -360,6 +407,16 @@ impl OutsideMarker { None, ))) } + + fn repair_style( + &mut self, + context: &SharedStyleContext, + node: &ServoLayoutNode, + new_style: &Arc<ComputedValues>, + ) { + self.list_item_style = node.style(context); + self.base.repair_style(new_style); + } } impl BlockFormattingContext { diff --git a/components/layout/flow/root.rs b/components/layout/flow/root.rs index b367b20c881..a37db54065d 100644 --- a/components/layout/flow/root.rs +++ b/components/layout/flow/root.rs @@ -59,7 +59,7 @@ impl BoxTree { // > none, user agents must instead apply the overflow-* values of the first such child // > element to the viewport. The element from which the value is propagated must then have a // > used overflow value of visible. - let root_style = root_element.style(context); + let root_style = root_element.style(context.shared_context()); let mut viewport_overflow_x = root_style.clone_overflow_x(); let mut viewport_overflow_y = root_style.clone_overflow_y(); @@ -76,7 +76,7 @@ impl BoxTree { continue; } - let style = child.style(context); + let style = child.style(context.shared_context()); if !style.get_box().display.is_none() { viewport_overflow_x = style.clone_overflow_x(); viewport_overflow_y = style.clone_overflow_y(); @@ -293,7 +293,7 @@ fn construct_for_root_element( context: &LayoutContext, root_element: ServoLayoutNode<'_>, ) -> Vec<ArcRefCell<BlockLevelBox>> { - let info = NodeAndStyleInfo::new(root_element, root_element.style(context)); + let info = NodeAndStyleInfo::new(root_element, root_element.style(context.shared_context())); let box_style = info.style.get_box(); let display_inside = match Display::from(box_style.display) { diff --git a/components/layout/formatting_contexts.rs b/components/layout/formatting_contexts.rs index 04a8c60f692..d704011d0e7 100644 --- a/components/layout/formatting_contexts.rs +++ b/components/layout/formatting_contexts.rs @@ -6,6 +6,7 @@ use app_units::Au; use malloc_size_of_derive::MallocSizeOf; use script::layout_dom::ServoLayoutElement; use servo_arc::Arc; +use style::context::SharedStyleContext; use style::properties::ComputedValues; use style::selector_parser::PseudoElement; @@ -217,6 +218,20 @@ impl IndependentFormattingContext { }, } } + + pub(crate) fn repair_style( + &mut self, + context: &SharedStyleContext, + new_style: &Arc<ComputedValues>, + ) { + self.base.repair_style(new_style); + match &mut self.contents { + IndependentFormattingContextContents::NonReplaced(content) => { + content.repair_style(context, new_style); + }, + IndependentFormattingContextContents::Replaced(..) => {}, + } + } } impl IndependentNonReplacedContents { @@ -334,6 +349,19 @@ impl IndependentNonReplacedContents { pub(crate) fn is_table(&self) -> bool { matches!(self, Self::Table(_)) } + + fn repair_style(&mut self, context: &SharedStyleContext, new_style: &Arc<ComputedValues>) { + match self { + IndependentNonReplacedContents::Flow(..) => {}, + IndependentNonReplacedContents::Flex(flex_container) => { + flex_container.repair_style(new_style) + }, + IndependentNonReplacedContents::Grid(taffy_container) => { + taffy_container.repair_style(new_style) + }, + IndependentNonReplacedContents::Table(table) => table.repair_style(context, new_style), + } + } } impl ComputeInlineContentSizes for IndependentNonReplacedContents { diff --git a/components/layout/fragment_tree/fragment.rs b/components/layout/fragment_tree/fragment.rs index f67da133031..1ebc7b3c989 100644 --- a/components/layout/fragment_tree/fragment.rs +++ b/components/layout/fragment_tree/fragment.rs @@ -304,6 +304,25 @@ impl Fragment { _ => None, } } + + pub(crate) fn repair_style(&self, style: &ServoArc<ComputedValues>) { + match self { + Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => { + box_fragment.borrow_mut().style = style.clone() + }, + Fragment::Positioning(positioning_fragment) => { + positioning_fragment.borrow_mut().style = style.clone(); + }, + Fragment::AbsoluteOrFixedPositioned(positioned_fragment) => { + if let Some(ref fragment) = positioned_fragment.borrow().fragment { + fragment.repair_style(style); + } + }, + Fragment::Text(..) => unreachable!("Should never try to repair style of TextFragment"), + Fragment::Image(image_fragment) => image_fragment.borrow_mut().style = style.clone(), + Fragment::IFrame(iframe_fragment) => iframe_fragment.borrow_mut().style = style.clone(), + } + } } impl TextFragment { diff --git a/components/layout/fragment_tree/positioning_fragment.rs b/components/layout/fragment_tree/positioning_fragment.rs index 803a154ba83..e45a6137bff 100644 --- a/components/layout/fragment_tree/positioning_fragment.rs +++ b/components/layout/fragment_tree/positioning_fragment.rs @@ -24,8 +24,8 @@ pub(crate) struct PositioningFragment { /// The scrollable overflow of this anonymous fragment's children. pub scrollable_overflow: PhysicalRect<Au>, - /// If this fragment was created with a style, the style of the fragment. - pub style: Option<ServoArc<ComputedValues>>, + /// The style of the fragment. + pub style: ServoArc<ComputedValues>, /// This [`PositioningFragment`]'s containing block rectangle in coordinates relative to /// the initial containing block, but not taking into account any transforms. @@ -33,8 +33,12 @@ pub(crate) struct PositioningFragment { } impl PositioningFragment { - pub fn new_anonymous(rect: PhysicalRect<Au>, children: Vec<Fragment>) -> ArcRefCell<Self> { - Self::new_with_base_fragment(BaseFragment::anonymous(), None, rect, children) + pub fn new_anonymous( + style: ServoArc<ComputedValues>, + rect: PhysicalRect<Au>, + children: Vec<Fragment>, + ) -> ArcRefCell<Self> { + Self::new_with_base_fragment(BaseFragment::anonymous(), style, rect, children) } pub fn new_empty( @@ -42,12 +46,12 @@ impl PositioningFragment { rect: PhysicalRect<Au>, style: ServoArc<ComputedValues>, ) -> ArcRefCell<Self> { - Self::new_with_base_fragment(base_fragment_info.into(), Some(style), rect, Vec::new()) + Self::new_with_base_fragment(base_fragment_info.into(), style, rect, Vec::new()) } fn new_with_base_fragment( base: BaseFragment, - style: Option<ServoArc<ComputedValues>>, + style: ServoArc<ComputedValues>, rect: PhysicalRect<Au>, children: Vec<Fragment>, ) -> ArcRefCell<Self> { diff --git a/components/layout/layout_box_base.rs b/components/layout/layout_box_base.rs index d025a627aef..161aee0f9bb 100644 --- a/components/layout/layout_box_base.rs +++ b/components/layout/layout_box_base.rs @@ -89,6 +89,13 @@ impl LayoutBoxBase { pub(crate) fn clear_fragments(&self) { self.fragments.borrow_mut().clear(); } + + pub(crate) fn repair_style(&mut self, new_style: &Arc<ComputedValues>) { + self.style = new_style.clone(); + for fragment in self.fragments.borrow_mut().iter_mut() { + fragment.repair_style(new_style); + } + } } impl Debug for LayoutBoxBase { diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index cdf76d3fed0..fcf658036b2 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -56,7 +56,7 @@ use style::media_queries::{Device, MediaList, MediaType}; use style::properties::style_structs::Font; use style::properties::{ComputedValues, PropertyId}; use style::queries::values::PrefersColorScheme; -use style::selector_parser::{PseudoElement, SnapshotMap}; +use style::selector_parser::{PseudoElement, RestyleDamage, SnapshotMap}; use style::servo::media_queries::FontMetricsProvider; use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards}; use style::stylesheets::{ @@ -83,7 +83,7 @@ use crate::query::{ process_content_boxes_request, process_node_scroll_area_request, process_offset_parent_query, process_resolved_font_style_query, process_resolved_style_request, process_text_index_request, }; -use crate::traversal::RecalcStyle; +use crate::traversal::{RecalcStyle, compute_damage_and_repair_style}; use crate::{BoxTree, FragmentTree}; // This mutex is necessary due to syncronisation issues between two different types of thread-local storage @@ -765,6 +765,12 @@ impl LayoutThread { driver::traverse_dom(&recalc_style_traversal, token, rayon_pool).as_node(); let root_node = root_element.as_node(); + let damage = compute_damage_and_repair_style(layout_context.shared_context(), root_node); + if damage == RestyleDamage::REPAINT { + layout_context.style_context.stylist.rule_tree().maybe_gc(); + return; + } + let mut box_tree = self.box_tree.borrow_mut(); let box_tree = &mut *box_tree; let mut build_box_tree = || { diff --git a/components/layout/positioned.rs b/components/layout/positioned.rs index bb5386dc696..b607462d6eb 100644 --- a/components/layout/positioned.rs +++ b/components/layout/positioned.rs @@ -473,7 +473,7 @@ impl HoistedAbsolutelyPositionedBox { false => shared_fragment.resolved_alignment.inline, }; - let mut inline_axis_solver = AbsoluteAxisSolver { + let inline_axis_solver = AbsoluteAxisSolver { axis: Direction::Inline, containing_size: cbis, padding_border_sum: pbm.padding_border_sums.inline, @@ -496,7 +496,7 @@ impl HoistedAbsolutelyPositionedBox { true => style.clone_align_self().0.0, false => shared_fragment.resolved_alignment.block, }; - let mut block_axis_solver = AbsoluteAxisSolver { + let block_axis_solver = AbsoluteAxisSolver { axis: Direction::Block, containing_size: cbbs, padding_border_sum: pbm.padding_border_sums.block, @@ -511,52 +511,6 @@ impl HoistedAbsolutelyPositionedBox { is_table, }; - if let IndependentFormattingContextContents::Replaced(replaced) = &context.contents { - // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width - // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height - let inset_sums = LogicalVec2 { - inline: inline_axis_solver.inset_sum(), - block: block_axis_solver.inset_sum(), - }; - let automatic_size = |alignment: AlignFlags, offsets: &LogicalSides1D<_>| { - if alignment.value() == AlignFlags::STRETCH && !offsets.either_auto() { - Size::Stretch - } else { - Size::FitContent - } - }; - let used_size = replaced.used_size_as_if_inline_element_from_content_box_sizes( - containing_block, - &style, - context.preferred_aspect_ratio(&pbm.padding_border_sums), - LogicalVec2 { - inline: &inline_axis_solver.computed_sizes, - block: &block_axis_solver.computed_sizes, - }, - LogicalVec2 { - inline: automatic_size(inline_alignment, &inline_axis_solver.box_offsets), - block: automatic_size(block_alignment, &block_axis_solver.box_offsets), - }, - pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums, - ); - inline_axis_solver.override_size(used_size.inline); - block_axis_solver.override_size(used_size.block); - } - - // The block axis can depend on layout results, so we only solve it tentatively, - // we may have to resolve it properly later on. - let mut block_axis = block_axis_solver.solve_tentatively(); - - // The inline axis can be fully resolved, computing intrinsic sizes using the - // tentative block size. - let mut inline_axis = inline_axis_solver.solve(Some(|| { - let ratio = context.preferred_aspect_ratio(&pbm.padding_border_sums); - let constraint_space = ConstraintSpace::new(block_axis.size, style.writing_mode, ratio); - context - .inline_content_sizes(layout_context, &constraint_space) - .sizes - })); - let mut positioning_context = PositioningContext::default(); let mut new_fragment = { let content_size: LogicalVec2<Au>; @@ -566,10 +520,34 @@ impl HoistedAbsolutelyPositionedBox { IndependentFormattingContextContents::Replaced(replaced) => { // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height - content_size = LogicalVec2 { - inline: inline_axis.size.to_definite().unwrap(), - block: block_axis.size.to_definite().unwrap(), + let inset_sums = LogicalVec2 { + inline: inline_axis_solver.inset_sum(), + block: block_axis_solver.inset_sum(), + }; + let automatic_size = |alignment: AlignFlags, offsets: &LogicalSides1D<_>| { + if alignment.value() == AlignFlags::STRETCH && !offsets.either_auto() { + Size::Stretch + } else { + Size::FitContent + } }; + content_size = replaced.used_size_as_if_inline_element_from_content_box_sizes( + containing_block, + &style, + context.preferred_aspect_ratio(&pbm.padding_border_sums), + LogicalVec2 { + inline: &inline_axis_solver.computed_sizes, + block: &block_axis_solver.computed_sizes, + }, + LogicalVec2 { + inline: automatic_size( + inline_alignment, + &inline_axis_solver.box_offsets, + ), + block: automatic_size(block_alignment, &block_axis_solver.box_offsets), + }, + pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums, + ); fragments = replaced.make_fragments( layout_context, &style, @@ -579,11 +557,26 @@ impl HoistedAbsolutelyPositionedBox { IndependentFormattingContextContents::NonReplaced(non_replaced) => { // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height - let inline_size = inline_axis.size.to_definite().unwrap(); + + // The block size can depend on layout results, so we only solve it extrinsically, + // we may have to resolve it properly later on. + let extrinsic_block_size = block_axis_solver.solve_size_extrinsically(); + + // The inline axis can be fully resolved, computing intrinsic sizes using the + // extrinsic block size. + let inline_size = inline_axis_solver.solve_size(|| { + let ratio = context.preferred_aspect_ratio(&pbm.padding_border_sums); + let constraint_space = + ConstraintSpace::new(extrinsic_block_size, style.writing_mode, ratio); + context + .inline_content_sizes(layout_context, &constraint_space) + .sizes + }); + let containing_block_for_children = ContainingBlock { size: ContainingBlockSize { inline: inline_size, - block: block_axis.size, + block: extrinsic_block_size, }, style: &style, }; @@ -603,22 +596,14 @@ impl HoistedAbsolutelyPositionedBox { false, /* depends_on_block_constraints */ ); - let inline_size = if let Some(inline_size) = - independent_layout.content_inline_size_for_table - { - // Tables can become narrower than predicted due to collapsed columns, - // so we need to solve again to update margins. - inline_axis_solver.override_size(inline_size); - inline_axis = inline_axis_solver.solve_tentatively(); - inline_size - } else { - inline_size - }; + // Tables can become narrower than predicted due to collapsed columns + let inline_size = independent_layout + .content_inline_size_for_table + .unwrap_or(inline_size); // Now we can properly solve the block size. - block_axis = block_axis_solver - .solve(Some(|| independent_layout.content_block_size.into())); - let block_size = block_axis.size.to_definite().unwrap(); + let block_size = block_axis_solver + .solve_size(|| independent_layout.content_block_size.into()); content_size = LogicalVec2 { inline: inline_size, @@ -629,11 +614,13 @@ impl HoistedAbsolutelyPositionedBox { }, }; + let inline_margins = inline_axis_solver.solve_margins(content_size.inline); + let block_margins = block_axis_solver.solve_margins(content_size.block); let margin = LogicalSides { - inline_start: inline_axis.margin_start, - inline_end: inline_axis.margin_end, - block_start: block_axis.margin_start, - block_end: block_axis.margin_end, + inline_start: inline_margins.start, + inline_end: inline_margins.end, + block_start: block_margins.start, + block_end: block_margins.end, }; let pb = pbm.padding + pbm.border; @@ -715,12 +702,6 @@ impl LogicalRect<Au> { } } -struct AxisResult { - size: SizeConstraint, - margin_start: Au, - margin_end: Au, -} - struct AbsoluteAxisSolver<'a> { axis: Direction, containing_size: Au, @@ -763,101 +744,77 @@ impl AbsoluteAxisSolver<'_> { } } - /// This unifies some of the parts in common in: - /// - /// * <https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width> - /// * <https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height> - /// - /// … and: - /// - /// * <https://drafts.csswg.org/css2/visudet.html#abs-replaced-width> - /// * <https://drafts.csswg.org/css2/visudet.html#abs-replaced-height> - /// - /// In the replaced case, `size` is never `Auto`. - fn solve(&self, get_content_size: Option<impl FnOnce() -> ContentSizes>) -> AxisResult { - let solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint { - let stretch_size = stretch_size.max(Au::zero()); - if let Some(get_content_size) = get_content_size { - SizeConstraint::Definite(self.computed_sizes.resolve( - self.axis, - initial_behavior, - Au::zero, - Some(stretch_size), - get_content_size, - self.is_table, - )) - } else { - self.computed_sizes.resolve_extrinsic( - initial_behavior, - Au::zero(), - Some(stretch_size), - ) - } - }; - if self.box_offsets.either_auto() { - let margin_start = self.computed_margin_start.auto_is(Au::zero); - let margin_end = self.computed_margin_end.auto_is(Au::zero); - let stretch_size = self.containing_size - + #[inline] + fn automatic_size(&self) -> Size<Au> { + match self.alignment.value() { + _ if self.box_offsets.either_auto() => Size::FitContent, + AlignFlags::NORMAL | AlignFlags::AUTO if !self.is_table => Size::Stretch, + AlignFlags::STRETCH => Size::Stretch, + _ => Size::FitContent, + } + } + + #[inline] + fn stretch_size(&self) -> Au { + Au::zero().max( + self.containing_size - self.inset_sum() - self.padding_border_sum - - margin_start - - margin_end; - let size = solve_size(Size::FitContent, stretch_size); - AxisResult { - size, - margin_start, - margin_end, - } - } else { - let mut free_space = self.containing_size - self.inset_sum() - self.padding_border_sum; - let stretch_size = free_space - self.computed_margin_start.auto_is(Au::zero) - - self.computed_margin_end.auto_is(Au::zero); - let initial_behavior = match self.alignment.value() { - AlignFlags::NORMAL | AlignFlags::AUTO if !self.is_table => Size::Stretch, - AlignFlags::STRETCH => Size::Stretch, - _ => Size::FitContent, - }; - let size = solve_size(initial_behavior, stretch_size); - if let Some(used_size) = size.to_definite() { - free_space -= used_size; - } else { - free_space = Au::zero(); - } - let (margin_start, margin_end) = - match (self.computed_margin_start, self.computed_margin_end) { - (AuOrAuto::Auto, AuOrAuto::Auto) => { - if self.avoid_negative_margin_start && free_space < Au::zero() { - (Au::zero(), free_space) - } else { - let margin_start = free_space / 2; - (margin_start, free_space - margin_start) - } - }, - (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (free_space - end, end), - (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => { - (start, free_space - start) - }, - (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => { - (start, end) - }, - }; - AxisResult { - size, - margin_start, - margin_end, - } - } + self.computed_margin_end.auto_is(Au::zero), + ) } - fn solve_tentatively(&mut self) -> AxisResult { - self.solve(None::<fn() -> ContentSizes>) + #[inline] + fn solve_size_extrinsically(&self) -> SizeConstraint { + self.computed_sizes.resolve_extrinsic( + self.automatic_size(), + Au::zero(), + Some(self.stretch_size()), + ) + } + + #[inline] + fn solve_size(&self, get_content_size: impl FnOnce() -> ContentSizes) -> Au { + self.computed_sizes.resolve( + self.axis, + self.automatic_size(), + Au::zero, + Some(self.stretch_size()), + get_content_size, + self.is_table, + ) } - fn override_size(&mut self, size: Au) { - self.computed_sizes.preferred = Size::Numeric(size); - self.computed_sizes.min = Size::default(); - self.computed_sizes.max = Size::default(); + fn solve_margins(&self, size: Au) -> LogicalSides1D<Au> { + if self.box_offsets.either_auto() { + LogicalSides1D::new( + self.computed_margin_start.auto_is(Au::zero), + self.computed_margin_end.auto_is(Au::zero), + ) + } else { + let free_space = + self.containing_size - self.inset_sum() - self.padding_border_sum - size; + match (self.computed_margin_start, self.computed_margin_end) { + (AuOrAuto::Auto, AuOrAuto::Auto) => { + if self.avoid_negative_margin_start && free_space < Au::zero() { + LogicalSides1D::new(Au::zero(), free_space) + } else { + let margin_start = free_space / 2; + LogicalSides1D::new(margin_start, free_space - margin_start) + } + }, + (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => { + LogicalSides1D::new(free_space - end, end) + }, + (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => { + LogicalSides1D::new(start, free_space - start) + }, + (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => { + LogicalSides1D::new(start, end) + }, + } + } } fn origin_for_margin_box( diff --git a/components/layout/table/layout.rs b/components/layout/table/layout.rs index 00dac210625..5b7e79d7fb0 100644 --- a/components/layout/table/layout.rs +++ b/components/layout/table/layout.rs @@ -2867,6 +2867,7 @@ impl TableSlotCell { block: vertical_align_offset, }; let vertical_align_fragment = PositioningFragment::new_anonymous( + self.base.style.clone(), vertical_align_fragment_rect.as_physical(None), layout.layout.fragments, ); diff --git a/components/layout/table/mod.rs b/components/layout/table/mod.rs index 08fc89d927e..72b67863e7d 100644 --- a/components/layout/table/mod.rs +++ b/components/layout/table/mod.rs @@ -76,9 +76,12 @@ pub(crate) use construct::AnonymousTableContent; pub use construct::TableBuilder; use euclid::{Point2D, Size2D, UnknownUnit, Vector2D}; use malloc_size_of_derive::MallocSizeOf; +use script::layout_dom::ServoLayoutElement; use servo_arc::Arc; +use style::context::SharedStyleContext; use style::properties::ComputedValues; use style::properties::style_structs::Font; +use style::selector_parser::PseudoElement; use style_traits::dom::OpaqueNode; use super::flow::BlockFormattingContext; @@ -191,6 +194,19 @@ impl Table { ), } } + + pub(crate) fn repair_style( + &mut self, + context: &SharedStyleContext, + new_style: &Arc<ComputedValues>, + ) { + self.style = new_style.clone(); + self.grid_style = context.stylist.style_for_anonymous::<ServoLayoutElement>( + &context.guards, + &PseudoElement::ServoTableGrid, + new_style, + ); + } } type TableSlotCoordinates = Point2D<usize, UnknownUnit>; @@ -232,6 +248,10 @@ impl TableSlotCell { pub fn node_id(&self) -> usize { self.base.base_fragment_info.tag.map_or(0, |tag| tag.node.0) } + + fn repair_style(&mut self, new_style: &Arc<ComputedValues>) { + self.base.repair_style(new_style); + } } /// A single table slot. It may be an actual cell, or a reference @@ -294,6 +314,13 @@ pub struct TableTrack { shared_background_style: SharedStyle, } +impl TableTrack { + fn repair_style(&mut self, new_style: &Arc<ComputedValues>) { + self.base.repair_style(new_style); + self.shared_background_style = SharedStyle::new(new_style.clone()); + } +} + #[derive(Debug, MallocSizeOf, PartialEq)] pub enum TableTrackGroupType { HeaderGroup, @@ -323,6 +350,11 @@ impl TableTrackGroup { pub(super) fn is_empty(&self) -> bool { self.track_range.is_empty() } + + fn repair_style(&mut self, new_style: &Arc<ComputedValues>) { + self.base.repair_style(new_style); + self.shared_background_style = SharedStyle::new(new_style.clone()); + } } #[derive(Debug, MallocSizeOf)] @@ -389,4 +421,22 @@ impl TableLevelBox { TableLevelBox::Track(track) => track.borrow().base.fragments(), } } + + pub(crate) fn repair_style( + &self, + context: &SharedStyleContext<'_>, + new_style: &Arc<ComputedValues>, + ) { + match self { + TableLevelBox::Caption(caption) => caption + .borrow_mut() + .context + .repair_style(context, new_style), + TableLevelBox::Cell(cell) => cell.borrow_mut().repair_style(new_style), + TableLevelBox::TrackGroup(track_group) => { + track_group.borrow_mut().repair_style(new_style); + }, + TableLevelBox::Track(track) => track.borrow_mut().repair_style(new_style), + } + } } diff --git a/components/layout/taffy/mod.rs b/components/layout/taffy/mod.rs index fc13e6c52ae..ba80824fa99 100644 --- a/components/layout/taffy/mod.rs +++ b/components/layout/taffy/mod.rs @@ -8,6 +8,7 @@ use std::fmt; use app_units::Au; use malloc_size_of_derive::MallocSizeOf; use servo_arc::Arc; +use style::context::SharedStyleContext; use style::properties::ComputedValues; use stylo_taffy::TaffyStyloStyle; @@ -68,6 +69,10 @@ impl TaffyContainer { style: info.style.clone(), } } + + pub(crate) fn repair_style(&mut self, new_style: &Arc<ComputedValues>) { + self.style = new_style.clone(); + } } #[derive(MallocSizeOf)] @@ -143,6 +148,23 @@ impl TaffyItemBox { }, } } + + pub(crate) fn repair_style( + &mut self, + context: &SharedStyleContext, + new_style: &Arc<ComputedValues>, + ) { + self.style = new_style.clone(); + match &mut self.taffy_level_box { + TaffyItemBoxInner::InFlowBox(independent_formatting_context) => { + independent_formatting_context.repair_style(context, new_style) + }, + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box + .borrow_mut() + .context + .repair_style(context, new_style), + } + } } /// Details from Taffy grid layout that will be stored diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index bf60c41d6ba..17c3d0b1c20 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -2,14 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use script::layout_dom::ServoLayoutNode; use script_layout_interface::wrapper_traits::LayoutNode; use style::context::{SharedStyleContext, StyleContext}; use style::data::ElementData; use style::dom::{NodeInfo, TElement, TNode}; +use style::selector_parser::RestyleDamage; use style::traversal::{DomTraversal, PerLevelTraversalData, recalc_style_at}; +use style::values::computed::Display; use crate::context::LayoutContext; -use crate::dom::DOMLayoutData; +use crate::dom::{DOMLayoutData, NodeExt}; +use crate::dom_traversal::iter_child_nodes; pub struct RecalcStyle<'a> { context: &'a LayoutContext<'a>, @@ -40,14 +44,33 @@ where ) where F: FnMut(E::ConcreteNode), { + if node.is_text_node() { + return; + } + + let had_style_data = node.style_data().is_some(); unsafe { node.initialize_style_and_layout_data::<DOMLayoutData>(); - if !node.is_text_node() { - let el = node.as_element().unwrap(); - let mut data = el.mutate_data().unwrap(); - recalc_style_at(self, traversal_data, context, el, &mut data, note_child); - el.unset_dirty_descendants(); - } + } + + let element = node.as_element().unwrap(); + let mut element_data = element.mutate_data().unwrap(); + + if !had_style_data { + element_data.damage = RestyleDamage::reconstruct(); + } + + recalc_style_at( + self, + traversal_data, + context, + element, + &mut element_data, + note_child, + ); + + unsafe { + element.unset_dirty_descendants(); } } @@ -68,3 +91,48 @@ where &self.context.style_context } } + +pub(crate) fn compute_damage_and_repair_style( + context: &SharedStyleContext, + node: ServoLayoutNode<'_>, +) -> RestyleDamage { + compute_damage_and_repair_style_inner(context, node, RestyleDamage::empty()) +} + +pub(crate) fn compute_damage_and_repair_style_inner( + context: &SharedStyleContext, + node: ServoLayoutNode<'_>, + parent_restyle_damage: RestyleDamage, +) -> RestyleDamage { + let original_damage; + let damage = { + let mut element_data = node + .style_data() + .expect("Should not run `compute_damage` before styling.") + .element_data + .borrow_mut(); + + if let Some(ref style) = element_data.styles.primary { + if style.get_box().display == Display::None { + return parent_restyle_damage; + } + } + + original_damage = std::mem::take(&mut element_data.damage); + element_data.damage |= parent_restyle_damage; + element_data.damage + }; + + let mut propagated_damage = damage; + for child in iter_child_nodes(node) { + if child.is_element() { + propagated_damage |= compute_damage_and_repair_style_inner(context, child, damage); + } + } + + if propagated_damage == RestyleDamage::REPAINT && original_damage == RestyleDamage::REPAINT { + node.repair_style(context); + } + + propagated_damage +} |