style: Remove the Mutex from new_animations_sender by moving it to the local StyleContext.

As a follow-up, we could move all the data living under a mutex in the
SharedLayoutContext only in order to create the local context to the same place.

This should increase animation performance when there are multiple animations in
one page that happen to be on different threads.
This commit is contained in:
Emilio Cobos Álvarez 2016-06-29 20:04:30 -07:00
parent 5478e605ae
commit 203d2a62c2
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
15 changed files with 166 additions and 134 deletions

View file

@ -25,15 +25,14 @@ use std::hash::BuildHasherDefault;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use style::context::{LocalStyleContext, StyleContext}; use style::context::{LocalStyleContext, StyleContext};
use style::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
use style::properties::ServoComputedValues;
use style::selector_impl::ServoSelectorImpl; use style::selector_impl::ServoSelectorImpl;
use style::servo::SharedStyleContext; use style::servo::SharedStyleContext;
use url::Url; use url::Url;
use util::opts; use util::opts;
struct LocalLayoutContext { struct LocalLayoutContext {
style_context: LocalStyleContext<ServoComputedValues>, style_context: LocalStyleContext<ServoSelectorImpl>,
font_context: RefCell<FontContext>, font_context: RefCell<FontContext>,
} }
@ -64,11 +63,10 @@ fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext)
context context
} else { } else {
let font_cache_thread = shared_layout_context.font_cache_thread.lock().unwrap().clone(); 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 { let context = Rc::new(LocalLayoutContext {
style_context: LocalStyleContext { style_context: LocalStyleContext::new(&local_style_data),
applicable_declarations_cache: RefCell::new(ApplicableDeclarationsCache::new()),
style_sharing_candidate_cache: RefCell::new(StyleSharingCandidateCache::new()),
},
font_context: RefCell::new(FontContext::new(font_cache_thread)), font_context: RefCell::new(FontContext::new(font_cache_thread)),
}); });
*r = Some(context.clone()); *r = Some(context.clone());
@ -110,7 +108,7 @@ impl<'a> StyleContext<'a, ServoSelectorImpl> for LayoutContext<'a> {
&self.shared.style_context &self.shared.style_context
} }
fn local_context(&self) -> &LocalStyleContext<ServoComputedValues> { fn local_context(&self) -> &LocalStyleContext<ServoSelectorImpl> {
&self.cached_local_layout_context.style_context &self.cached_local_layout_context.style_context
} }
} }

View file

@ -108,7 +108,7 @@ use style::parallel::WorkQueueData;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::refcell::RefCell; use style::refcell::RefCell;
use style::selector_matching::USER_OR_USER_AGENT_STYLESHEETS; use style::selector_matching::USER_OR_USER_AGENT_STYLESHEETS;
use style::servo::{Animation, SharedStyleContext, Stylesheet, Stylist}; use style::servo::{Animation, LocalStyleContextCreationInfo, SharedStyleContext, Stylesheet, Stylist};
use style::stylesheets::CSSRuleIteratorExt; use style::stylesheets::CSSRuleIteratorExt;
use url::Url; use url::Url;
use util::geometry::MAX_RECT; use util::geometry::MAX_RECT;
@ -488,6 +488,8 @@ impl LayoutThread {
screen_size_changed: bool, screen_size_changed: bool,
goal: ReflowGoal) goal: ReflowGoal)
-> SharedLayoutContext { -> SharedLayoutContext {
let local_style_context_creation_data = LocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
SharedLayoutContext { SharedLayoutContext {
style_context: SharedStyleContext { style_context: SharedStyleContext {
viewport_size: self.viewport_size.clone(), viewport_size: self.viewport_size.clone(),
@ -495,10 +497,10 @@ impl LayoutThread {
stylist: rw_data.stylist.clone(), stylist: rw_data.stylist.clone(),
generation: self.generation, generation: self.generation,
goal: goal, goal: goal,
new_animations_sender: Mutex::new(self.new_animations_sender.clone()),
running_animations: self.running_animations.clone(), running_animations: self.running_animations.clone(),
expired_animations: self.expired_animations.clone(), expired_animations: self.expired_animations.clone(),
error_reporter: self.error_reporter.clone(), error_reporter: self.error_reporter.clone(),
local_context_creation_data: Mutex::new(local_style_context_creation_data),
}, },
image_cache_thread: self.image_cache_thread.clone(), image_cache_thread: self.image_cache_thread.clone(),
image_cache_sender: Mutex::new(self.image_cache_sender.clone()), image_cache_sender: Mutex::new(self.image_cache_sender.clone()),

View file

@ -19,8 +19,8 @@ use properties::style_struct_traits::Box;
use properties::{self, ComputedValues}; use properties::{self, ComputedValues};
use selector_impl::SelectorImplExt; use selector_impl::SelectorImplExt;
use selectors::matching::DeclarationBlock; use selectors::matching::DeclarationBlock;
use std::sync::Arc;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use string_cache::Atom; use string_cache::Atom;
use time; use time;
use values::computed::Time; use values::computed::Time;
@ -356,7 +356,7 @@ impl<T> GetMod for Vec<T> {
// //
// TODO(emilio): Take rid of this mutex splitting SharedLayoutContex into a // TODO(emilio): Take rid of this mutex splitting SharedLayoutContex into a
// cloneable part and a non-cloneable part.. // cloneable part and a non-cloneable part..
pub fn start_transitions_if_applicable<Impl: SelectorImplExt>(new_animations_sender: &Mutex<Sender<Animation<Impl>>>, pub fn start_transitions_if_applicable<Impl: SelectorImplExt>(new_animations_sender: &Sender<Animation<Impl>>,
node: OpaqueNode, node: OpaqueNode,
old_style: &Impl::ComputedValues, old_style: &Impl::ComputedValues,
new_style: &mut Arc<Impl::ComputedValues>) new_style: &mut Arc<Impl::ComputedValues>)
@ -377,7 +377,6 @@ pub fn start_transitions_if_applicable<Impl: SelectorImplExt>(new_animations_sen
let start_time = let start_time =
now + (box_style.transition_delay.0.get_mod(i).seconds() as f64); now + (box_style.transition_delay.0.get_mod(i).seconds() as f64);
new_animations_sender new_animations_sender
.lock().unwrap()
.send(Animation::Transition(node, start_time, AnimationFrame { .send(Animation::Transition(node, start_time, AnimationFrame {
duration: box_style.transition_duration.0.get_mod(i).seconds() as f64, duration: box_style.transition_duration.0.get_mod(i).seconds() as f64,
property_animation: property_animation, property_animation: property_animation,
@ -417,6 +416,7 @@ fn compute_style_for_animation_step<Impl: SelectorImplExt>(context: &SharedStyle
} }
pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContext<Impl>, pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContext<Impl>,
new_animations_sender: &Sender<Animation<Impl>>,
node: OpaqueNode, node: OpaqueNode,
new_style: &Arc<Impl::ComputedValues>) -> bool new_style: &Arc<Impl::ComputedValues>) -> bool
{ {
@ -465,19 +465,18 @@ pub fn maybe_start_animations<Impl: SelectorImplExt>(context: &SharedStyleContex
}; };
context.new_animations_sender new_animations_sender
.lock().unwrap() .send(Animation::Keyframes(node, name.clone(), KeyframesAnimationState {
.send(Animation::Keyframes(node, name.clone(), KeyframesAnimationState { started_at: animation_start,
started_at: animation_start, duration: duration as f64,
duration: duration as f64, delay: delay as f64,
delay: delay as f64, iteration_state: iteration_state,
iteration_state: iteration_state, running_state: running_state,
running_state: running_state, direction: animation_direction,
direction: animation_direction, current_direction: initial_direction,
current_direction: initial_direction, expired: false,
expired: false, cascade_style: new_style.clone(),
cascade_style: new_style.clone(), })).unwrap();
})).unwrap();
had_animations = true; had_animations = true;
} }
} }

View file

@ -10,7 +10,6 @@ use dom::OpaqueNode;
use error_reporting::ParseErrorReporter; use error_reporting::ParseErrorReporter;
use euclid::Size2D; use euclid::Size2D;
use matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache}; use matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
use properties::ComputedValues;
use selector_impl::SelectorImplExt; use selector_impl::SelectorImplExt;
use selector_matching::Stylist; use selector_matching::Stylist;
use std::cell::RefCell; use std::cell::RefCell;
@ -18,6 +17,19 @@ use std::collections::HashMap;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
/// This structure is used to create a local style context from a shared one.
pub struct LocalStyleContextCreationInfo<Impl: SelectorImplExt> {
new_animations_sender: Sender<Animation<Impl>>,
}
impl<Impl: SelectorImplExt> LocalStyleContextCreationInfo<Impl> {
pub fn new(animations_sender: Sender<Animation<Impl>>) -> Self {
LocalStyleContextCreationInfo {
new_animations_sender: animations_sender,
}
}
}
pub struct SharedStyleContext<Impl: SelectorImplExt> { pub struct SharedStyleContext<Impl: SelectorImplExt> {
/// The current viewport size. /// The current viewport size.
pub viewport_size: Size2D<Au>, pub viewport_size: Size2D<Au>,
@ -32,10 +44,6 @@ pub struct SharedStyleContext<Impl: SelectorImplExt> {
/// This can be used to easily check for invalid stale data. /// This can be used to easily check for invalid stale data.
pub generation: u32, pub generation: u32,
/// A channel on which new animations that have been triggered by style recalculation can be
/// sent.
pub new_animations_sender: Mutex<Sender<Animation<Impl>>>,
/// Why is this reflow occurring /// Why is this reflow occurring
pub goal: ReflowGoal, pub goal: ReflowGoal,
@ -47,16 +55,32 @@ pub struct SharedStyleContext<Impl: SelectorImplExt> {
///The CSS error reporter for all CSS loaded in this layout thread ///The CSS error reporter for all CSS loaded in this layout thread
pub error_reporter: Box<ParseErrorReporter + Sync>, pub error_reporter: Box<ParseErrorReporter + Sync>,
/// Data needed to create the local style context from the shared one.
pub local_context_creation_data: Mutex<LocalStyleContextCreationInfo<Impl>>,
} }
pub struct LocalStyleContext<C: ComputedValues> { pub struct LocalStyleContext<Impl: SelectorImplExt> {
pub applicable_declarations_cache: RefCell<ApplicableDeclarationsCache<C>>, pub applicable_declarations_cache: RefCell<ApplicableDeclarationsCache<Impl::ComputedValues>>,
pub style_sharing_candidate_cache: RefCell<StyleSharingCandidateCache<C>>, pub style_sharing_candidate_cache: RefCell<StyleSharingCandidateCache<Impl::ComputedValues>>,
/// A channel on which new animations that have been triggered by style
/// recalculation can be sent.
pub new_animations_sender: Sender<Animation<Impl>>,
}
impl<Impl: SelectorImplExt> LocalStyleContext<Impl> {
pub fn new(local_context_creation_data: &LocalStyleContextCreationInfo<Impl>) -> Self {
LocalStyleContext {
applicable_declarations_cache: RefCell::new(ApplicableDeclarationsCache::new()),
style_sharing_candidate_cache: RefCell::new(StyleSharingCandidateCache::new()),
new_animations_sender: local_context_creation_data.new_animations_sender.clone(),
}
}
} }
pub trait StyleContext<'a, Impl: SelectorImplExt> { pub trait StyleContext<'a, Impl: SelectorImplExt> {
fn shared_context(&self) -> &'a SharedStyleContext<Impl>; fn shared_context(&self) -> &'a SharedStyleContext<Impl>;
fn local_context(&self) -> &LocalStyleContext<Impl::ComputedValues>; fn local_context(&self) -> &LocalStyleContext<Impl>;
} }
/// Why we're doing reflow. /// Why we're doing reflow.

View file

@ -7,7 +7,7 @@
#![allow(unsafe_code)] #![allow(unsafe_code)]
use animation::{self, Animation}; use animation::{self, Animation};
use context::{SharedStyleContext, LocalStyleContext}; use context::{StyleContext, SharedStyleContext};
use data::PrivateStyleData; use data::PrivateStyleData;
use dom::{TElement, TNode, TRestyleDamage}; use dom::{TElement, TNode, TRestyleDamage};
use properties::{ComputedValues, PropertyDeclaration, cascade}; use properties::{ComputedValues, PropertyDeclaration, cascade};
@ -371,19 +371,22 @@ trait PrivateMatchMethods: TNode
/// ///
/// Note that animations only apply to nodes or ::before or ::after /// Note that animations only apply to nodes or ::before or ::after
/// pseudo-elements. /// pseudo-elements.
fn cascade_node_pseudo_element(&self, fn cascade_node_pseudo_element<'a, Ctx>(&self,
context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>, context: &Ctx,
parent_style: Option<&Arc<Self::ConcreteComputedValues>>, parent_style: Option<&Arc<Self::ConcreteComputedValues>>,
applicable_declarations: &[DeclarationBlock], applicable_declarations: &[DeclarationBlock],
mut style: Option<&mut Arc<Self::ConcreteComputedValues>>, mut style: Option<&mut Arc<Self::ConcreteComputedValues>>,
applicable_declarations_cache: applicable_declarations_cache:
&mut ApplicableDeclarationsCache<Self::ConcreteComputedValues>, &mut ApplicableDeclarationsCache<Self::ConcreteComputedValues>,
shareable: bool, shareable: bool,
animate_properties: bool) animate_properties: bool)
-> (Self::ConcreteRestyleDamage, Arc<Self::ConcreteComputedValues>) { -> (Self::ConcreteRestyleDamage, Arc<Self::ConcreteComputedValues>)
where Ctx: StyleContext<'a, <Self::ConcreteElement as Element>::Impl> {
let mut cacheable = true; let mut cacheable = true;
let shared_context = context.shared_context();
if animate_properties { if animate_properties {
cacheable = !self.update_animations_for_cascade(context, &mut style) && cacheable; cacheable = !self.update_animations_for_cascade(shared_context,
&mut style) && cacheable;
} }
let this_style; let this_style;
@ -395,22 +398,22 @@ trait PrivateMatchMethods: TNode
None => None, None => None,
}; };
let (the_style, is_cacheable) = cascade(context.viewport_size, let (the_style, is_cacheable) = cascade(shared_context.viewport_size,
applicable_declarations, applicable_declarations,
shareable, shareable,
Some(&***parent_style), Some(&***parent_style),
cached_computed_values, cached_computed_values,
context.error_reporter.clone()); shared_context.error_reporter.clone());
cacheable = cacheable && is_cacheable; cacheable = cacheable && is_cacheable;
this_style = the_style this_style = the_style
} }
None => { None => {
let (the_style, is_cacheable) = cascade(context.viewport_size, let (the_style, is_cacheable) = cascade(shared_context.viewport_size,
applicable_declarations, applicable_declarations,
shareable, shareable,
None, None,
None, None,
context.error_reporter.clone()); shared_context.error_reporter.clone());
cacheable = cacheable && is_cacheable; cacheable = cacheable && is_cacheable;
this_style = the_style this_style = the_style
} }
@ -419,10 +422,12 @@ trait PrivateMatchMethods: TNode
let mut this_style = Arc::new(this_style); let mut this_style = Arc::new(this_style);
if animate_properties { if animate_properties {
let new_animations_sender = &context.local_context().new_animations_sender;
let this_opaque = self.opaque(); let this_opaque = self.opaque();
// Trigger any present animations if necessary. // Trigger any present animations if necessary.
let mut animations_started = animation::maybe_start_animations::<<Self::ConcreteElement as Element>::Impl>( let mut animations_started = animation::maybe_start_animations::<<Self::ConcreteElement as Element>::Impl>(
&context, &shared_context,
new_animations_sender,
this_opaque, this_opaque,
&this_style); &this_style);
@ -431,7 +436,7 @@ trait PrivateMatchMethods: TNode
if let Some(ref style) = style { if let Some(ref style) = style {
animations_started |= animations_started |=
animation::start_transitions_if_applicable::<<Self::ConcreteElement as Element>::Impl>( animation::start_transitions_if_applicable::<<Self::ConcreteElement as Element>::Impl>(
&context.new_animations_sender, new_animations_sender,
this_opaque, this_opaque,
&**style, &**style,
&mut this_style); &mut this_style);
@ -658,12 +663,13 @@ pub trait MatchMethods : TNode {
} }
} }
unsafe fn cascade_node(&self, unsafe fn cascade_node<'a, Ctx>(&self,
context: &SharedStyleContext<<Self::ConcreteElement as Element>::Impl>, context: &Ctx,
local_context: &LocalStyleContext<Self::ConcreteComputedValues>, parent: Option<Self>,
parent: Option<Self>, applicable_declarations:
applicable_declarations: &ApplicableDeclarations<<Self::ConcreteElement as Element>::Impl>) &ApplicableDeclarations<<Self::ConcreteElement as Element>::Impl>)
where <Self::ConcreteElement as Element>::Impl: SelectorImplExt<ComputedValues = Self::ConcreteComputedValues> where <Self::ConcreteElement as Element>::Impl: SelectorImplExt<ComputedValues = Self::ConcreteComputedValues>,
Ctx: StyleContext<'a, <Self::ConcreteElement as Element>::Impl>
{ {
// Get our parent's style. This must be unsafe so that we don't touch the parent's // Get our parent's style. This must be unsafe so that we don't touch the parent's
// borrow flags. // borrow flags.
@ -679,7 +685,7 @@ pub trait MatchMethods : TNode {
}; };
let mut applicable_declarations_cache = let mut applicable_declarations_cache =
local_context.applicable_declarations_cache.borrow_mut(); context.local_context().applicable_declarations_cache.borrow_mut();
let damage; let damage;
if self.is_text_node() { if self.is_text_node() {

View file

@ -45,7 +45,7 @@ pub fn traverse_dom<N, C>(root: N,
where N: TNode, C: DomTraversalContext<N> { where N: TNode, C: DomTraversalContext<N> {
run_queue_with_custom_work_data_type(queue, |queue| { run_queue_with_custom_work_data_type(queue, |queue| {
queue.push(WorkUnit { queue.push(WorkUnit {
fun: top_down_dom::<N, C>, fun: top_down_dom::<N, C>,
data: (Box::new(vec![root.to_unsafe()]), root.opaque()), data: (Box::new(vec![root.to_unsafe()]), root.opaque()),
}); });
}, queue_data); }, queue_data);

View file

@ -65,7 +65,7 @@ pub trait ElementExt: Element {
// NB: The `Clone` trait is here for convenience due to: // NB: The `Clone` trait is here for convenience due to:
// https://github.com/rust-lang/rust/issues/26925 // https://github.com/rust-lang/rust/issues/26925
pub trait SelectorImplExt : SelectorImpl + Clone + Debug + Sized { pub trait SelectorImplExt : SelectorImpl + Clone + Debug + Sized + 'static {
type ComputedValues: properties::ComputedValues; type ComputedValues: properties::ComputedValues;
fn pseudo_element_cascade_type(pseudo: &Self::PseudoElement) -> PseudoElementCascadeType; fn pseudo_element_cascade_type(pseudo: &Self::PseudoElement) -> PseudoElementCascadeType;

View file

@ -15,4 +15,5 @@ pub type Stylesheet = stylesheets::Stylesheet<ServoSelectorImpl>;
pub type PrivateStyleData = data::PrivateStyleData<ServoSelectorImpl, ServoComputedValues>; pub type PrivateStyleData = data::PrivateStyleData<ServoSelectorImpl, ServoComputedValues>;
pub type Stylist = selector_matching::Stylist<ServoSelectorImpl>; pub type Stylist = selector_matching::Stylist<ServoSelectorImpl>;
pub type SharedStyleContext = context::SharedStyleContext<ServoSelectorImpl>; pub type SharedStyleContext = context::SharedStyleContext<ServoSelectorImpl>;
pub type LocalStyleContextCreationInfo = context::LocalStyleContextCreationInfo<ServoSelectorImpl>;
pub type Animation = animation::Animation<ServoSelectorImpl>; pub type Animation = animation::Animation<ServoSelectorImpl>;

View file

@ -218,8 +218,7 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C,
// Perform the CSS cascade. // Perform the CSS cascade.
unsafe { unsafe {
node.cascade_node(&context.shared_context(), node.cascade_node(context,
&context.local_context(),
parent_opt, parent_opt,
&applicable_declarations); &applicable_declarations);
} }

53
ports/geckolib/context.rs Normal file
View file

@ -0,0 +1,53 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use selector_impl::{GeckoSelectorImpl, SharedStyleContext};
use std::cell::RefCell;
use std::rc::Rc;
use style::context::{LocalStyleContext, StyleContext};
thread_local!(static LOCAL_CONTEXT_KEY:
RefCell<Option<Rc<LocalStyleContext<GeckoSelectorImpl>>>> = RefCell::new(None));
// Keep this implementation in sync with the one in components/layout/context.rs.
fn create_or_get_local_context(shared: &SharedStyleContext)
-> Rc<LocalStyleContext<GeckoSelectorImpl>> {
LOCAL_CONTEXT_KEY.with(|r| {
let mut r = r.borrow_mut();
if let Some(context) = r.clone() {
if shared.screen_size_changed {
context.applicable_declarations_cache.borrow_mut().evict_all();
}
context
} else {
let context = Rc::new(LocalStyleContext::new(&shared.local_context_creation_data.lock().unwrap()));
*r = Some(context.clone());
context
}
})
}
pub struct StandaloneStyleContext<'a> {
pub shared: &'a SharedStyleContext,
cached_local_context: Rc<LocalStyleContext<GeckoSelectorImpl>>,
}
impl<'a> StandaloneStyleContext<'a> {
pub fn new(shared: &'a SharedStyleContext) -> Self {
let local_context = create_or_get_local_context(shared);
StandaloneStyleContext {
shared: shared,
cached_local_context: local_context,
}
}
}
impl<'a> StyleContext<'a, GeckoSelectorImpl> for StandaloneStyleContext<'a> {
fn shared_context(&self) -> &'a SharedStyleContext {
&self.shared
}
fn local_context(&self) -> &LocalStyleContext<GeckoSelectorImpl> {
&self.cached_local_context
}
}

View file

@ -6,7 +6,7 @@ use euclid::Size2D;
use euclid::size::TypedSize2D; use euclid::size::TypedSize2D;
use gecko_bindings::bindings::RawServoStyleSet; use gecko_bindings::bindings::RawServoStyleSet;
use num_cpus; use num_cpus;
use selector_impl::{GeckoSelectorImpl, Stylist, Stylesheet, SharedStyleContext}; use selector_impl::{Animation, SharedStyleContext, Stylist, Stylesheet};
use std::cmp; use std::cmp;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::mpsc::{channel, Receiver, Sender};
@ -18,8 +18,6 @@ use util::geometry::ViewportPx;
use util::thread_state; use util::thread_state;
use util::workqueue::WorkQueue; use util::workqueue::WorkQueue;
pub type Animation = ::style::animation::Animation<GeckoSelectorImpl>;
pub struct PerDocumentStyleData { pub struct PerDocumentStyleData {
/// Rule processor. /// Rule processor.
pub stylist: Arc<Stylist>, pub stylist: Arc<Stylist>,

View file

@ -22,7 +22,7 @@ use std::ptr;
use std::slice; use std::slice;
use std::str::from_utf8_unchecked; use std::str::from_utf8_unchecked;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use style::context::ReflowGoal; use style::context::{LocalStyleContextCreationInfo, ReflowGoal};
use style::dom::{TDocument, TElement, TNode}; use style::dom::{TDocument, TElement, TNode};
use style::error_reporting::StdoutErrorReporter; use style::error_reporting::StdoutErrorReporter;
use style::parallel; use style::parallel;
@ -77,7 +77,7 @@ pub extern "C" fn Servo_Initialize() -> () {
fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) { fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) {
debug_assert!(node.is_element() || node.is_text_node()); debug_assert!(node.is_element() || node.is_text_node());
let data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) }; let per_doc_data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) };
// Force the creation of our lazily-constructed initial computed values on // Force the creation of our lazily-constructed initial computed values on
// the main thread, since it's not safe to call elsewhere. // the main thread, since it's not safe to call elsewhere.
@ -88,24 +88,28 @@ fn restyle_subtree(node: GeckoNode, raw_data: *mut RawServoStyleSet) {
// along in startup than the sensible place to call Servo_Initialize. // along in startup than the sensible place to call Servo_Initialize.
GeckoComputedValues::initial_values(); GeckoComputedValues::initial_values();
let _needs_dirtying = Arc::get_mut(&mut data.stylist).unwrap() let _needs_dirtying = Arc::get_mut(&mut per_doc_data.stylist).unwrap()
.update(&data.stylesheets, data.stylesheets_changed); .update(&per_doc_data.stylesheets,
data.stylesheets_changed = false; per_doc_data.stylesheets_changed);
per_doc_data.stylesheets_changed = false;
let local_context_data =
LocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone());
let shared_style_context = SharedStyleContext { let shared_style_context = SharedStyleContext {
viewport_size: Size2D::new(Au(0), Au(0)), viewport_size: Size2D::new(Au(0), Au(0)),
screen_size_changed: false, screen_size_changed: false,
generation: 0, generation: 0,
goal: ReflowGoal::ForScriptQuery, goal: ReflowGoal::ForScriptQuery,
stylist: data.stylist.clone(), stylist: per_doc_data.stylist.clone(),
new_animations_sender: Mutex::new(data.new_animations_sender.clone()), running_animations: per_doc_data.running_animations.clone(),
running_animations: data.running_animations.clone(), expired_animations: per_doc_data.expired_animations.clone(),
expired_animations: data.expired_animations.clone(),
error_reporter: Box::new(StdoutErrorReporter), error_reporter: Box::new(StdoutErrorReporter),
local_context_creation_data: Mutex::new(local_context_data),
}; };
if node.is_dirty() || node.has_dirty_descendants() { if node.is_dirty() || node.has_dirty_descendants() {
parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context, &mut data.work_queue); parallel::traverse_dom::<GeckoNode, RecalcStyleOnly>(node, &shared_style_context, &mut per_doc_data.work_queue);
} }
} }

View file

@ -24,6 +24,7 @@ extern crate style_traits;
extern crate url; extern crate url;
extern crate util; extern crate util;
mod context;
mod data; mod data;
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub mod glue; pub mod glue;

View file

@ -12,6 +12,7 @@ pub type Stylist = style::selector_matching::Stylist<GeckoSelectorImpl>;
pub type Stylesheet = style::stylesheets::Stylesheet<GeckoSelectorImpl>; pub type Stylesheet = style::stylesheets::Stylesheet<GeckoSelectorImpl>;
pub type SharedStyleContext = style::context::SharedStyleContext<GeckoSelectorImpl>; pub type SharedStyleContext = style::context::SharedStyleContext<GeckoSelectorImpl>;
pub type PrivateStyleData = style::data::PrivateStyleData<GeckoSelectorImpl, GeckoComputedValues>; pub type PrivateStyleData = style::data::PrivateStyleData<GeckoSelectorImpl, GeckoComputedValues>;
pub type Animation = style::animation::Animation<GeckoSelectorImpl>;
#[cfg(feature = "servo_features")] #[cfg(feature = "servo_features")]
known_heap_size!(0, GeckoSelectorImpl, PseudoElement, NonTSPseudoClass); known_heap_size!(0, GeckoSelectorImpl, PseudoElement, NonTSPseudoClass);

View file

@ -2,66 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use properties::GeckoComputedValues; use context::StandaloneStyleContext;
use selector_impl::{GeckoSelectorImpl, SharedStyleContext}; use selector_impl::SharedStyleContext;
use std::cell::RefCell;
use std::mem; use std::mem;
use std::rc::Rc;
use style::context::{LocalStyleContext, StyleContext};
use style::dom::OpaqueNode; use style::dom::OpaqueNode;
use style::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
use style::traversal::{DomTraversalContext, recalc_style_at}; use style::traversal::{DomTraversalContext, recalc_style_at};
use wrapper::GeckoNode; use wrapper::GeckoNode;
thread_local!(static LOCAL_CONTEXT_KEY:
RefCell<Option<Rc<LocalStyleContext<GeckoComputedValues>>>> = RefCell::new(None));
// Keep this implementation in sync with the one in components/layout/context.rs.
fn create_or_get_local_context(shared: &SharedStyleContext)
-> Rc<LocalStyleContext<GeckoComputedValues>> {
LOCAL_CONTEXT_KEY.with(|r| {
let mut r = r.borrow_mut();
if let Some(context) = r.clone() {
if shared.screen_size_changed {
context.applicable_declarations_cache.borrow_mut().evict_all();
}
context
} else {
let context = Rc::new(LocalStyleContext {
applicable_declarations_cache: RefCell::new(ApplicableDeclarationsCache::new()),
style_sharing_candidate_cache: RefCell::new(StyleSharingCandidateCache::new()),
});
*r = Some(context.clone());
context
}
})
}
pub struct StandaloneStyleContext<'a> {
pub shared: &'a SharedStyleContext,
cached_local_context: Rc<LocalStyleContext<GeckoComputedValues>>,
}
impl<'a> StandaloneStyleContext<'a> {
pub fn new(shared: &'a SharedStyleContext) -> Self {
let local_context = create_or_get_local_context(shared);
StandaloneStyleContext {
shared: shared,
cached_local_context: local_context,
}
}
}
impl<'a> StyleContext<'a, GeckoSelectorImpl> for StandaloneStyleContext<'a> {
fn shared_context(&self) -> &'a SharedStyleContext {
&self.shared
}
fn local_context(&self) -> &LocalStyleContext<GeckoComputedValues> {
&self.cached_local_context
}
}
pub struct RecalcStyleOnly<'lc> { pub struct RecalcStyleOnly<'lc> {
context: StandaloneStyleContext<'lc>, context: StandaloneStyleContext<'lc>,
root: OpaqueNode, root: OpaqueNode,
@ -73,7 +20,7 @@ impl<'lc, 'ln> DomTraversalContext<GeckoNode<'ln>> for RecalcStyleOnly<'lc> {
fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self { fn new<'a>(shared: &'a Self::SharedContext, root: OpaqueNode) -> Self {
// See the comment in RecalcStyleAndConstructFlows::new for an explanation of why this is // See the comment in RecalcStyleAndConstructFlows::new for an explanation of why this is
// necessary. // necessary.
let shared_lc: &'lc SharedStyleContext = unsafe { mem::transmute(shared) }; let shared_lc: &'lc Self::SharedContext = unsafe { mem::transmute(shared) };
RecalcStyleOnly { RecalcStyleOnly {
context: StandaloneStyleContext::new(shared_lc), context: StandaloneStyleContext::new(shared_lc),
root: root, root: root,
@ -90,4 +37,3 @@ impl<'lc, 'ln> DomTraversalContext<GeckoNode<'ln>> for RecalcStyleOnly<'lc> {
fn process_postorder(&self, _: GeckoNode<'ln>) {} fn process_postorder(&self, _: GeckoNode<'ln>) {}
} }