diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2016-12-15 16:00:40 -0800 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2016-12-16 10:57:27 -0800 |
commit | 648ce1e44e65b194184b713e8b47695d5ff17921 (patch) | |
tree | 94a20912b289dd1799cc017720f6daf83ed6d121 /components/layout | |
parent | 1b2daae453e9276977059fd51c9b733e6400f35c (diff) | |
download | servo-648ce1e44e65b194184b713e8b47695d5ff17921.tar.gz servo-648ce1e44e65b194184b713e8b47695d5ff17921.zip |
Make the DomTraversalContext own the SharedStyleContext and share it immutably across the traversal.
This allows us to get rid of a bunch of lifetimes and simplify a lot of code. It
also lets us get rid of that nasty lifetime transmute, which is awesome.
The situation with thread-local contexts is still suboptimal, but we fix that in
subsequent patches.
Diffstat (limited to 'components/layout')
-rw-r--r-- | components/layout/block.rs | 2 | ||||
-rw-r--r-- | components/layout/context.rs | 73 | ||||
-rw-r--r-- | components/layout/flex.rs | 2 | ||||
-rw-r--r-- | components/layout/inline.rs | 2 | ||||
-rw-r--r-- | components/layout/multicol.rs | 2 | ||||
-rw-r--r-- | components/layout/parallel.rs | 28 | ||||
-rw-r--r-- | components/layout/query.rs | 23 | ||||
-rw-r--r-- | components/layout/sequential.rs | 13 | ||||
-rw-r--r-- | components/layout/traversal.rs | 100 |
9 files changed, 133 insertions, 112 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs index 9d38627b80f..f7370e00a4e 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -55,7 +55,7 @@ use std::fmt; use std::sync::Arc; use style::computed_values::{border_collapse, box_sizing, display, float, overflow_x, overflow_y}; use style::computed_values::{position, text_align}; -use style::context::{SharedStyleContext, StyleContext}; +use style::context::SharedStyleContext; use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode}; use style::properties::ServoComputedValues; use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPOSITION}; diff --git a/components/layout/context.rs b/components/layout/context.rs index 23ec3e41d88..9497d736b47 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -25,22 +25,39 @@ use std::collections::HashMap; use std::hash::BuildHasherDefault; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use style::context::{LocalStyleContext, StyleContext, SharedStyleContext}; +use style::context::{SharedStyleContext, ThreadLocalStyleContext}; -struct LocalLayoutContext { - style_context: LocalStyleContext, +pub struct ThreadLocalLayoutContext { + pub style_context: ThreadLocalStyleContext, + pub font_context: RefCell<FontContext>, +} + +impl ThreadLocalLayoutContext { + pub fn new(shared: &SharedLayoutContext) -> Rc<Self> { + let font_cache_thread = shared.font_cache_thread.lock().unwrap().clone(); + let local_style_data = shared.style_context.local_context_creation_data.lock().unwrap(); + + Rc::new(ThreadLocalLayoutContext { + style_context: ThreadLocalStyleContext::new(&local_style_data), + font_context: RefCell::new(FontContext::new(font_cache_thread)), + }) + } +} - font_context: RefCell<FontContext>, +impl Borrow<ThreadLocalStyleContext> for ThreadLocalLayoutContext { + fn borrow(&self) -> &ThreadLocalStyleContext { + &self.style_context + } } -impl HeapSizeOf for LocalLayoutContext { +impl HeapSizeOf for ThreadLocalLayoutContext { // FIXME(njn): measure other fields eventually. fn heap_size_of_children(&self) -> usize { self.font_context.heap_size_of_children() } } -thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<LocalLayoutContext>>> = RefCell::new(None)); +thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<ThreadLocalLayoutContext>>> = RefCell::new(None)); pub fn heap_size_of_local_context() -> usize { LOCAL_CONTEXT_KEY.with(|r| { @@ -49,20 +66,14 @@ pub fn heap_size_of_local_context() -> usize { } // Keep this implementation in sync with the one in ports/geckolib/traversal.rs. -fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext) - -> Rc<LocalLayoutContext> { +pub fn create_or_get_local_context(shared: &SharedLayoutContext) + -> Rc<ThreadLocalLayoutContext> { LOCAL_CONTEXT_KEY.with(|r| { let mut r = r.borrow_mut(); if let Some(context) = r.clone() { context } else { - let font_cache_thread = shared_layout_context.font_cache_thread.lock().unwrap().clone(); - let local_style_data = shared_layout_context.style_context.local_context_creation_data.lock().unwrap(); - - let context = Rc::new(LocalLayoutContext { - style_context: LocalStyleContext::new(&local_style_data), - font_context: RefCell::new(FontContext::new(font_cache_thread)), - }); + let context = ThreadLocalLayoutContext::new(shared); *r = Some(context.clone()); context } @@ -97,27 +108,27 @@ impl Borrow<SharedStyleContext> for SharedLayoutContext { pub struct LayoutContext<'a> { pub shared: &'a SharedLayoutContext, - cached_local_layout_context: Rc<LocalLayoutContext>, + pub thread_local: &'a ThreadLocalLayoutContext, } -impl<'a> StyleContext<'a> for LayoutContext<'a> { - fn shared_context(&self) -> &'a SharedStyleContext { - &self.shared.style_context - } - - fn local_context(&self) -> &LocalStyleContext { - &self.cached_local_layout_context.style_context +impl<'a> LayoutContext<'a> { + pub fn new(shared: &'a SharedLayoutContext, + thread_local: &'a ThreadLocalLayoutContext) -> Self + { + LayoutContext { + shared: shared, + thread_local: thread_local, + } } } impl<'a> LayoutContext<'a> { - pub fn new(shared_layout_context: &'a SharedLayoutContext) -> LayoutContext<'a> { - let local_context = create_or_get_local_context(shared_layout_context); - - LayoutContext { - shared: shared_layout_context, - cached_local_layout_context: local_context, - } + // FIXME(bholley): The following two methods are identical and should be merged. + // shared_context() is the appropriate name, but it involves renaming a lot of + // calls. + #[inline(always)] + pub fn shared_context(&self) -> &SharedStyleContext { + &self.shared.style_context } #[inline(always)] @@ -127,7 +138,7 @@ impl<'a> LayoutContext<'a> { #[inline(always)] pub fn font_context(&self) -> RefMut<FontContext> { - self.cached_local_layout_context.font_context.borrow_mut() + self.thread_local.font_context.borrow_mut() } } diff --git a/components/layout/flex.rs b/components/layout/flex.rs index 7b169674363..7b8d694494c 100644 --- a/components/layout/flex.rs +++ b/components/layout/flex.rs @@ -26,7 +26,7 @@ use std::ops::Range; use std::sync::Arc; use style::computed_values::{align_content, align_self, flex_direction, flex_wrap, justify_content}; use style::computed_values::border_collapse; -use style::context::{SharedStyleContext, StyleContext}; +use style::context::SharedStyleContext; use style::logical_geometry::{Direction, LogicalSize}; use style::properties::ServoComputedValues; use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW}; diff --git a/components/layout/inline.rs b/components/layout/inline.rs index cefb77bb592..372aa2ea088 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -32,7 +32,7 @@ use std::sync::Arc; use style::arc_ptr_eq; use style::computed_values::{display, overflow_x, position, text_align, text_justify}; use style::computed_values::{vertical_align, white_space}; -use style::context::{SharedStyleContext, StyleContext}; +use style::context::SharedStyleContext; use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; use style::properties::{longhands, ServoComputedValues}; use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPOSITION, RESOLVE_GENERATED_CONTENT}; diff --git a/components/layout/multicol.rs b/components/layout/multicol.rs index 24d90069aa6..b5651369ebf 100644 --- a/components/layout/multicol.rs +++ b/components/layout/multicol.rs @@ -21,7 +21,7 @@ use gfx_traits::print_tree::PrintTree; use std::cmp::{min, max}; use std::fmt; use std::sync::Arc; -use style::context::{StyleContext, SharedStyleContext}; +use style::context::SharedStyleContext; use style::logical_geometry::LogicalSize; use style::properties::ServoComputedValues; use style::values::Either; diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index 6422ab674a9..505afa7897f 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -8,7 +8,8 @@ #![allow(unsafe_code)] -use context::{LayoutContext, SharedLayoutContext}; +use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext}; +use context::create_or_get_local_context; use flow::{self, Flow, MutableFlowUtils, PostorderFlowTraversal, PreorderFlowTraversal}; use flow_ref::FlowRef; use profile_traits::time::{self, TimerMetadata, profile}; @@ -52,7 +53,7 @@ pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow { pub type ChunkedFlowTraversalFunction<'scope> = extern "Rust" fn(Box<[UnsafeFlow]>, &'scope SharedLayoutContext, &rayon::Scope<'scope>); -pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &SharedLayoutContext); +pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &LayoutContext); /// Information that we need stored in each flow. pub struct FlowParallelInfo { @@ -140,11 +141,14 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { #[inline(always)] fn run_parallel_helper<'scope>(&self, unsafe_flows: &[UnsafeFlow], - layout_context: &'scope SharedLayoutContext, + shared: &'scope SharedLayoutContext, scope: &rayon::Scope<'scope>, top_down_func: ChunkedFlowTraversalFunction<'scope>, bottom_up_func: FlowTraversalFunction) { + let tlc = create_or_get_local_context(shared); + let context = LayoutContext::new(&shared, &*tlc); + let mut discovered_child_flows = vec![]; for unsafe_flow in unsafe_flows { let mut had_children = false; @@ -175,7 +179,7 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { // If there were no more children, start assigning block-sizes. if !had_children { - bottom_up_func(*unsafe_flow, layout_context) + bottom_up_func(*unsafe_flow, &context) } } @@ -183,7 +187,7 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice(); scope.spawn(move |scope| { - top_down_func(nodes, layout_context, scope); + top_down_func(nodes, shared, scope); }); } } @@ -220,10 +224,9 @@ fn assign_inline_sizes<'scope>(unsafe_flows: Box<[UnsafeFlow]>, fn assign_block_sizes_and_store_overflow( unsafe_flow: UnsafeFlow, - shared_layout_context: &SharedLayoutContext) { - let layout_context = LayoutContext::new(shared_layout_context); + context: &LayoutContext) { let assign_block_sizes_traversal = AssignBSizes { - layout_context: &layout_context, + layout_context: context, }; assign_block_sizes_traversal.run_parallel(unsafe_flow) } @@ -232,11 +235,12 @@ pub fn traverse_flow_tree_preorder( root: &mut Flow, profiler_metadata: Option<TimerMetadata>, time_profiler_chan: time::ProfilerChan, - shared_layout_context: &SharedLayoutContext, + shared: &SharedLayoutContext, queue: &rayon::ThreadPool) { if opts::get().bubble_inline_sizes_separately { - let layout_context = LayoutContext::new(shared_layout_context); - let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context }; + let tlc = ThreadLocalLayoutContext::new(shared); + let context = LayoutContext::new(shared, &*tlc); + let bubble_inline_sizes = BubbleISizes { layout_context: &context }; root.traverse_postorder(&bubble_inline_sizes); } @@ -246,7 +250,7 @@ pub fn traverse_flow_tree_preorder( rayon::scope(move |scope| { profile(time::ProfilerCategory::LayoutParallelWarmup, profiler_metadata, time_profiler_chan, move || { - assign_inline_sizes(nodes, &shared_layout_context, scope); + assign_inline_sizes(nodes, &shared, scope); }); }); }); diff --git a/components/layout/query.rs b/components/layout/query.rs index 81d0ce5e320..b6eb7cfeb39 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -6,6 +6,8 @@ use app_units::Au; use construct::ConstructionResult; +use context::SharedLayoutContext; +use context::create_or_get_local_context; use euclid::point::Point2D; use euclid::rect::Rect; use euclid::size::Size2D; @@ -624,13 +626,12 @@ pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layou /// Return the resolved value of property for a given (pseudo)element. /// https://drafts.csswg.org/cssom/#resolved-value -pub fn process_resolved_style_request<'a, N, C>(requested_node: N, - style_context: &'a C, - pseudo: &Option<PseudoElement>, - property: &PropertyId, - layout_root: &mut Flow) -> String +pub fn process_resolved_style_request<'a, N>(shared: &SharedLayoutContext, + requested_node: N, + pseudo: &Option<PseudoElement>, + property: &PropertyId, + layout_root: &mut Flow) -> String where N: LayoutNode, - C: StyleContext<'a> { use style::traversal::{clear_descendant_data, style_element_in_display_none_subtree}; let element = requested_node.as_element().unwrap(); @@ -645,8 +646,14 @@ pub fn process_resolved_style_request<'a, N, C>(requested_node: N, // we'd need a mechanism to prevent detect when it's stale (since we don't // traverse display:none subtrees during restyle). let display_none_root = if element.get_data().is_none() { - Some(style_element_in_display_none_subtree(element, &|e| e.as_node().initialize_data(), - style_context)) + let tlc = create_or_get_local_context(shared); + let context = StyleContext { + shared: &shared.style_context, + thread_local: &tlc.style_context, + }; + + Some(style_element_in_display_none_subtree(&context, element, + &|e| e.as_node().initialize_data())) } else { None }; diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index b4d31269629..e5f62fe1cea 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -5,7 +5,7 @@ //! Implements sequential traversals over the DOM and flow trees. use app_units::Au; -use context::{LayoutContext, SharedLayoutContext}; +use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext}; use display_list_builder::DisplayListBuildState; use euclid::point::Point2D; use floats::SpeculatedFloatPlacement; @@ -16,13 +16,12 @@ use fragment::FragmentBorderBoxIterator; use generated_content::ResolveGeneratedContent; use gfx_traits::ScrollRootId; use servo_config::opts; -use style::context::StyleContext; use style::servo::restyle_damage::{REFLOW, STORE_OVERFLOW}; use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList}; pub use style::sequential::traverse_dom; -pub fn resolve_generated_content(root: &mut Flow, shared_layout_context: &SharedLayoutContext) { +pub fn resolve_generated_content(root: &mut Flow, shared: &SharedLayoutContext) { fn doit(flow: &mut Flow, level: u32, traversal: &mut ResolveGeneratedContent) { if !traversal.should_process(flow) { return @@ -35,13 +34,14 @@ pub fn resolve_generated_content(root: &mut Flow, shared_layout_context: &Shared } } - let layout_context = LayoutContext::new(shared_layout_context); + let tlc = ThreadLocalLayoutContext::new(shared); + let layout_context = LayoutContext::new(shared, &*tlc); let mut traversal = ResolveGeneratedContent::new(&layout_context); doit(root, 0, &mut traversal) } pub fn traverse_flow_tree_preorder(root: &mut Flow, - shared_layout_context: &SharedLayoutContext) { + shared: &SharedLayoutContext) { fn doit(flow: &mut Flow, assign_inline_sizes: AssignISizes, assign_block_sizes: AssignBSizes) { @@ -58,7 +58,8 @@ pub fn traverse_flow_tree_preorder(root: &mut Flow, } } - let layout_context = LayoutContext::new(shared_layout_context); + let tlc = ThreadLocalLayoutContext::new(shared); + let layout_context = LayoutContext::new(shared, &*tlc); if opts::get().bubble_inline_sizes_separately { let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context }; diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index bda40df574f..43ef8e14fda 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -5,74 +5,59 @@ //! Traversals over the DOM and flow trees, running the layout computations. use construct::FlowConstructor; -use context::{LayoutContext, SharedLayoutContext}; +use context::{LayoutContext, SharedLayoutContext, ThreadLocalLayoutContext}; +use context::create_or_get_local_context; use display_list_builder::DisplayListBuildState; use flow::{self, PreorderFlowTraversal}; use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal}; use gfx::display_list::OpaqueNode; use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; use servo_config::opts; -use std::mem; +use std::rc::Rc; use style::atomic_refcell::AtomicRefCell; -use style::context::{LocalStyleContext, SharedStyleContext, StyleContext}; +use style::context::{SharedStyleContext, StyleContext}; use style::data::ElementData; use style::dom::{TElement, TNode}; use style::selector_parser::RestyleDamage; use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT}; -use style::traversal::{DomTraversalContext, recalc_style_at, remove_from_bloom_filter}; +use style::traversal::{DomTraversal, recalc_style_at, remove_from_bloom_filter}; use style::traversal::PerLevelTraversalData; use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData}; -pub struct RecalcStyleAndConstructFlows<'lc> { - context: LayoutContext<'lc>, +pub struct RecalcStyleAndConstructFlows { + shared: SharedLayoutContext, root: OpaqueNode, } -#[allow(unsafe_code)] -impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc> - where N: LayoutNode + TNode, - N::ConcreteElement: TElement +impl RecalcStyleAndConstructFlows { + pub fn shared_layout_context(&self) -> &SharedLayoutContext { + &self.shared + } +} -{ - type SharedContext = SharedLayoutContext; - #[allow(unsafe_code)] - fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { - // FIXME(bholley): This transmutation from &'a to &'lc is very unfortunate, but I haven't - // found a way to avoid it despite spending several days on it (and consulting Manishearth, - // brson, and nmatsakis). - // - // The crux of the problem is that parameterizing DomTraversalContext on the lifetime of - // the SharedContext doesn't work for a variety of reasons [1]. However, the code in - // parallel.rs needs to be able to use the DomTraversalContext trait (or something similar) - // to stack-allocate a struct (a generalized LayoutContext<'a>) that holds a borrowed - // SharedContext, which means that the struct needs to be parameterized on a lifetime. - // Given the aforementioned constraint, the only way to accomplish this is to avoid - // propagating the borrow lifetime from the struct to the trait, but that means that the - // new() method on the trait cannot require the lifetime of its argument to match the - // lifetime of the Self object it creates. - // - // This could be solved with an associated type with an unbound lifetime parameter, but - // that would require higher-kinded types, which don't exist yet and probably aren't coming - // for a while. - // - // So we transmute. :-( This is safe because the DomTravesalContext is stack-allocated on - // the worker thread while processing a WorkUnit, whereas the borrowed SharedContext is - // live for the entire duration of the restyle. This really could _almost_ compile: all - // we'd need to do is change the signature to to |new<'a: 'lc>|, and everything would - // work great. But we can't do that, because that would cause a mismatch with the signature - // in the trait we're implementing, and we can't mention 'lc in that trait at all for the - // reasons described above. - // - // [1] For example, the WorkQueue type needs to be parameterized on the concrete type of - // DomTraversalContext::SharedContext, and the WorkQueue lifetime is similar to that of the - // LayoutThread, generally much longer than that of a given SharedLayoutContext borrow. - let shared_lc: &'lc SharedLayoutContext = unsafe { mem::transmute(shared) }; +impl RecalcStyleAndConstructFlows { + /// Creates a traversal context, taking ownership of the shared layout context. + pub fn new(shared: SharedLayoutContext, root: OpaqueNode) -> Self { RecalcStyleAndConstructFlows { - context: LayoutContext::new(shared_lc), + shared: shared, root: root, } } + /// Consumes this traversal context, returning ownership of the shared layout + /// context to the caller. + pub fn destroy(self) -> SharedLayoutContext { + self.shared + } +} + +#[allow(unsafe_code)] +impl<N> DomTraversal<N> for RecalcStyleAndConstructFlows + where N: LayoutNode + TNode, + N::ConcreteElement: TElement +{ + type ThreadLocalContext = ThreadLocalLayoutContext; + fn process_preorder(&self, node: N, traversal_data: &mut PerLevelTraversalData) { // FIXME(pcwalton): Stop allocating here. Ideally this should just be // done by the HTML parser. @@ -81,12 +66,19 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc> if !node.is_text_node() { let el = node.as_element().unwrap(); let mut data = el.mutate_data().unwrap(); - recalc_style_at::<_, _, Self>(&self.context, traversal_data, el, &mut data); + let tlc = create_or_get_local_context(&self.shared); + let context = StyleContext { + shared: &self.shared.style_context, + thread_local: &tlc.style_context, + }; + recalc_style_at(self, traversal_data, &context, el, &mut data); } } fn process_postorder(&self, node: N) { - construct_flows_at(&self.context, self.root, node); + let tlc = create_or_get_local_context(&self.shared); + let context = LayoutContext::new(&self.shared, &*tlc); + construct_flows_at(&context, self.root, node); } fn text_node_needs_traversal(node: N) -> bool { @@ -107,8 +99,12 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc> element.as_node().clear_data(); } - fn local_context(&self) -> &LocalStyleContext { - self.context.local_context() + fn shared_context(&self) -> &SharedStyleContext { + &self.shared.style_context + } + + fn create_or_get_thread_local_context(&self) -> Rc<ThreadLocalLayoutContext> { + create_or_get_local_context(&self.shared) } } @@ -121,7 +117,9 @@ pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayo /// The flow construction traversal, which builds flows for styled nodes. #[inline] #[allow(unsafe_code)] -fn construct_flows_at<'a, N: LayoutNode>(context: &'a LayoutContext<'a>, root: OpaqueNode, node: N) { +fn construct_flows_at<'a, N>(context: &LayoutContext<'a>, root: OpaqueNode, node: N) + where N: LayoutNode, +{ debug!("construct_flows_at: {:?}", node); // Construct flows for this node. @@ -146,7 +144,7 @@ fn construct_flows_at<'a, N: LayoutNode>(context: &'a LayoutContext<'a>, root: O el.mutate_data().unwrap().persist(); unsafe { el.unset_dirty_descendants(); } - remove_from_bloom_filter(context, root, el); + remove_from_bloom_filter(&context.shared.style_context, root, el); } } |