зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #17615 - Rip out the generic abstractions around ThreadLocalStyleContext (from bholley:simplify_local_context); r=emilio
https://bugzilla.mozilla.org/show_bug.cgi?id=1378540 Source-Repo: https://github.com/servo/servo Source-Revision: 8923a9e5f0cc292062f852babe878326aff656ef --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : fd5436ab04b074ecab59f7341e77590975f62656
This commit is contained in:
Родитель
c5c6d606ca
Коммит
df77fb2e20
|
@ -18,39 +18,12 @@ use script_layout_interface::{PendingImage, PendingImageState};
|
|||
use script_traits::PaintWorkletExecutor;
|
||||
use script_traits::UntrustedNodeAddress;
|
||||
use servo_url::ServoUrl;
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use style::context::{SharedStyleContext, ThreadLocalStyleContext};
|
||||
use style::dom::TElement;
|
||||
|
||||
/// TLS data scoped to the traversal.
|
||||
pub struct ScopedThreadLocalLayoutContext<E: TElement> {
|
||||
pub style_context: ThreadLocalStyleContext<E>,
|
||||
}
|
||||
|
||||
impl<E: TElement> ScopedThreadLocalLayoutContext<E> {
|
||||
pub fn new(context: &LayoutContext) -> Self {
|
||||
ScopedThreadLocalLayoutContext {
|
||||
style_context: ThreadLocalStyleContext::new(&context.style_context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: TElement> Borrow<ThreadLocalStyleContext<E>> for ScopedThreadLocalLayoutContext<E> {
|
||||
fn borrow(&self) -> &ThreadLocalStyleContext<E> {
|
||||
&self.style_context
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: TElement> BorrowMut<ThreadLocalStyleContext<E>> for ScopedThreadLocalLayoutContext<E> {
|
||||
fn borrow_mut(&mut self) -> &mut ThreadLocalStyleContext<E> {
|
||||
&mut self.style_context
|
||||
}
|
||||
}
|
||||
use style::context::SharedStyleContext;
|
||||
|
||||
thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<FontContext>> = RefCell::new(None));
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use atomic_refcell::AtomicRefCell;
|
||||
use construct::FlowConstructor;
|
||||
use context::{LayoutContext, ScopedThreadLocalLayoutContext};
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::DisplayListBuildState;
|
||||
use flow::{self, PreorderFlowTraversal};
|
||||
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
|
||||
|
@ -55,10 +55,8 @@ impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
|
|||
E::ConcreteNode: LayoutNode,
|
||||
E::FontMetricsProvider: Send,
|
||||
{
|
||||
type ThreadLocalContext = ScopedThreadLocalLayoutContext<E>;
|
||||
|
||||
fn process_preorder(&self, traversal_data: &PerLevelTraversalData,
|
||||
thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode) {
|
||||
context: &mut StyleContext<E>, node: E::ConcreteNode) {
|
||||
// FIXME(pcwalton): Stop allocating here. Ideally this should just be
|
||||
// done by the HTML parser.
|
||||
node.initialize_data();
|
||||
|
@ -66,16 +64,12 @@ impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
|
|||
if !node.is_text_node() {
|
||||
let el = node.as_element().unwrap();
|
||||
let mut data = el.mutate_data().unwrap();
|
||||
let mut context = StyleContext {
|
||||
shared: &self.context.shared_context(),
|
||||
thread_local: &mut thread_local.style_context,
|
||||
};
|
||||
recalc_style_at(self, traversal_data, &mut context, el, &mut data);
|
||||
recalc_style_at(self, traversal_data, context, el, &mut data);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_postorder(&self, thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode) {
|
||||
construct_flows_at(&self.context, thread_local, node);
|
||||
fn process_postorder(&self, _style_context: &mut StyleContext<E>, node: E::ConcreteNode) {
|
||||
construct_flows_at(&self.context, node);
|
||||
}
|
||||
|
||||
fn text_node_needs_traversal(node: E::ConcreteNode) -> bool {
|
||||
|
@ -100,10 +94,6 @@ impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
|
|||
&self.context.style_context
|
||||
}
|
||||
|
||||
fn create_thread_local_context(&self) -> Self::ThreadLocalContext {
|
||||
ScopedThreadLocalLayoutContext::new(&self.context)
|
||||
}
|
||||
|
||||
fn is_parallel(&self) -> bool {
|
||||
self.driver.is_parallel()
|
||||
}
|
||||
|
@ -118,9 +108,7 @@ pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayo
|
|||
/// The flow construction traversal, which builds flows for styled nodes.
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
fn construct_flows_at<N>(context: &LayoutContext,
|
||||
_thread_local: &mut ScopedThreadLocalLayoutContext<N::ConcreteElement>,
|
||||
node: N)
|
||||
fn construct_flows_at<N>(context: &LayoutContext, node: N)
|
||||
where N: LayoutNode,
|
||||
{
|
||||
debug!("construct_flows_at: {:?}", node);
|
||||
|
|
|
@ -296,7 +296,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
|||
///
|
||||
/// XXXManishearth It would be better to make this a type parameter on
|
||||
/// ThreadLocalStyleContext and StyleContext
|
||||
type FontMetricsProvider: FontMetricsProvider;
|
||||
type FontMetricsProvider: FontMetricsProvider + Send;
|
||||
|
||||
/// Get this element as a node.
|
||||
fn as_node(&self) -> Self::ConcreteNode;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! Gecko-specific bits for the styling DOM traversal.
|
||||
|
||||
use atomic_refcell::AtomicRefCell;
|
||||
use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
|
||||
use context::{SharedStyleContext, StyleContext};
|
||||
use data::ElementData;
|
||||
use dom::{NodeInfo, TNode};
|
||||
use gecko::wrapper::{GeckoElement, GeckoNode};
|
||||
|
@ -29,25 +29,19 @@ impl<'a> RecalcStyleOnly<'a> {
|
|||
}
|
||||
|
||||
impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> {
|
||||
type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>;
|
||||
|
||||
fn process_preorder(&self,
|
||||
traversal_data: &PerLevelTraversalData,
|
||||
thread_local: &mut Self::ThreadLocalContext,
|
||||
context: &mut StyleContext<GeckoElement<'le>>,
|
||||
node: GeckoNode<'le>)
|
||||
{
|
||||
if node.is_element() {
|
||||
let el = node.as_element().unwrap();
|
||||
let mut data = unsafe { el.ensure_data() }.borrow_mut();
|
||||
let mut context = StyleContext {
|
||||
shared: &self.shared,
|
||||
thread_local: thread_local,
|
||||
};
|
||||
recalc_style_at(self, traversal_data, &mut context, el, &mut data);
|
||||
recalc_style_at(self, traversal_data, context, el, &mut data);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_postorder(&self, _: &mut Self::ThreadLocalContext, _: GeckoNode<'le>) {
|
||||
fn process_postorder(&self, _: &mut StyleContext<GeckoElement<'le>>, _: GeckoNode<'le>) {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
|
@ -66,10 +60,6 @@ impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc>
|
|||
&self.shared
|
||||
}
|
||||
|
||||
fn create_thread_local_context(&self) -> Self::ThreadLocalContext {
|
||||
ThreadLocalStyleContext::new(&self.shared)
|
||||
}
|
||||
|
||||
fn is_parallel(&self) -> bool {
|
||||
self.driver.is_parallel()
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use context::TraversalStatistics;
|
||||
use context::{StyleContext, ThreadLocalStyleContext, TraversalStatistics};
|
||||
use dom::{OpaqueNode, SendNode, TElement, TNode};
|
||||
use rayon;
|
||||
use scoped_tls::ScopedTLS;
|
||||
|
@ -84,7 +84,7 @@ pub fn traverse_dom<E, D>(traversal: &D,
|
|||
let traversal_data = PerLevelTraversalData {
|
||||
current_dom_depth: depth,
|
||||
};
|
||||
let tls = ScopedTLS::<D::ThreadLocalContext>::new(pool);
|
||||
let tls = ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool);
|
||||
let root = root.as_node().opaque();
|
||||
|
||||
pool.install(|| {
|
||||
|
@ -124,11 +124,11 @@ pub fn traverse_dom<E, D>(traversal: &D,
|
|||
#[inline(never)]
|
||||
fn create_thread_local_context<'scope, E, D>(
|
||||
traversal: &'scope D,
|
||||
slot: &mut Option<D::ThreadLocalContext>)
|
||||
slot: &mut Option<ThreadLocalStyleContext<E>>)
|
||||
where E: TElement + 'scope,
|
||||
D: DomTraversal<E>
|
||||
{
|
||||
*slot = Some(traversal.create_thread_local_context())
|
||||
*slot = Some(ThreadLocalStyleContext::new(traversal.shared_context()));
|
||||
}
|
||||
|
||||
/// A parallel top-down DOM traversal.
|
||||
|
@ -152,7 +152,7 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
|
|||
scope: &'a rayon::Scope<'scope>,
|
||||
pool: &'scope rayon::ThreadPool,
|
||||
traversal: &'scope D,
|
||||
tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
|
||||
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>)
|
||||
where E: TElement + 'scope,
|
||||
D: DomTraversal<E>,
|
||||
{
|
||||
|
@ -167,7 +167,11 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
|
|||
// Scope the borrow of the TLS so that the borrow is dropped before
|
||||
// a potential recursive call when we pass TailCall.
|
||||
let mut tlc = tls.ensure(
|
||||
|slot: &mut Option<D::ThreadLocalContext>| create_thread_local_context(traversal, slot));
|
||||
|slot: &mut Option<ThreadLocalStyleContext<E>>| create_thread_local_context(traversal, slot));
|
||||
let mut context = StyleContext {
|
||||
shared: traversal.shared_context(),
|
||||
thread_local: &mut *tlc,
|
||||
};
|
||||
|
||||
for n in nodes {
|
||||
// If the last node we processed produced children, spawn them off
|
||||
|
@ -199,15 +203,15 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
|
|||
|
||||
let node = **n;
|
||||
let mut children_to_process = 0isize;
|
||||
traversal.process_preorder(&traversal_data, &mut *tlc, node);
|
||||
traversal.process_preorder(&traversal_data, &mut context, node);
|
||||
if let Some(el) = node.as_element() {
|
||||
traversal.traverse_children(&mut *tlc, el, |_tlc, kid| {
|
||||
traversal.traverse_children(&mut context, el, |_context, kid| {
|
||||
children_to_process += 1;
|
||||
discovered_child_nodes.push(unsafe { SendNode::new(kid) })
|
||||
});
|
||||
}
|
||||
|
||||
traversal.handle_postorder_traversal(&mut *tlc, root, node,
|
||||
traversal.handle_postorder_traversal(&mut context, root, node,
|
||||
children_to_process);
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +260,7 @@ fn traverse_nodes<'a, 'scope, E, D>(nodes: &[SendNode<E::ConcreteNode>],
|
|||
scope: &'a rayon::Scope<'scope>,
|
||||
pool: &'scope rayon::ThreadPool,
|
||||
traversal: &'scope D,
|
||||
tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
|
||||
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>)
|
||||
where E: TElement + 'scope,
|
||||
D: DomTraversal<E>,
|
||||
{
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use context::{StyleContext, ThreadLocalStyleContext};
|
||||
use dom::{TElement, TNode};
|
||||
use std::borrow::BorrowMut;
|
||||
use std::collections::VecDeque;
|
||||
use time;
|
||||
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
|
||||
|
@ -28,7 +28,12 @@ pub fn traverse_dom<E, D>(traversal: &D,
|
|||
debug_assert!(token.should_traverse());
|
||||
|
||||
let mut discovered = VecDeque::<WorkItem<E::ConcreteNode>>::with_capacity(16);
|
||||
let mut tlc = traversal.create_thread_local_context();
|
||||
let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
|
||||
let mut context = StyleContext {
|
||||
shared: traversal.shared_context(),
|
||||
thread_local: &mut tlc,
|
||||
};
|
||||
|
||||
let root_depth = root.depth();
|
||||
|
||||
if token.traverse_unstyled_children_only() {
|
||||
|
@ -47,25 +52,24 @@ pub fn traverse_dom<E, D>(traversal: &D,
|
|||
while let Some(WorkItem(node, depth)) = discovered.pop_front() {
|
||||
let mut children_to_process = 0isize;
|
||||
let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
|
||||
traversal.process_preorder(&traversal_data, &mut tlc, node);
|
||||
traversal.process_preorder(&traversal_data, &mut context, node);
|
||||
|
||||
if let Some(el) = node.as_element() {
|
||||
traversal.traverse_children(&mut tlc, el, |_tlc, kid| {
|
||||
traversal.traverse_children(&mut context, el, |_context, kid| {
|
||||
children_to_process += 1;
|
||||
discovered.push_back(WorkItem(kid, depth + 1))
|
||||
});
|
||||
}
|
||||
|
||||
traversal.handle_postorder_traversal(&mut tlc, root.as_node().opaque(),
|
||||
traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
|
||||
node, children_to_process);
|
||||
}
|
||||
|
||||
// Dump statistics to stdout if requested.
|
||||
if dump_stats {
|
||||
let tlsc = tlc.borrow_mut();
|
||||
tlsc.statistics.finish(traversal, start_time.unwrap());
|
||||
if tlsc.statistics.is_large_traversal() {
|
||||
println!("{}", tlsc.statistics);
|
||||
context.thread_local.statistics.finish(traversal, start_time.unwrap());
|
||||
if context.thread_local.statistics.is_large_traversal() {
|
||||
println!("{}", context.thread_local.statistics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! Traversing the DOM tree; the bloom filter.
|
||||
|
||||
use atomic_refcell::AtomicRefCell;
|
||||
use context::{ElementCascadeInputs, StyleContext, SharedStyleContext, ThreadLocalStyleContext};
|
||||
use context::{ElementCascadeInputs, StyleContext, SharedStyleContext};
|
||||
use data::{ElementData, ElementStyles};
|
||||
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
|
||||
use invalidation::element::restyle_hints::{RECASCADE_SELF, RECASCADE_DESCENDANTS, RestyleHint};
|
||||
|
@ -13,7 +13,6 @@ use matching::{ChildCascadeRequirement, MatchMethods};
|
|||
use sharing::{StyleSharingBehavior, StyleSharingTarget};
|
||||
#[cfg(feature = "servo")] use servo_config::opts;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
/// A per-traversal-level chunk of data. This is sent down by the traversal, and
|
||||
/// currently only holds the dom depth for the bloom filter.
|
||||
|
@ -138,22 +137,17 @@ fn is_servo_nonincremental_layout() -> bool {
|
|||
/// A DOM Traversal trait, that is used to generically implement styling for
|
||||
/// Gecko and Servo.
|
||||
pub trait DomTraversal<E: TElement> : Sync {
|
||||
/// The thread-local context, used to store non-thread-safe stuff that needs
|
||||
/// to be used in the traversal, and of which we use one per worker, like
|
||||
/// the bloom filter, for example.
|
||||
type ThreadLocalContext: Send + BorrowMut<ThreadLocalStyleContext<E>>;
|
||||
|
||||
/// Process `node` on the way down, before its children have been processed.
|
||||
fn process_preorder(&self,
|
||||
data: &PerLevelTraversalData,
|
||||
thread_local: &mut Self::ThreadLocalContext,
|
||||
context: &mut StyleContext<E>,
|
||||
node: E::ConcreteNode);
|
||||
|
||||
/// Process `node` on the way up, after its children have been processed.
|
||||
///
|
||||
/// This is only executed if `needs_postorder_traversal` returns true.
|
||||
fn process_postorder(&self,
|
||||
thread_local: &mut Self::ThreadLocalContext,
|
||||
contect: &mut StyleContext<E>,
|
||||
node: E::ConcreteNode);
|
||||
|
||||
/// Boolean that specifies whether a bottom up traversal should be
|
||||
|
@ -177,7 +171,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
/// call durign the parallel traversal.
|
||||
fn handle_postorder_traversal(
|
||||
&self,
|
||||
thread_local: &mut Self::ThreadLocalContext,
|
||||
context: &mut StyleContext<E>,
|
||||
root: OpaqueNode,
|
||||
mut node: E::ConcreteNode,
|
||||
children_to_process: isize
|
||||
|
@ -190,7 +184,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
if children_to_process == 0 {
|
||||
// We are a leaf. Walk up the chain.
|
||||
loop {
|
||||
self.process_postorder(thread_local, node);
|
||||
self.process_postorder(context, node);
|
||||
if node.opaque() == root {
|
||||
break;
|
||||
}
|
||||
|
@ -404,7 +398,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
/// a parameter to keep the logs tidy.
|
||||
fn should_traverse_children(
|
||||
&self,
|
||||
thread_local: &mut ThreadLocalStyleContext<E>,
|
||||
context: &mut StyleContext<E>,
|
||||
parent: E,
|
||||
parent_data: &ElementData,
|
||||
log: LogBehavior
|
||||
|
@ -442,7 +436,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
// happens, we may just end up doing wasted work, since Gecko
|
||||
// recursively drops Servo ElementData when the XBL insertion parent of
|
||||
// an Element is changed.
|
||||
if cfg!(feature = "gecko") && thread_local.is_initial_style() &&
|
||||
if cfg!(feature = "gecko") && context.thread_local.is_initial_style() &&
|
||||
parent_data.styles.primary().has_moz_binding() {
|
||||
if log.allow() {
|
||||
debug!("Parent {:?} has XBL binding, deferring traversal",
|
||||
|
@ -458,23 +452,23 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
/// should be enqueued for processing.
|
||||
fn traverse_children<F>(
|
||||
&self,
|
||||
thread_local: &mut Self::ThreadLocalContext,
|
||||
context: &mut StyleContext<E>,
|
||||
parent: E,
|
||||
mut f: F
|
||||
)
|
||||
where
|
||||
F: FnMut(&mut Self::ThreadLocalContext, E::ConcreteNode)
|
||||
F: FnMut(&mut StyleContext<E>, E::ConcreteNode)
|
||||
{
|
||||
// Check if we're allowed to traverse past this element.
|
||||
let should_traverse =
|
||||
self.should_traverse_children(
|
||||
thread_local.borrow_mut(),
|
||||
context,
|
||||
parent,
|
||||
&parent.borrow_data().unwrap(),
|
||||
MayLog
|
||||
);
|
||||
|
||||
thread_local.borrow_mut().end_element(parent);
|
||||
context.thread_local.end_element(parent);
|
||||
if !should_traverse {
|
||||
return;
|
||||
}
|
||||
|
@ -495,7 +489,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
}
|
||||
}
|
||||
f(thread_local, kid);
|
||||
f(context, kid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -517,9 +511,6 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
/// Return the shared style context common to all worker threads.
|
||||
fn shared_context(&self) -> &SharedStyleContext;
|
||||
|
||||
/// Creates a thread-local context.
|
||||
fn create_thread_local_context(&self) -> Self::ThreadLocalContext;
|
||||
|
||||
/// Whether we're performing a parallel traversal.
|
||||
///
|
||||
/// NB: We do this check on runtime. We could guarantee correctness in this
|
||||
|
@ -763,7 +754,7 @@ where
|
|||
// Preprocess children, propagating restyle hints and handling sibling
|
||||
// relationships.
|
||||
let should_traverse_children = traversal.should_traverse_children(
|
||||
&mut context.thread_local,
|
||||
context,
|
||||
element,
|
||||
&data,
|
||||
DontLog
|
||||
|
|
Загрузка…
Ссылка в новой задаче