diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 4fb3838d18e..88a6514433b 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -30,6 +30,10 @@ impl<'a> RecalcStyleAndConstructFlows<'a> { RecalcStyleAndConstructFlows { context: context } } + pub fn context(&self) -> &LayoutContext<'a> { + &self.context + } + /// Consumes this traversal context, returning ownership of the shared layout /// context to the caller. pub fn destroy(self) -> LayoutContext<'a> { @@ -183,6 +187,19 @@ where fn process(&mut self, node: &ConcreteThreadSafeLayoutNode); } +#[allow(unsafe_code)] +#[inline] +pub unsafe fn construct_flows_at_ancestors<'dom>( + context: &LayoutContext, + mut node: impl LayoutNode<'dom>, +) { + while let Some(element) = node.traversal_parent() { + element.set_dirty_descendants(); + node = element.as_node(); + construct_flows_at(context, node); + } +} + /// The flow construction traversal, which builds flows for styled nodes. #[inline] #[allow(unsafe_code)] diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 126c74a886f..41e054bbe83 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -34,7 +34,7 @@ use crate::data::{LayoutData, LayoutDataFlags, StyleAndLayoutData}; use atomic_refcell::{AtomicRef, AtomicRefMut}; use script_layout_interface::wrapper_traits::GetStyleAndOpaqueLayoutData; use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSafeLayoutNode}; -use style::dom::{NodeInfo, TNode}; +use style::dom::{NodeInfo, TElement, TNode}; use style::selector_parser::RestyleDamage; use style::values::computed::counters::ContentItem; use style::values::generics::counters::Content; @@ -148,7 +148,13 @@ where } let damage = { - let data = node.get_style_and_layout_data().unwrap(); + let data = match node.get_style_and_layout_data() { + Some(data) => data, + None => panic!( + "could not get style and layout data for <{}>", + node.as_element().unwrap().local_name() + ), + }; if !data .layout_data diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index a8f5a17fc1d..c043d3b75d3 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -346,8 +346,10 @@ impl BoxSlot<'_> { impl Drop for BoxSlot<'_> { fn drop(&mut self) { - if let Some(slot) = &mut self.slot { - assert!(slot.borrow().is_some(), "failed to set a layout box"); + if !std::thread::panicking() { + if let Some(slot) = &mut self.slot { + assert!(slot.borrow().is_some(), "failed to set a layout box"); + } } } } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 037fffc34ec..82da02d1ce3 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -57,7 +57,8 @@ use layout::query::{process_node_scroll_area_request, process_node_scroll_id_req use layout::query::{process_offset_parent_query, process_resolved_style_request}; use layout::sequential; use layout::traversal::{ - ComputeStackingRelativePositions, PreorderFlowTraversal, RecalcStyleAndConstructFlows, + construct_flows_at_ancestors, ComputeStackingRelativePositions, PreorderFlowTraversal, + RecalcStyleAndConstructFlows, }; use layout::wrapper::LayoutNodeLayoutData; use layout_traits::LayoutThreadFactory; @@ -1200,7 +1201,7 @@ impl LayoutThread { .expect("layout: wrong layout query timestamp"); }; - let element = match document.root_element() { + let root_element = match document.root_element() { None => { // Since we cannot compute anything, give spec-required placeholders. debug!("layout: No root node: bailing"); @@ -1250,9 +1251,9 @@ impl LayoutThread { debug!( "layout: processing reflow request for: {:?} ({}) (query={:?})", - element, self.url, data.reflow_goal + root_element, self.url, data.reflow_goal ); - trace!("{:?}", ShowSubtree(element.as_node())); + trace!("{:?}", ShowSubtree(root_element.as_node())); let initial_viewport = data.window_size.initial_viewport; let device_pixel_ratio = data.window_size.device_pixel_ratio; @@ -1309,7 +1310,7 @@ impl LayoutThread { .unwrap(); } if had_used_viewport_units { - if let Some(mut data) = element.mutate_data() { + if let Some(mut data) = root_element.mutate_data() { data.hint.insert(RestyleHint::recascade_subtree()); } } @@ -1344,7 +1345,7 @@ impl LayoutThread { } if viewport_size_changed { - if let Some(mut flow) = self.try_get_layout_root(element.as_node()) { + if let Some(mut flow) = self.try_get_layout_root(root_element.as_node()) { LayoutThread::reflow_all_nodes(FlowRef::deref_mut(&mut flow)); } } @@ -1395,7 +1396,7 @@ impl LayoutThread { debug!("Noting restyle for {:?}: {:?}", el, style_data); } - self.stylist.flush(&guards, Some(element), Some(&map)); + self.stylist.flush(&guards, Some(root_element), Some(&map)); // Create a layout context for use throughout the following passes. let mut layout_context = self.build_layout_context( @@ -1414,13 +1415,19 @@ impl LayoutThread { (None, 1) }; + let dirty_root = unsafe { + ServoLayoutNode::new(&data.dirty_root.unwrap()) + .as_element() + .unwrap() + }; + let traversal = RecalcStyleAndConstructFlows::new(layout_context); let token = { let shared = >::shared_context( &traversal, ); - RecalcStyleAndConstructFlows::pre_traverse(element, shared) + RecalcStyleAndConstructFlows::pre_traverse(dirty_root, shared) }; if token.should_traverse() { @@ -1431,11 +1438,13 @@ impl LayoutThread { self.time_profiler_chan.clone(), || { // Perform CSS selector matching and flow construction. - driver::traverse_dom::( - &traversal, - token, - thread_pool, - ); + let root = driver::traverse_dom::< + ServoLayoutElement, + RecalcStyleAndConstructFlows, + >(&traversal, token, thread_pool); + unsafe { + construct_flows_at_ancestors(traversal.context(), root.as_node()); + } }, ); // TODO(pcwalton): Measure energy usage of text shaping, perhaps? @@ -1452,7 +1461,7 @@ impl LayoutThread { ); // Retrieve the (possibly rebuilt) root flow. - *self.root_flow.borrow_mut() = self.try_get_layout_root(element.as_node()); + *self.root_flow.borrow_mut() = self.try_get_layout_root(root_element.as_node()); } for element in elements_with_snapshot { @@ -1462,7 +1471,10 @@ impl LayoutThread { layout_context = traversal.destroy(); if self.dump_style_tree { - println!("{:?}", ShowSubtreeDataAndPrimaryValues(element.as_node())); + println!( + "{:?}", + ShowSubtreeDataAndPrimaryValues(root_element.as_node()) + ); } if self.dump_rule_tree { diff --git a/components/layout_thread_2020/dom_wrapper.rs b/components/layout_thread_2020/dom_wrapper.rs index 7b1da3454a0..15e19ee73a4 100644 --- a/components/layout_thread_2020/dom_wrapper.rs +++ b/components/layout_thread_2020/dom_wrapper.rs @@ -1307,7 +1307,10 @@ impl<'le> ThreadSafeLayoutElement<'le> for ServoThreadSafeLayoutElement<'le> { } fn style_data(&self) -> AtomicRef { - self.element.borrow_data().expect("Unstyled layout node?") + match self.element.borrow_data() { + Some(data) => data, + None => panic!("could not find styles for <{}>", self.element.local_name()), + } } fn is_shadow_host(&self) -> bool { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 13c6697d21b..214e9c1325a 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -89,7 +89,6 @@ use style::dom::{TDocument, TElement, TNode}; use style::driver; use style::error_reporting::RustLogReporter; use style::global_style_data::{GLOBAL_STYLE_DATA, STYLE_THREAD_POOL}; -use style::invalidation::element::restyle_hints::RestyleHint; use style::media_queries::{Device, MediaList, MediaType}; use style::properties::PropertyId; use style::selector_parser::SnapshotMap; @@ -891,7 +890,7 @@ impl LayoutThread { let mut rw_data = possibly_locked_rw_data.lock(); - let element = match document.root_element() { + let root_element = match document.root_element() { None => { // Since we cannot compute anything, give spec-required placeholders. debug!("layout: No root node: bailing"); @@ -962,7 +961,6 @@ impl LayoutThread { ua_or_user: &ua_or_user_guard, }; - let had_used_viewport_units = self.stylist.device().used_viewport_units(); let device = Device::new(MediaType::screen(), initial_viewport, device_pixel_ratio); let sheet_origins_affected_by_device_change = self.stylist.set_device(device, &guards); @@ -990,11 +988,6 @@ impl LayoutThread { )) .unwrap(); } - if had_used_viewport_units { - if let Some(mut data) = element.mutate_data() { - data.hint.insert(RestyleHint::recascade_subtree()); - } - } } if self.first_reflow.get() { @@ -1062,7 +1055,7 @@ impl LayoutThread { debug!("Noting restyle for {:?}: {:?}", el, style_data); } - self.stylist.flush(&guards, Some(element), Some(&map)); + self.stylist.flush(&guards, Some(root_element), Some(&map)); // Create a layout context for use throughout the following passes. let mut layout_context = self.build_layout_context( @@ -1073,10 +1066,16 @@ impl LayoutThread { data.animations.clone(), ); + let dirty_root = unsafe { + ServoLayoutNode::new(&data.dirty_root.unwrap()) + .as_element() + .unwrap() + }; + let traversal = RecalcStyle::new(layout_context); let token = { let shared = DomTraversal::::shared_context(&traversal); - RecalcStyle::pre_traverse(element, shared) + RecalcStyle::pre_traverse(dirty_root, shared) }; let rayon_pool = STYLE_THREAD_POOL.pool(); @@ -1085,7 +1084,7 @@ impl LayoutThread { let box_tree = if token.should_traverse() { driver::traverse_dom(&traversal, token, rayon_pool); - let root_node = document.root_element().unwrap().as_node(); + let root_node = root_element.as_node(); let build_box_tree = || BoxTree::construct(traversal.context(), root_node); let box_tree = if let Some(pool) = rayon_pool { pool.install(build_box_tree) @@ -1122,7 +1121,7 @@ impl LayoutThread { if self.dump_style_tree { println!( "{:?}", - style::dom::ShowSubtreeDataAndPrimaryValues(element.as_node()) + style::dom::ShowSubtreeDataAndPrimaryValues(root_element.as_node()) ); } diff --git a/components/script/dom/bindings/cell.rs b/components/script/dom/bindings/cell.rs index e3f5ad71bee..5807138c948 100644 --- a/components/script/dom/bindings/cell.rs +++ b/components/script/dom/bindings/cell.rs @@ -45,11 +45,12 @@ impl DomRefCell { &mut *self.value.as_ptr() } - /// Version of the above that we use during restyle while the script thread - /// is blocked. - pub fn borrow_mut_for_layout(&self) -> RefMut { + /// Mutably borrow a cell for layout. Ideally this would use + /// `RefCell::try_borrow_mut_unguarded` but that doesn't exist yet. + #[allow(unsafe_code)] + pub unsafe fn borrow_mut_for_layout(&self) -> &mut T { debug_assert!(thread_state::get().is_layout()); - self.value.borrow_mut() + &mut *self.value.as_ptr() } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 4577835d24e..efb3277f1cf 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -387,6 +387,8 @@ pub struct Document { animation_timeline: DomRefCell, /// Animations for this Document animations: DomRefCell, + /// The nearest inclusive ancestors to all the nodes that require a restyle. + dirty_root: MutNullableDom, } #[derive(JSTraceable, MallocSizeOf)] @@ -446,6 +448,112 @@ enum ElementLookupResult { #[allow(non_snake_case)] impl Document { + pub fn note_node_with_dirty_descendants(&self, node: &Node) { + debug_assert!(*node.owner_doc() == *self); + if !node.is_connected() { + return; + } + + let parent = match node.inclusive_ancestors(ShadowIncluding::Yes).nth(1) { + Some(parent) => parent, + None => { + // There is no parent so this is the Document node, so we + // behave as if we were called with the document element. + let document_element = match self.GetDocumentElement() { + Some(element) => element, + None => return, + }; + if let Some(dirty_root) = self.dirty_root.get() { + // There was an existing dirty root so we mark its + // ancestors as dirty until the document element. + for ancestor in dirty_root + .upcast::() + .inclusive_ancestors(ShadowIncluding::Yes) + { + if ancestor.is::() { + ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true); + } + } + } + self.dirty_root.set(Some(&document_element)); + return; + }, + }; + + if parent.is::() { + if !parent.is_styled() { + return; + } + + if parent.is_display_none() { + return; + } + } + + let element_parent: DomRoot; + let element = match node.downcast::() { + Some(element) => element, + None => { + // Current node is not an element, it's probably a text node, + // we try to get its element parent. + match DomRoot::downcast::(parent) { + Some(parent) => { + element_parent = parent; + &element_parent + }, + None => { + // Parent is not an element so it must be a document, + // and this is not an element either, so there is + // nothing to do. + return; + }, + } + }, + }; + + let dirty_root = match self.dirty_root.get() { + None => { + element + .upcast::() + .set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true); + self.dirty_root.set(Some(element)); + return; + }, + Some(root) => root, + }; + + for ancestor in element + .upcast::() + .inclusive_ancestors(ShadowIncluding::Yes) + { + if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) { + return; + } + if ancestor.is::() { + ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true); + } + } + + let new_dirty_root = element + .upcast::() + .common_ancestor(dirty_root.upcast(), ShadowIncluding::Yes); + + let mut has_dirty_descendants = true; + for ancestor in dirty_root + .upcast::() + .inclusive_ancestors(ShadowIncluding::Yes) + { + ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, has_dirty_descendants); + has_dirty_descendants &= *ancestor != *new_dirty_root; + } + self.dirty_root + .set(Some(new_dirty_root.downcast::().unwrap())); + } + + pub fn take_dirty_root(&self) -> Option> { + self.dirty_root.take() + } + #[inline] pub fn loader(&self) -> Ref { self.loader.borrow() @@ -967,8 +1075,14 @@ impl Document { } pub fn dirty_all_nodes(&self) { - let root = self.upcast::(); - for node in root.traverse_preorder(ShadowIncluding::Yes) { + let root = match self.GetDocumentElement() { + Some(root) => root, + None => return, + }; + for node in root + .upcast::() + .traverse_preorder(ShadowIncluding::Yes) + { node.dirty(NodeDamage::OtherNodeDamage) } } @@ -2917,6 +3031,7 @@ impl Document { DomRefCell::new(AnimationTimeline::new()) }, animations: DomRefCell::new(Animations::new()), + dirty_root: Default::default(), } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 6f6f33f56a8..458f301e238 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -309,6 +309,7 @@ impl Element { restyle.hint.insert(RestyleHint::RESTYLE_SELF); if damage == NodeDamage::OtherNodeDamage { + doc.note_node_with_dirty_descendants(self.upcast()); restyle.damage = RestyleDamage::rebuild_and_reflow(); } } @@ -515,6 +516,7 @@ impl Element { pub fn detach_shadow(&self) { if let Some(ref shadow_root) = self.shadow_root() { + self.upcast::().note_dirty_descendants(); shadow_root.detach(); self.ensure_rare_data().shadow_root = None; } else { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index a7eda2e3597..f17c22163d0 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -150,12 +150,9 @@ pub struct Node { /// are this node. ranges: WeakRangeVec, - /// Style+Layout information. Only the layout thread may touch this data. - /// - /// Must be sent back to the layout thread to be destroyed when this - /// node is finalized. - #[ignore_malloc_size_of = "Unsafe cell"] - style_and_layout_data: UnsafeCell>>, + /// Style+Layout information. + #[ignore_malloc_size_of = "trait object"] + style_and_layout_data: DomRefCell>>, } bitflags! { @@ -318,6 +315,8 @@ impl Node { /// Fails unless `child` is a child of this node. fn remove_child(&self, child: &Node, cached_index: Option) { assert!(child.parent_node.get().as_deref() == Some(self)); + self.note_dirty_descendants(); + let prev_sibling = child.GetPreviousSibling(); match prev_sibling { None => { @@ -630,17 +629,7 @@ impl Node { // FIXME(emilio): This and the function below should move to Element. pub fn note_dirty_descendants(&self) { - debug_assert!(self.is_connected()); - - for ancestor in self.inclusive_ancestors(ShadowIncluding::Yes) { - if ancestor.get_flag(NodeFlags::HAS_DIRTY_DESCENDANTS) { - return; - } - - if ancestor.is::() { - ancestor.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, true); - } - } + self.owner_doc().note_node_with_dirty_descendants(self); } pub fn has_dirty_descendants(&self) -> bool { @@ -708,6 +697,22 @@ impl Node { } } + pub fn common_ancestor( + &self, + other: &Node, + shadow_including: ShadowIncluding, + ) -> DomRoot { + for ancestor in self.inclusive_ancestors(shadow_including) { + if other + .inclusive_ancestors(shadow_including) + .any(|node| node == ancestor) + { + return ancestor; + } + } + unreachable!(); + } + pub fn is_inclusive_ancestor_of(&self, parent: &Node) -> bool { self == parent || self.is_ancestor_of(parent) } @@ -1246,21 +1251,38 @@ impl Node { } } - #[allow(unsafe_code)] - pub fn style(&self) -> Option> { - if !window_from_node(self).layout_reflow(QueryMsg::StyleQuery) { - return None; - } - unsafe { - (*self.style_and_layout_data.get()).as_ref().map(|data| { + pub fn is_styled(&self) -> bool { + self.style_and_layout_data.borrow().is_some() + } + + pub fn is_display_none(&self) -> bool { + self.style_and_layout_data + .borrow() + .as_ref() + .map_or(true, |data| { data.style_data .element_data .borrow() .styles .primary() - .clone() + .get_box() + .display + .is_none() }) + } + + pub fn style(&self) -> Option> { + if !window_from_node(self).layout_reflow(QueryMsg::StyleQuery) { + return None; } + self.style_and_layout_data.borrow().as_ref().map(|data| { + data.style_data + .element_data + .borrow() + .styles + .primary() + .clone() + }) } } @@ -1444,13 +1466,21 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> { #[inline] #[allow(unsafe_code)] fn get_style_and_opaque_layout_data(self) -> Option<&'dom StyleAndOpaqueLayoutData> { - unsafe { (*self.unsafe_get().style_and_layout_data.get()).as_deref() } + unsafe { + self.unsafe_get() + .style_and_layout_data + .borrow_for_layout() + .as_deref() + } } #[inline] #[allow(unsafe_code)] unsafe fn init_style_and_opaque_layout_data(self, val: Box) { - let data = &mut *self.unsafe_get().style_and_layout_data.get(); + let data = self + .unsafe_get() + .style_and_layout_data + .borrow_mut_for_layout(); debug_assert!(data.is_none()); *data = Some(val); } @@ -1458,7 +1488,9 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> { #[inline] #[allow(unsafe_code)] unsafe fn take_style_and_opaque_layout_data(self) -> Box { - (*self.unsafe_get().style_and_layout_data.get()) + self.unsafe_get() + .style_and_layout_data + .borrow_mut_for_layout() .take() .unwrap() } @@ -1649,7 +1681,7 @@ where } /// Whether a tree traversal should pass shadow tree boundaries. -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] pub enum ShadowIncluding { No, Yes, @@ -1775,7 +1807,7 @@ impl Node { inclusive_descendants_version: Cell::new(0), ranges: WeakRangeVec::new(), - style_and_layout_data: UnsafeCell::new(None), + style_and_layout_data: Default::default(), } } diff --git a/components/script/dom/range.rs b/components/script/dom/range.rs index 0b1c8f16de1..e9b3a2e34cb 100644 --- a/components/script/dom/range.rs +++ b/components/script/dom/range.rs @@ -296,19 +296,8 @@ impl RangeMethods for Range { // https://dom.spec.whatwg.org/#dom-range-commonancestorcontainer fn CommonAncestorContainer(&self) -> DomRoot { - let end_container = self.EndContainer(); - // Step 1. - for container in self - .StartContainer() - .inclusive_ancestors(ShadowIncluding::No) - { - // Step 2. - if container.is_inclusive_ancestor_of(&end_container) { - // Step 3. - return container; - } - } - unreachable!(); + self.EndContainer() + .common_ancestor(&self.StartContainer(), ShadowIncluding::No) } // https://dom.spec.whatwg.org/#dom-range-setstart diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index f1c0567a399..c70c13d8cef 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -281,7 +281,7 @@ impl<'dom> LayoutShadowRootHelpers<'dom> for LayoutDom<'dom, ShadowRoot> { quirks_mode: QuirksMode, guard: &SharedRwLockReadGuard, ) { - let mut author_styles = (*self.unsafe_get()).author_styles.borrow_mut_for_layout(); + let author_styles = self.unsafe_get().author_styles.borrow_mut_for_layout(); if author_styles.stylesheets.dirty() { author_styles.flush::(device, quirks_mode, guard); } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 73d3f163ec7..946bcdcfea9 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1659,6 +1659,14 @@ impl Window { document.flush_dirty_canvases(); } + let pending_restyles = document.drain_pending_restyles(); + + let dirty_root = document + .take_dirty_root() + .filter(|_| !stylesheets_changed) + .or_else(|| document.GetDocumentElement()) + .map(|root| root.upcast::().to_trusted_node_address()); + // Send new document and relevant styles to layout. let needs_display = reflow_goal.needs_display(); let reflow = ScriptReflow { @@ -1666,13 +1674,14 @@ impl Window { page_clip_rect: self.page_clip_rect.get(), }, document: document.upcast::().to_trusted_node_address(), + dirty_root, stylesheets_changed, window_size: self.window_size.get(), origin: self.origin().immutable().clone(), reflow_goal, script_join_chan: join_chan, dom_count: document.dom_count(), - pending_restyles: document.drain_pending_restyles(), + pending_restyles, animation_timeline_value: document.current_animation_timeline_value(), animations: document.animations().sets.clone(), }; @@ -1770,12 +1779,17 @@ impl Window { // We shouldn't need a reflow immediately after a // reflow, except if we're waiting for a deferred paint. - assert!({ - let condition = self.Document().needs_reflow(); - condition.is_none() || - (!for_display && condition == Some(ReflowTriggerCondition::PaintPostponed)) || - self.suppress_reflow.get() - }); + let condition = self.Document().needs_reflow(); + assert!( + { + condition.is_none() || + (!for_display && + condition == Some(ReflowTriggerCondition::PaintPostponed)) || + self.suppress_reflow.get() + }, + "condition was {:?}", + condition + ); } else { debug!( "Document doesn't need reflow - skipping it (reason {:?})", diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 1dcbfe7eb33..8495d61fc8a 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -193,6 +193,8 @@ pub struct ScriptReflow { pub reflow_info: Reflow, /// The document node. pub document: TrustedNodeAddress, + /// The dirty root from which to restyle. + pub dirty_root: Option, /// Whether the document's stylesheets have changed since the last script reflow. pub stylesheets_changed: bool, /// The current window size. diff --git a/components/style/driver.rs b/components/style/driver.rs index aa39f3482f4..eab7c3a6a31 100644 --- a/components/style/driver.rs +++ b/components/style/driver.rs @@ -63,7 +63,8 @@ pub fn traverse_dom( traversal: &D, token: PreTraverseToken, pool: Option<&rayon::ThreadPool>, -) where +) -> E +where E: TElement, D: DomTraversal, { @@ -187,4 +188,6 @@ pub fn traverse_dom( } } } + + root } diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs index 4b18decc66a..e46848e5cf1 100644 --- a/tests/unit/script/size_of.rs +++ b/tests/unit/script/size_of.rs @@ -30,10 +30,10 @@ macro_rules! sizeof_checker ( // Update the sizes here sizeof_checker!(size_event_target, EventTarget, 56); -sizeof_checker!(size_node, Node, 184); -sizeof_checker!(size_element, Element, 360); -sizeof_checker!(size_htmlelement, HTMLElement, 376); -sizeof_checker!(size_div, HTMLDivElement, 376); -sizeof_checker!(size_span, HTMLSpanElement, 376); -sizeof_checker!(size_text, Text, 216); -sizeof_checker!(size_characterdata, CharacterData, 216); +sizeof_checker!(size_node, Node, 192); +sizeof_checker!(size_element, Element, 368); +sizeof_checker!(size_htmlelement, HTMLElement, 384); +sizeof_checker!(size_div, HTMLDivElement, 384); +sizeof_checker!(size_span, HTMLSpanElement, 384); +sizeof_checker!(size_text, Text, 224); +sizeof_checker!(size_characterdata, CharacterData, 224);