diff --git a/components/style/dom.rs b/components/style/dom.rs index 3ce4a716e68..465590d03f5 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -16,6 +16,7 @@ use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement}; use sink::Push; use std::fmt; use std::fmt::Debug; +use std::ops::Deref; use std::sync::Arc; use stylist::ApplicableDeclarationBlock; @@ -262,3 +263,38 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre /// native anonymous content can opt out of this style fixup.) fn skip_root_and_item_based_display_fixup(&self) -> bool; } + +/// TNode and TElement aren't Send because we want to be careful and explicit +/// about our parallel traversal. However, there are certain situations +/// (including but not limited to the traversal) where we need to send DOM +/// objects to other threads. + +#[derive(Debug, PartialEq)] +pub struct SendNode(N); +unsafe impl Send for SendNode {} +impl SendNode { + pub unsafe fn new(node: N) -> Self { + SendNode(node) + } +} +impl Deref for SendNode { + type Target = N; + fn deref(&self) -> &N { + &self.0 + } +} + +#[derive(Debug, PartialEq)] +pub struct SendElement(E); +unsafe impl Send for SendElement {} +impl SendElement { + pub unsafe fn new(el: E) -> Self { + SendElement(el) + } +} +impl Deref for SendElement { + type Target = E; + fn deref(&self) -> &E { + &self.0 + } +} diff --git a/components/style/matching.rs b/components/style/matching.rs index a1580e404b4..ff89dd07003 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -13,7 +13,7 @@ use cache::LRUCache; use cascade_info::CascadeInfo; use context::{SharedStyleContext, StyleContext}; use data::{ComputedStyle, ElementData, ElementStyles, PseudoStyles}; -use dom::{TElement, TNode}; +use dom::{SendElement, TElement, TNode}; use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade}; use properties::longhands::display::computed_value as display; use rule_tree::StrongRuleNode; @@ -65,19 +65,13 @@ impl MatchResults { } } -// TElement isn't Send because we want to be careful and explicit about our -// parallel traversal, but we need the candidates to be Send so that we can stick -// them in ScopedTLS. -#[derive(Debug, PartialEq)] -struct SendElement(pub E); -unsafe impl Send for SendElement {} - /// Information regarding a candidate. /// /// TODO: We can stick a lot more info here. #[derive(Debug)] struct StyleSharingCandidate { - /// The element. + /// The element. We use SendElement here so that the cache may live in + /// ScopedTLS. element: SendElement, /// The cached common style affecting attribute info. common_style_affecting_attributes: Option, @@ -353,7 +347,7 @@ impl StyleSharingCandidateCache { element, parent); self.cache.insert(StyleSharingCandidate { - element: SendElement(*element), + element: unsafe { SendElement::new(*element) }, common_style_affecting_attributes: None, class_attributes: None, }, ()); @@ -501,9 +495,8 @@ trait PrivateMatchMethods: TElement { shared_context: &SharedStyleContext, candidate: &mut StyleSharingCandidate) -> Result { - let candidate_element = candidate.element.0; - element_matches_candidate(self, candidate, &candidate_element, - shared_context) + let candidate_element = *candidate.element; + element_matches_candidate(self, candidate, &candidate_element, shared_context) } }