Auto merge of #16014 - servo:style-ref, r=emilio

Per-process lock for CSSOM objects

<!-- Please describe your changes on the following line: -->

Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching:

* https://bugzilla.mozilla.org/show_bug.cgi?id=1311469
* https://bugzilla.mozilla.org/show_bug.cgi?id=1335941
* https://bugzilla.mozilla.org/show_bug.cgi?id=1339703

This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once.

In Stylo, there is one such lock per process (in a `lazy_static`), used for everything.

I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock.

This was previously #15998, closed accidentally.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16014)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-03-19 14:31:19 -07:00 committed by GitHub
commit bb54f0a429
73 changed files with 1468 additions and 911 deletions

5
Cargo.lock generated
View file

@ -928,9 +928,7 @@ dependencies = [
"lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.18.0", "selectors 0.18.0",
"servo_url 0.0.1", "servo_url 0.0.1",
"style 0.0.1", "style 0.0.1",
@ -2756,8 +2754,8 @@ dependencies = [
"nsstring_vendor 0.1.0", "nsstring_vendor 0.1.0",
"num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2783,7 +2781,6 @@ dependencies = [
"cssparser 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -446,7 +446,7 @@ fn translate_including_floats(cur_b: &mut Au, delta: Au, floats: &mut Floats) {
/// ///
/// Note that flows with position 'fixed' just form a flat list as they all /// Note that flows with position 'fixed' just form a flat list as they all
/// have the Root flow as their CB. /// have the Root flow as their CB.
pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a SharedStyleContext); pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a SharedStyleContext<'a>);
impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> { impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> {
#[inline] #[inline]

View file

@ -311,7 +311,7 @@ impl InlineFragmentsAccumulator {
/// An object that knows how to create flows. /// An object that knows how to create flows.
pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> { pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
/// The layout context. /// The layout context.
pub layout_context: &'a LayoutContext, pub layout_context: &'a LayoutContext<'a>,
/// Satisfy the compiler about the unused parameters, which we use to improve the ergonomics of /// Satisfy the compiler about the unused parameters, which we use to improve the ergonomics of
/// the ensuing impl {} by removing the need to parameterize all the methods individually. /// the ensuing impl {} by removing the need to parameterize all the methods individually.
phantom2: PhantomData<N>, phantom2: PhantomData<N>,
@ -320,7 +320,7 @@ pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
FlowConstructor<'a, ConcreteThreadSafeLayoutNode> { FlowConstructor<'a, ConcreteThreadSafeLayoutNode> {
/// Creates a new flow constructor. /// Creates a new flow constructor.
pub fn new(layout_context: &'a LayoutContext) -> Self { pub fn new(layout_context: &'a LayoutContext<'a>) -> Self {
FlowConstructor { FlowConstructor {
layout_context: layout_context, layout_context: layout_context,
phantom2: PhantomData, phantom2: PhantomData,
@ -660,10 +660,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let mut style = node.style(self.style_context()); let mut style = node.style(self.style_context());
if node_is_input_or_text_area { if node_is_input_or_text_area {
style = self.style_context() let context = self.style_context();
.stylist style = context.stylist.style_for_anonymous_box(
.style_for_anonymous_box(&PseudoElement::ServoInputText, &context.guards, &PseudoElement::ServoInputText, &style)
&style)
} }
self.create_fragments_for_node_text_content(&mut initial_fragments, node, &style) self.create_fragments_for_node_text_content(&mut initial_fragments, node, &style)
@ -1096,11 +1095,14 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
-> ConstructionResult { -> ConstructionResult {
let mut legalizer = Legalizer::new(); let mut legalizer = Legalizer::new();
let table_style = node.style(self.style_context()); let table_style;
let wrapper_style = self.style_context() let wrapper_style;
.stylist {
.style_for_anonymous_box(&PseudoElement::ServoTableWrapper, let context = self.style_context();
&table_style); table_style = node.style(context);
wrapper_style = context.stylist.style_for_anonymous_box(
&context.guards, &PseudoElement::ServoTableWrapper, &table_style);
}
let wrapper_fragment = let wrapper_fragment =
Fragment::from_opaque_node_and_style(node.opaque(), Fragment::from_opaque_node_and_style(node.opaque(),
PseudoElementType::Normal, PseudoElementType::Normal,
@ -2080,8 +2082,7 @@ impl Legalizer {
let reference_block = reference.as_block(); let reference_block = reference.as_block();
let mut new_style = reference_block.fragment.style.clone(); let mut new_style = reference_block.fragment.style.clone();
for pseudo in pseudos { for pseudo in pseudos {
new_style = context.stylist.style_for_anonymous_box(pseudo, new_style = context.stylist.style_for_anonymous_box(&context.guards, pseudo, &new_style)
&new_style)
} }
let fragment = reference_block.fragment let fragment = reference_block.fragment
.create_similar_anonymous_fragment(new_style, .create_similar_anonymous_fragment(new_style,

View file

@ -75,9 +75,9 @@ pub fn heap_size_of_persistent_local_context() -> usize {
} }
/// Layout information shared among all workers. This must be thread-safe. /// Layout information shared among all workers. This must be thread-safe.
pub struct LayoutContext { pub struct LayoutContext<'a> {
/// Bits shared by the layout and style system. /// Bits shared by the layout and style system.
pub style_context: SharedStyleContext, pub style_context: SharedStyleContext<'a>,
/// The shared image cache thread. /// The shared image cache thread.
pub image_cache_thread: Mutex<ImageCacheThread>, pub image_cache_thread: Mutex<ImageCacheThread>,
@ -95,7 +95,7 @@ pub struct LayoutContext {
pub pending_images: Option<Mutex<Vec<PendingImage>>> pub pending_images: Option<Mutex<Vec<PendingImage>>>
} }
impl Drop for LayoutContext { impl<'a> Drop for LayoutContext<'a> {
fn drop(&mut self) { fn drop(&mut self) {
if !thread::panicking() { if !thread::panicking() {
if let Some(ref pending_images) = self.pending_images { if let Some(ref pending_images) = self.pending_images {
@ -105,7 +105,7 @@ impl Drop for LayoutContext {
} }
} }
impl LayoutContext { impl<'a> LayoutContext<'a> {
#[inline(always)] #[inline(always)]
pub fn shared_context(&self) -> &SharedStyleContext { pub fn shared_context(&self) -> &SharedStyleContext {
&self.style_context &self.style_context

View file

@ -121,7 +121,7 @@ fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
} }
pub struct DisplayListBuildState<'a> { pub struct DisplayListBuildState<'a> {
pub layout_context: &'a LayoutContext, pub layout_context: &'a LayoutContext<'a>,
pub root_stacking_context: StackingContext, pub root_stacking_context: StackingContext,
pub items: HashMap<StackingContextId, Vec<DisplayItem>>, pub items: HashMap<StackingContextId, Vec<DisplayItem>>,
pub stacking_context_children: HashMap<StackingContextId, Vec<StackingContext>>, pub stacking_context_children: HashMap<StackingContextId, Vec<StackingContext>>,

View file

@ -97,7 +97,7 @@ static KATAKANA_IROHA: [char; 47] = [
/// The generated content resolution traversal. /// The generated content resolution traversal.
pub struct ResolveGeneratedContent<'a> { pub struct ResolveGeneratedContent<'a> {
/// The layout context. /// The layout context.
layout_context: &'a LayoutContext, layout_context: &'a LayoutContext<'a>,
/// The counter representing an ordered list item. /// The counter representing an ordered list item.
list_item: Counter, list_item: Counter,
/// Named CSS counters. /// Named CSS counters.

View file

@ -22,20 +22,20 @@ use style::traversal::PerLevelTraversalData;
use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData}; use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData};
use wrapper::ThreadSafeLayoutNodeHelpers; use wrapper::ThreadSafeLayoutNodeHelpers;
pub struct RecalcStyleAndConstructFlows { pub struct RecalcStyleAndConstructFlows<'a> {
context: LayoutContext, context: LayoutContext<'a>,
driver: TraversalDriver, driver: TraversalDriver,
} }
impl RecalcStyleAndConstructFlows { impl<'a> RecalcStyleAndConstructFlows<'a> {
pub fn layout_context(&self) -> &LayoutContext { pub fn layout_context(&self) -> &LayoutContext<'a> {
&self.context &self.context
} }
} }
impl RecalcStyleAndConstructFlows { impl<'a> RecalcStyleAndConstructFlows<'a> {
/// Creates a traversal context, taking ownership of the shared layout context. /// Creates a traversal context, taking ownership of the shared layout context.
pub fn new(context: LayoutContext, driver: TraversalDriver) -> Self { pub fn new(context: LayoutContext<'a>, driver: TraversalDriver) -> Self {
RecalcStyleAndConstructFlows { RecalcStyleAndConstructFlows {
context: context, context: context,
driver: driver, driver: driver,
@ -44,13 +44,13 @@ impl RecalcStyleAndConstructFlows {
/// Consumes this traversal context, returning ownership of the shared layout /// Consumes this traversal context, returning ownership of the shared layout
/// context to the caller. /// context to the caller.
pub fn destroy(self) -> LayoutContext { pub fn destroy(self) -> LayoutContext<'a> {
self.context self.context
} }
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
impl<E> DomTraversal<E> for RecalcStyleAndConstructFlows impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
where E: TElement, where E: TElement,
E::ConcreteNode: LayoutNode, E::ConcreteNode: LayoutNode,
{ {
@ -152,7 +152,7 @@ fn construct_flows_at<N>(context: &LayoutContext,
/// The bubble-inline-sizes traversal, the first part of layout computation. This computes /// The bubble-inline-sizes traversal, the first part of layout computation. This computes
/// preferred and intrinsic inline-sizes and bubbles them up the tree. /// preferred and intrinsic inline-sizes and bubbles them up the tree.
pub struct BubbleISizes<'a> { pub struct BubbleISizes<'a> {
pub layout_context: &'a LayoutContext, pub layout_context: &'a LayoutContext<'a>,
} }
impl<'a> PostorderFlowTraversal for BubbleISizes<'a> { impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
@ -171,7 +171,7 @@ impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
/// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`. /// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct AssignISizes<'a> { pub struct AssignISizes<'a> {
pub layout_context: &'a LayoutContext, pub layout_context: &'a LayoutContext<'a>,
} }
impl<'a> PreorderFlowTraversal for AssignISizes<'a> { impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
@ -191,7 +191,7 @@ impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
/// positions. In Gecko this corresponds to `Reflow`. /// positions. In Gecko this corresponds to `Reflow`.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct AssignBSizes<'a> { pub struct AssignBSizes<'a> {
pub layout_context: &'a LayoutContext, pub layout_context: &'a LayoutContext<'a>,
} }
impl<'a> PostorderFlowTraversal for AssignBSizes<'a> { impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
@ -220,7 +220,7 @@ impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct ComputeAbsolutePositions<'a> { pub struct ComputeAbsolutePositions<'a> {
pub layout_context: &'a LayoutContext, pub layout_context: &'a LayoutContext<'a>,
} }
impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> { impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {

View file

@ -114,7 +114,9 @@ use style::error_reporting::StdoutErrorReporter;
use style::logical_geometry::LogicalPoint; use style::logical_geometry::LogicalPoint;
use style::media_queries::{Device, MediaType}; use style::media_queries::{Device, MediaType};
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::servo::AUTHOR_SHARED_LOCK;
use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW}; use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards};
use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets}; use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
use style::stylist::Stylist; use style::stylist::Stylist;
use style::thread_state; use style::thread_state;
@ -214,7 +216,7 @@ pub struct LayoutThread {
WebRenderImageInfo, WebRenderImageInfo,
BuildHasherDefault<FnvHasher>>>>, BuildHasherDefault<FnvHasher>>>>,
// Webrender interface. /// Webrender interface.
webrender_api: webrender_traits::RenderApi, webrender_api: webrender_traits::RenderApi,
/// The timer object to control the timing of the animations. This should /// The timer object to control the timing of the animations. This should
@ -344,13 +346,14 @@ impl<'a, 'b: 'a> RwData<'a, 'b> {
} }
fn add_font_face_rules(stylesheet: &Stylesheet, fn add_font_face_rules(stylesheet: &Stylesheet,
guard: &SharedRwLockReadGuard,
device: &Device, device: &Device,
font_cache_thread: &FontCacheThread, font_cache_thread: &FontCacheThread,
font_cache_sender: &IpcSender<()>, font_cache_sender: &IpcSender<()>,
outstanding_web_fonts_counter: &Arc<AtomicUsize>) { outstanding_web_fonts_counter: &Arc<AtomicUsize>) {
if opts::get().load_webfonts_synchronously { if opts::get().load_webfonts_synchronously {
let (sender, receiver) = ipc::channel().unwrap(); let (sender, receiver) = ipc::channel().unwrap();
stylesheet.effective_font_face_rules(&device, |font_face| { stylesheet.effective_font_face_rules(&device, guard, |font_face| {
let effective_sources = font_face.effective_sources(); let effective_sources = font_face.effective_sources();
font_cache_thread.add_web_font(font_face.family.clone(), font_cache_thread.add_web_font(font_face.family.clone(),
effective_sources, effective_sources,
@ -358,7 +361,7 @@ fn add_font_face_rules(stylesheet: &Stylesheet,
receiver.recv().unwrap(); receiver.recv().unwrap();
}) })
} else { } else {
stylesheet.effective_font_face_rules(&device, |font_face| { stylesheet.effective_font_face_rules(&device, guard, |font_face| {
let effective_sources = font_face.effective_sources(); let effective_sources = font_face.effective_sources();
outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst); outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst);
font_cache_thread.add_web_font(font_face.family.clone(), font_cache_thread.add_web_font(font_face.family.clone(),
@ -406,8 +409,11 @@ impl LayoutThread {
let stylist = Arc::new(Stylist::new(device)); let stylist = Arc::new(Stylist::new(device));
let outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0)); let outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0));
for stylesheet in &*UA_STYLESHEETS.user_or_user_agent_stylesheets { let ua_stylesheets = &*UA_STYLESHEETS;
let guard = ua_stylesheets.shared_lock.read();
for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
add_font_face_rules(stylesheet, add_font_face_rules(stylesheet,
&guard,
&stylist.device, &stylist.device,
&font_cache_thread, &font_cache_thread,
&ipc_font_cache_sender, &ipc_font_cache_sender,
@ -493,16 +499,18 @@ impl LayoutThread {
} }
// Create a layout context for use in building display lists, hit testing, &c. // Create a layout context for use in building display lists, hit testing, &c.
fn build_layout_context(&self, fn build_layout_context<'a>(&self,
rw_data: &LayoutThreadData, guards: StylesheetGuards<'a>,
request_images: bool) rw_data: &LayoutThreadData,
-> LayoutContext { request_images: bool)
-> LayoutContext<'a> {
let thread_local_style_context_creation_data = let thread_local_style_context_creation_data =
ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone()); ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
LayoutContext { LayoutContext {
style_context: SharedStyleContext { style_context: SharedStyleContext {
stylist: rw_data.stylist.clone(), stylist: rw_data.stylist.clone(),
guards: guards,
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: Box::new(self.error_reporter.clone()), error_reporter: Box::new(self.error_reporter.clone()),
@ -730,8 +738,10 @@ impl LayoutThread {
// GWTODO: Need to handle unloading web fonts. // GWTODO: Need to handle unloading web fonts.
let rw_data = possibly_locked_rw_data.lock(); let rw_data = possibly_locked_rw_data.lock();
if stylesheet.is_effective_for_device(&rw_data.stylist.device) { let guard = stylesheet.shared_lock.read();
if stylesheet.is_effective_for_device(&rw_data.stylist.device, &guard) {
add_font_face_rules(&*stylesheet, add_font_face_rules(&*stylesheet,
&guard,
&rw_data.stylist.device, &rw_data.stylist.device,
&self.font_cache_thread, &self.font_cache_thread,
&self.font_cache_sender, &self.font_cache_sender,
@ -1009,8 +1019,11 @@ impl LayoutThread {
Au::from_f32_px(initial_viewport.height)); Au::from_f32_px(initial_viewport.height));
// Calculate the actual viewport as per DEVICE-ADAPT § 6 // Calculate the actual viewport as per DEVICE-ADAPT § 6
let author_guard = document.style_shared_lock().read();
let device = Device::new(MediaType::Screen, initial_viewport); let device = Device::new(MediaType::Screen, initial_viewport);
Arc::get_mut(&mut rw_data.stylist).unwrap().set_device(device, &data.document_stylesheets); Arc::get_mut(&mut rw_data.stylist).unwrap()
.set_device(device, &author_guard, &data.document_stylesheets);
self.viewport_size = self.viewport_size =
rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| { rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| {
@ -1054,9 +1067,17 @@ impl LayoutThread {
} }
// If the entire flow tree is invalid, then it will be reflowed anyhow. // If the entire flow tree is invalid, then it will be reflowed anyhow.
let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update(&data.document_stylesheets, let ua_stylesheets = &*UA_STYLESHEETS;
Some(&*UA_STYLESHEETS), let ua_or_user_guard = ua_stylesheets.shared_lock.read();
data.stylesheets_changed); let guards = StylesheetGuards {
author: &author_guard,
ua_or_user: &ua_or_user_guard,
};
let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update(
&data.document_stylesheets,
&guards,
Some(ua_stylesheets),
data.stylesheets_changed);
let needs_reflow = viewport_size_changed && !needs_dirtying; let needs_reflow = viewport_size_changed && !needs_dirtying;
if needs_dirtying { if needs_dirtying {
if let Some(mut d) = element.mutate_data() { if let Some(mut d) = element.mutate_data() {
@ -1102,7 +1123,7 @@ impl LayoutThread {
} }
// Create a layout context for use throughout the following passes. // Create a layout context for use throughout the following passes.
let mut layout_context = self.build_layout_context(&*rw_data, true); let mut layout_context = self.build_layout_context(guards.clone(), &*rw_data, true);
// NB: Type inference falls apart here for some reason, so we need to be very verbose. :-( // NB: Type inference falls apart here for some reason, so we need to be very verbose. :-(
let traversal_driver = if self.parallel_flag && self.parallel_traversal.is_some() { let traversal_driver = if self.parallel_flag && self.parallel_traversal.is_some() {
@ -1161,7 +1182,7 @@ impl LayoutThread {
} }
if opts::get().dump_rule_tree { if opts::get().dump_rule_tree {
layout_context.style_context.stylist.rule_tree.dump_stdout(); layout_context.style_context.stylist.rule_tree.dump_stdout(&guards);
} }
// GC the rule tree if some heuristics are met. // GC the rule tree if some heuristics are met.
@ -1330,7 +1351,13 @@ impl LayoutThread {
page_clip_rect: max_rect(), page_clip_rect: max_rect(),
}; };
let mut layout_context = self.build_layout_context(&*rw_data, false); let author_guard = AUTHOR_SHARED_LOCK.read();
let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read();
let guards = StylesheetGuards {
author: &author_guard,
ua_or_user: &ua_or_user_guard,
};
let mut layout_context = self.build_layout_context(guards, &*rw_data, false);
if let Some(mut root_flow) = self.root_flow.clone() { if let Some(mut root_flow) = self.root_flow.clone() {
// Perform an abbreviated style recalc that operates without access to the DOM. // Perform an abbreviated style recalc that operates without access to the DOM.
@ -1528,7 +1555,8 @@ fn get_root_flow_background_color(flow: &mut Flow) -> webrender_traits::ColorF {
} }
fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> { fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
fn parse_ua_stylesheet(filename: &'static str) -> Result<Stylesheet, &'static str> { fn parse_ua_stylesheet(shared_lock: &SharedRwLock, filename: &'static str)
-> Result<Stylesheet, &'static str> {
let res = try!(read_resource_file(filename).map_err(|_| filename)); let res = try!(read_resource_file(filename).map_err(|_| filename));
Ok(Stylesheet::from_bytes( Ok(Stylesheet::from_bytes(
&res, &res,
@ -1537,26 +1565,29 @@ fn get_ua_stylesheets() -> Result<UserAgentStylesheets, &'static str> {
None, None,
Origin::UserAgent, Origin::UserAgent,
Default::default(), Default::default(),
shared_lock.clone(),
None, None,
&StdoutErrorReporter, &StdoutErrorReporter,
ParserContextExtraData::default())) ParserContextExtraData::default()))
} }
let shared_lock = SharedRwLock::new();
let mut user_or_user_agent_stylesheets = vec!(); let mut user_or_user_agent_stylesheets = vec!();
// FIXME: presentational-hints.css should be at author origin with zero specificity. // FIXME: presentational-hints.css should be at author origin with zero specificity.
// (Does it make a difference?) // (Does it make a difference?)
for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] { for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] {
user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(filename))); user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(&shared_lock, filename)));
} }
for &(ref contents, ref url) in &opts::get().user_stylesheets { for &(ref contents, ref url) in &opts::get().user_stylesheets {
user_or_user_agent_stylesheets.push(Stylesheet::from_bytes( user_or_user_agent_stylesheets.push(Stylesheet::from_bytes(
&contents, url.clone(), None, None, Origin::User, Default::default(), &contents, url.clone(), None, None, Origin::User, Default::default(),
None, &StdoutErrorReporter, ParserContextExtraData::default())); shared_lock.clone(), None, &StdoutErrorReporter, ParserContextExtraData::default()));
} }
let quirks_mode_stylesheet = try!(parse_ua_stylesheet("quirks-mode.css")); let quirks_mode_stylesheet = try!(parse_ua_stylesheet(&shared_lock, "quirks-mode.css"));
Ok(UserAgentStylesheets { Ok(UserAgentStylesheets {
shared_lock: shared_lock,
user_or_user_agent_stylesheets: user_or_user_agent_stylesheets, user_or_user_agent_stylesheets: user_or_user_agent_stylesheets,
quirks_mode_stylesheet: quirks_mode_stylesheet, quirks_mode_stylesheet: quirks_mode_stylesheet,
}) })

View file

@ -99,6 +99,7 @@ use style::keyframes::Keyframe;
use style::media_queries::MediaList; use style::media_queries::MediaList;
use style::properties::PropertyDeclarationBlock; use style::properties::PropertyDeclarationBlock;
use style::selector_parser::{PseudoElement, Snapshot}; use style::selector_parser::{PseudoElement, Snapshot};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule}; use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule};
use style::stylesheets::SupportsRule; use style::stylesheets::SupportsRule;
use style::values::specified::Length; use style::values::specified::Length;
@ -360,6 +361,7 @@ unsafe_no_jsmanaged_fields!(HttpsState);
unsafe_no_jsmanaged_fields!(Request); unsafe_no_jsmanaged_fields!(Request);
unsafe_no_jsmanaged_fields!(RequestInit); unsafe_no_jsmanaged_fields!(RequestInit);
unsafe_no_jsmanaged_fields!(SharedRt); unsafe_no_jsmanaged_fields!(SharedRt);
unsafe_no_jsmanaged_fields!(StyleSharedRwLock);
unsafe_no_jsmanaged_fields!(TouchpadPressurePhase); unsafe_no_jsmanaged_fields!(TouchpadPressurePhase);
unsafe_no_jsmanaged_fields!(USVString); unsafe_no_jsmanaged_fields!(USVString);
unsafe_no_jsmanaged_fields!(ReferrerPolicy); unsafe_no_jsmanaged_fields!(ReferrerPolicy);
@ -500,67 +502,67 @@ unsafe impl JSTraceable for Mutex<Option<SharedRt>> {
} }
} }
unsafe impl JSTraceable for RwLock<FontFaceRule> { unsafe impl JSTraceable for StyleLocked<FontFaceRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<CssRules> { unsafe impl JSTraceable for StyleLocked<CssRules> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<Keyframe> { unsafe impl JSTraceable for StyleLocked<Keyframe> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<KeyframesRule> { unsafe impl JSTraceable for StyleLocked<KeyframesRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<ImportRule> { unsafe impl JSTraceable for StyleLocked<ImportRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<SupportsRule> { unsafe impl JSTraceable for StyleLocked<SupportsRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<MediaRule> { unsafe impl JSTraceable for StyleLocked<MediaRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<NamespaceRule> { unsafe impl JSTraceable for StyleLocked<NamespaceRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<StyleRule> { unsafe impl JSTraceable for StyleLocked<StyleRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<ViewportRule> { unsafe impl JSTraceable for StyleLocked<ViewportRule> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
} }
unsafe impl JSTraceable for RwLock<PropertyDeclarationBlock> { unsafe impl JSTraceable for StyleLocked<PropertyDeclarationBlock> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }
@ -572,7 +574,7 @@ unsafe impl JSTraceable for RwLock<SharedRt> {
} }
} }
unsafe impl JSTraceable for RwLock<MediaList> { unsafe impl JSTraceable for StyleLocked<MediaList> {
unsafe fn trace(&self, _trc: *mut JSTracer) { unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing. // Do nothing.
} }

View file

@ -10,8 +10,8 @@ use dom::cssmediarule::CSSMediaRule;
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::csssupportsrule::CSSSupportsRule; use dom::csssupportsrule::CSSSupportsRule;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::{SharedRwLock, Locked};
use style::stylesheets::CssRules as StyleCssRules; use style::stylesheets::CssRules as StyleCssRules;
#[dom_struct] #[dom_struct]
@ -21,12 +21,19 @@ pub struct CSSConditionRule {
impl CSSConditionRule { impl CSSConditionRule {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
rules: Arc<RwLock<StyleCssRules>>) -> CSSConditionRule { rules: Arc<Locked<StyleCssRules>>) -> CSSConditionRule {
CSSConditionRule { CSSConditionRule {
cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules), cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules),
} }
} }
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
self.cssgroupingrule.parent_stylesheet()
}
pub fn shared_lock(&self) -> &SharedRwLock {
self.cssgroupingrule.shared_lock()
}
} }
impl CSSConditionRuleMethods for CSSConditionRule { impl CSSConditionRuleMethods for CSSConditionRule {

View file

@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::font_face::FontFaceRule; use style::font_face::FontFaceRule;
use style_traits::ToCss; use style::shared_lock::{Locked, ToCssWithGuard};
#[dom_struct] #[dom_struct]
pub struct CSSFontFaceRule { pub struct CSSFontFaceRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
fontfacerule: Arc<RwLock<FontFaceRule>>, fontfacerule: Arc<Locked<FontFaceRule>>,
} }
impl CSSFontFaceRule { impl CSSFontFaceRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<RwLock<FontFaceRule>>) fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc<Locked<FontFaceRule>>)
-> CSSFontFaceRule { -> CSSFontFaceRule {
CSSFontFaceRule { CSSFontFaceRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -33,7 +32,7 @@ impl CSSFontFaceRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
fontfacerule: Arc<RwLock<FontFaceRule>>) -> Root<CSSFontFaceRule> { fontfacerule: Arc<Locked<FontFaceRule>>) -> Root<CSSFontFaceRule> {
reflect_dom_object(box CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule), reflect_dom_object(box CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule),
window, window,
CSSFontFaceRuleBinding::Wrap) CSSFontFaceRuleBinding::Wrap)
@ -47,6 +46,7 @@ impl SpecificCSSRule for CSSFontFaceRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.fontfacerule.read().to_css_string().into() let guard = self.cssrule.shared_lock().read();
self.fontfacerule.read_with(&guard).to_css_string(&guard).into()
} }
} }

View file

@ -12,21 +12,21 @@ use dom::cssrule::CSSRule;
use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::cssrulelist::{CSSRuleList, RulesSource};
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::{SharedRwLock, Locked};
use style::stylesheets::CssRules as StyleCssRules; use style::stylesheets::CssRules as StyleCssRules;
#[dom_struct] #[dom_struct]
pub struct CSSGroupingRule { pub struct CSSGroupingRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
rules: Arc<RwLock<StyleCssRules>>, rules: Arc<Locked<StyleCssRules>>,
rulelist: MutNullableJS<CSSRuleList>, rulelist: MutNullableJS<CSSRuleList>,
} }
impl CSSGroupingRule { impl CSSGroupingRule {
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
rules: Arc<RwLock<StyleCssRules>>) -> CSSGroupingRule { rules: Arc<Locked<StyleCssRules>>) -> CSSGroupingRule {
CSSGroupingRule { CSSGroupingRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
rules: rules, rules: rules,
@ -40,6 +40,14 @@ impl CSSGroupingRule {
parent_stylesheet, parent_stylesheet,
RulesSource::Rules(self.rules.clone()))) RulesSource::Rules(self.rules.clone())))
} }
pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
self.cssrule.parent_stylesheet()
}
pub fn shared_lock(&self) -> &SharedRwLock {
self.cssrule.shared_lock()
}
} }
impl CSSGroupingRuleMethods for CSSGroupingRule { impl CSSGroupingRuleMethods for CSSGroupingRule {

View file

@ -10,21 +10,20 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::ImportRule; use style::stylesheets::ImportRule;
use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct CSSImportRule { pub struct CSSImportRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
import_rule: Arc<RwLock<ImportRule>>, import_rule: Arc<Locked<ImportRule>>,
} }
impl CSSImportRule { impl CSSImportRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, fn new_inherited(parent_stylesheet: &CSSStyleSheet,
import_rule: Arc<RwLock<ImportRule>>) import_rule: Arc<Locked<ImportRule>>)
-> Self { -> Self {
CSSImportRule { CSSImportRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -35,7 +34,7 @@ impl CSSImportRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, pub fn new(window: &Window,
parent_stylesheet: &CSSStyleSheet, parent_stylesheet: &CSSStyleSheet,
import_rule: Arc<RwLock<ImportRule>>) -> Root<Self> { import_rule: Arc<Locked<ImportRule>>) -> Root<Self> {
reflect_dom_object(box Self::new_inherited(parent_stylesheet, import_rule), reflect_dom_object(box Self::new_inherited(parent_stylesheet, import_rule),
window, window,
CSSImportRuleBinding::Wrap) CSSImportRuleBinding::Wrap)
@ -49,6 +48,7 @@ impl SpecificCSSRule for CSSImportRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.import_rule.read().to_css_string().into() let guard = self.cssrule.shared_lock().read();
self.import_rule.read_with(&guard).to_css_string(&guard).into()
} }
} }

View file

@ -12,21 +12,20 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::keyframes::Keyframe; use style::keyframes::Keyframe;
use style_traits::ToCss; use style::shared_lock::{Locked, ToCssWithGuard};
#[dom_struct] #[dom_struct]
pub struct CSSKeyframeRule { pub struct CSSKeyframeRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
keyframerule: Arc<RwLock<Keyframe>>, keyframerule: Arc<Locked<Keyframe>>,
style_decl: MutNullableJS<CSSStyleDeclaration>, style_decl: MutNullableJS<CSSStyleDeclaration>,
} }
impl CSSKeyframeRule { impl CSSKeyframeRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<RwLock<Keyframe>>) fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc<Locked<Keyframe>>)
-> CSSKeyframeRule { -> CSSKeyframeRule {
CSSKeyframeRule { CSSKeyframeRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -37,7 +36,7 @@ impl CSSKeyframeRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
keyframerule: Arc<RwLock<Keyframe>>) -> Root<CSSKeyframeRule> { keyframerule: Arc<Locked<Keyframe>>) -> Root<CSSKeyframeRule> {
reflect_dom_object(box CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule), reflect_dom_object(box CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule),
window, window,
CSSKeyframeRuleBinding::Wrap) CSSKeyframeRuleBinding::Wrap)
@ -48,11 +47,16 @@ impl CSSKeyframeRuleMethods for CSSKeyframeRule {
// https://drafts.csswg.org/css-animations/#dom-csskeyframerule-style // https://drafts.csswg.org/css-animations/#dom-csskeyframerule-style
fn Style(&self) -> Root<CSSStyleDeclaration> { fn Style(&self) -> Root<CSSStyleDeclaration> {
self.style_decl.or_init(|| { self.style_decl.or_init(|| {
CSSStyleDeclaration::new(self.global().as_window(), let guard = self.cssrule.shared_lock().read();
CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()), CSSStyleDeclaration::new(
self.keyframerule.read().block.clone()), self.global().as_window(),
None, CSSStyleOwner::CSSRule(
CSSModificationAccess::ReadWrite) JS::from_ref(self.upcast()),
self.keyframerule.read_with(&guard).block.clone(),
),
None,
CSSModificationAccess::ReadWrite,
)
}) })
} }
} }
@ -64,6 +68,7 @@ impl SpecificCSSRule for CSSKeyframeRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.keyframerule.read().to_css_string().into() let guard = self.cssrule.shared_lock().read();
self.keyframerule.read_with(&guard).to_css_string(&guard).into()
} }
} }

View file

@ -16,24 +16,23 @@ use dom::cssrulelist::{CSSRuleList, RulesSource};
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use servo_atoms::Atom; use servo_atoms::Atom;
use std::sync::Arc; use std::sync::Arc;
use style::keyframes::{Keyframe, KeyframeSelector}; use style::keyframes::{Keyframe, KeyframeSelector};
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::KeyframesRule; use style::stylesheets::KeyframesRule;
use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct CSSKeyframesRule { pub struct CSSKeyframesRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
keyframesrule: Arc<RwLock<KeyframesRule>>, keyframesrule: Arc<Locked<KeyframesRule>>,
rulelist: MutNullableJS<CSSRuleList>, rulelist: MutNullableJS<CSSRuleList>,
} }
impl CSSKeyframesRule { impl CSSKeyframesRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<RwLock<KeyframesRule>>) fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc<Locked<KeyframesRule>>)
-> CSSKeyframesRule { -> CSSKeyframesRule {
CSSKeyframesRule { CSSKeyframesRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -44,7 +43,7 @@ impl CSSKeyframesRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
keyframesrule: Arc<RwLock<KeyframesRule>>) -> Root<CSSKeyframesRule> { keyframesrule: Arc<Locked<KeyframesRule>>) -> Root<CSSKeyframesRule> {
reflect_dom_object(box CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule), reflect_dom_object(box CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule),
window, window,
CSSKeyframesRuleBinding::Wrap) CSSKeyframesRuleBinding::Wrap)
@ -63,11 +62,12 @@ impl CSSKeyframesRule {
fn find_rule(&self, selector: &str) -> Option<usize> { fn find_rule(&self, selector: &str) -> Option<usize> {
let mut input = Parser::new(selector); let mut input = Parser::new(selector);
if let Ok(sel) = KeyframeSelector::parse(&mut input) { if let Ok(sel) = KeyframeSelector::parse(&mut input) {
let guard = self.cssrule.shared_lock().read();
// This finds the *last* element matching a selector // This finds the *last* element matching a selector
// because that's the rule that applies. Thus, rposition // because that's the rule that applies. Thus, rposition
self.keyframesrule.read() self.keyframesrule.read_with(&guard)
.keyframes.iter().rposition(|frame| { .keyframes.iter().rposition(|frame| {
frame.read().selector == sel frame.read_with(&guard).selector == sel
}) })
} else { } else {
None None
@ -86,7 +86,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
let rule = Keyframe::parse(&rule, self.cssrule.parent_stylesheet().style_stylesheet(), let rule = Keyframe::parse(&rule, self.cssrule.parent_stylesheet().style_stylesheet(),
ParserContextExtraData::default()); ParserContextExtraData::default());
if let Ok(rule) = rule { if let Ok(rule) = rule {
self.keyframesrule.write().keyframes.push(rule); let mut guard = self.cssrule.shared_lock().write();
self.keyframesrule.write_with(&mut guard).keyframes.push(rule);
self.rulelist().append_lazy_dom_rule(); self.rulelist().append_lazy_dom_rule();
} }
} }
@ -107,7 +108,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
fn Name(&self) -> DOMString { fn Name(&self) -> DOMString {
DOMString::from(&*self.keyframesrule.read().name) let guard = self.cssrule.shared_lock().read();
DOMString::from(&*self.keyframesrule.read_with(&guard).name)
} }
// https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name
@ -122,7 +124,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule {
"none" => return Err(Error::Syntax), "none" => return Err(Error::Syntax),
_ => () _ => ()
} }
self.keyframesrule.write().name = Atom::from(value); let mut guard = self.cssrule.shared_lock().write();
self.keyframesrule.write_with(&mut guard).name = Atom::from(value);
Ok(()) Ok(())
} }
} }
@ -134,7 +137,8 @@ impl SpecificCSSRule for CSSKeyframesRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.keyframesrule.read().to_css_string().into() let guard = self.cssrule.shared_lock().read();
self.keyframesrule.read_with(&guard).to_css_string(&guard).into()
} }
fn deparent_children(&self) { fn deparent_children(&self) {

View file

@ -14,26 +14,27 @@ use dom::cssstylesheet::CSSStyleSheet;
use dom::medialist::MediaList; use dom::medialist::MediaList;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::media_queries::parse_media_query_list; use style::media_queries::parse_media_query_list;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::MediaRule; use style::stylesheets::MediaRule;
use style_traits::ToCss; use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct CSSMediaRule { pub struct CSSMediaRule {
cssrule: CSSConditionRule, cssconditionrule: CSSConditionRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
mediarule: Arc<RwLock<MediaRule>>, mediarule: Arc<Locked<MediaRule>>,
medialist: MutNullableJS<MediaList>, medialist: MutNullableJS<MediaList>,
} }
impl CSSMediaRule { impl CSSMediaRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<RwLock<MediaRule>>) fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc<Locked<MediaRule>>)
-> CSSMediaRule { -> CSSMediaRule {
let list = mediarule.read().rules.clone(); let guard = parent_stylesheet.shared_lock().read();
let list = mediarule.read_with(&guard).rules.clone();
CSSMediaRule { CSSMediaRule {
cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
mediarule: mediarule, mediarule: mediarule,
medialist: MutNullableJS::new(None), medialist: MutNullableJS::new(None),
} }
@ -41,21 +42,26 @@ impl CSSMediaRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
mediarule: Arc<RwLock<MediaRule>>) -> Root<CSSMediaRule> { mediarule: Arc<Locked<MediaRule>>) -> Root<CSSMediaRule> {
reflect_dom_object(box CSSMediaRule::new_inherited(parent_stylesheet, mediarule), reflect_dom_object(box CSSMediaRule::new_inherited(parent_stylesheet, mediarule),
window, window,
CSSMediaRuleBinding::Wrap) CSSMediaRuleBinding::Wrap)
} }
fn medialist(&self) -> Root<MediaList> { fn medialist(&self) -> Root<MediaList> {
self.medialist.or_init(|| MediaList::new(self.global().as_window(), self.medialist.or_init(|| {
self.mediarule.read().media_queries.clone())) let guard = self.cssconditionrule.shared_lock().read();
MediaList::new(self.global().as_window(),
self.cssconditionrule.parent_stylesheet(),
self.mediarule.read_with(&guard).media_queries.clone())
})
} }
/// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface
pub fn get_condition_text(&self) -> DOMString { pub fn get_condition_text(&self) -> DOMString {
let rule = self.mediarule.read(); let guard = self.cssconditionrule.shared_lock().read();
let list = rule.media_queries.read(); let rule = self.mediarule.read_with(&guard);
let list = rule.media_queries.read_with(&guard);
list.to_css_string().into() list.to_css_string().into()
} }
@ -63,9 +69,16 @@ impl CSSMediaRule {
pub fn set_condition_text(&self, text: DOMString) { pub fn set_condition_text(&self, text: DOMString) {
let mut input = Parser::new(&text); let mut input = Parser::new(&text);
let new_medialist = parse_media_query_list(&mut input); let new_medialist = parse_media_query_list(&mut input);
let rule = self.mediarule.read(); let mut guard = self.cssconditionrule.shared_lock().write();
let mut list = rule.media_queries.write();
*list = new_medialist; // Clone an Arc because we cant borrow `guard` twice at the same time.
// FIXME(SimonSapin): allow access to multiple objects with one write guard?
// Would need a set of usize pointer addresses or something,
// the same object is not accessed more than once.
let mqs = Arc::clone(&self.mediarule.write_with(&mut guard).media_queries);
*mqs.write_with(&mut guard) = new_medialist;
} }
} }
@ -76,7 +89,8 @@ impl SpecificCSSRule for CSSMediaRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.mediarule.read().to_css_string().into() let guard = self.cssconditionrule.shared_lock().read();
self.mediarule.read_with(&guard).to_css_string(&guard).into()
} }
} }

View file

@ -11,20 +11,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::NamespaceRule; use style::stylesheets::NamespaceRule;
use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct CSSNamespaceRule { pub struct CSSNamespaceRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
namespacerule: Arc<RwLock<NamespaceRule>>, namespacerule: Arc<Locked<NamespaceRule>>,
} }
impl CSSNamespaceRule { impl CSSNamespaceRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<RwLock<NamespaceRule>>) fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc<Locked<NamespaceRule>>)
-> CSSNamespaceRule { -> CSSNamespaceRule {
CSSNamespaceRule { CSSNamespaceRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -34,7 +33,7 @@ impl CSSNamespaceRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
namespacerule: Arc<RwLock<NamespaceRule>>) -> Root<CSSNamespaceRule> { namespacerule: Arc<Locked<NamespaceRule>>) -> Root<CSSNamespaceRule> {
reflect_dom_object(box CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule), reflect_dom_object(box CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule),
window, window,
CSSNamespaceRuleBinding::Wrap) CSSNamespaceRuleBinding::Wrap)
@ -44,14 +43,16 @@ impl CSSNamespaceRule {
impl CSSNamespaceRuleMethods for CSSNamespaceRule { impl CSSNamespaceRuleMethods for CSSNamespaceRule {
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix
fn Prefix(&self) -> DOMString { fn Prefix(&self) -> DOMString {
self.namespacerule.read().prefix let guard = self.cssrule.shared_lock().read();
self.namespacerule.read_with(&guard).prefix
.as_ref().map(|s| s.to_string().into()) .as_ref().map(|s| s.to_string().into())
.unwrap_or(DOMString::new()) .unwrap_or(DOMString::new())
} }
// https://drafts.csswg.org/cssom/#dom-cssnamespacerule-namespaceuri // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-namespaceuri
fn NamespaceURI(&self) -> DOMString { fn NamespaceURI(&self) -> DOMString {
(*self.namespacerule.read().url).into() let guard = self.cssrule.shared_lock().read();
(*self.namespacerule.read_with(&guard).url).into()
} }
} }
@ -62,6 +63,7 @@ impl SpecificCSSRule for CSSNamespaceRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.namespacerule.read().to_css_string().into() let guard = self.cssrule.shared_lock().read();
self.namespacerule.read_with(&guard).to_css_string(&guard).into()
} }
} }

View file

@ -20,6 +20,7 @@ use dom::cssviewportrule::CSSViewportRule;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::cell::Cell; use std::cell::Cell;
use style::shared_lock::SharedRwLock;
use style::stylesheets::CssRule as StyleCssRule; use style::stylesheets::CssRule as StyleCssRule;
@ -103,6 +104,10 @@ impl CSSRule {
pub fn parent_stylesheet(&self) -> &CSSStyleSheet { pub fn parent_stylesheet(&self) -> &CSSStyleSheet {
&self.parent_stylesheet &self.parent_stylesheet
} }
pub fn shared_lock(&self) -> &SharedRwLock {
&self.parent_stylesheet.style_stylesheet().shared_lock
}
} }
impl CSSRuleMethods for CSSRule { impl CSSRuleMethods for CSSRule {

View file

@ -13,8 +13,8 @@ use dom::cssrule::CSSRule;
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::Locked;
use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError}; use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError};
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -43,19 +43,20 @@ pub struct CSSRuleList {
} }
pub enum RulesSource { pub enum RulesSource {
Rules(Arc<RwLock<CssRules>>), Rules(Arc<Locked<CssRules>>),
Keyframes(Arc<RwLock<KeyframesRule>>), Keyframes(Arc<Locked<KeyframesRule>>),
} }
impl CSSRuleList { impl CSSRuleList {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList {
let guard = parent_stylesheet.shared_lock().read();
let dom_rules = match rules { let dom_rules = match rules {
RulesSource::Rules(ref rules) => { RulesSource::Rules(ref rules) => {
rules.read().0.iter().map(|_| MutNullableJS::new(None)).collect() rules.read_with(&guard).0.iter().map(|_| MutNullableJS::new(None)).collect()
} }
RulesSource::Keyframes(ref rules) => { RulesSource::Keyframes(ref rules) => {
rules.read().keyframes.iter().map(|_| MutNullableJS::new(None)).collect() rules.read_with(&guard).keyframes.iter().map(|_| MutNullableJS::new(None)).collect()
} }
}; };
@ -89,7 +90,12 @@ impl CSSRuleList {
let index = idx as usize; let index = idx as usize;
let parent_stylesheet = self.parent_stylesheet.style_stylesheet(); let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
let new_rule = css_rules.write().insert_rule(rule, parent_stylesheet, index, nested)?; let new_rule = {
let mut guard = parent_stylesheet.shared_lock.write();
css_rules.write_with(&mut guard).insert_rule(rule, parent_stylesheet, index, nested)?
// Drop `guard` here,
// CSSRule::new_specific re-acquires the lock for @support and @media.
};
let parent_stylesheet = &*self.parent_stylesheet; let parent_stylesheet = &*self.parent_stylesheet;
let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule); let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule);
@ -100,10 +106,11 @@ impl CSSRuleList {
// In case of a keyframe rule, index must be valid. // In case of a keyframe rule, index must be valid.
pub fn remove_rule(&self, index: u32) -> ErrorResult { pub fn remove_rule(&self, index: u32) -> ErrorResult {
let index = index as usize; let index = index as usize;
let mut guard = self.parent_stylesheet.shared_lock().write();
match self.rules { match self.rules {
RulesSource::Rules(ref css_rules) => { RulesSource::Rules(ref css_rules) => {
css_rules.write().remove_rule(index)?; css_rules.write_with(&mut guard).remove_rule(index)?;
let mut dom_rules = self.dom_rules.borrow_mut(); let mut dom_rules = self.dom_rules.borrow_mut();
dom_rules[index].get().map(|r| r.detach()); dom_rules[index].get().map(|r| r.detach());
dom_rules.remove(index); dom_rules.remove(index);
@ -114,7 +121,7 @@ impl CSSRuleList {
let mut dom_rules = self.dom_rules.borrow_mut(); let mut dom_rules = self.dom_rules.borrow_mut();
dom_rules[index].get().map(|r| r.detach()); dom_rules[index].get().map(|r| r.detach());
dom_rules.remove(index); dom_rules.remove(index);
kf.write().keyframes.remove(index); kf.write_with(&mut guard).keyframes.remove(index);
Ok(()) Ok(())
} }
} }
@ -131,16 +138,17 @@ impl CSSRuleList {
self.dom_rules.borrow().get(idx as usize).map(|rule| { self.dom_rules.borrow().get(idx as usize).map(|rule| {
rule.or_init(|| { rule.or_init(|| {
let parent_stylesheet = &self.parent_stylesheet; let parent_stylesheet = &self.parent_stylesheet;
let guard = parent_stylesheet.shared_lock().read();
match self.rules { match self.rules {
RulesSource::Rules(ref rules) => { RulesSource::Rules(ref rules) => {
CSSRule::new_specific(self.global().as_window(), CSSRule::new_specific(self.global().as_window(),
parent_stylesheet, parent_stylesheet,
rules.read().0[idx as usize].clone()) rules.read_with(&guard).0[idx as usize].clone())
} }
RulesSource::Keyframes(ref rules) => { RulesSource::Keyframes(ref rules) => {
Root::upcast(CSSKeyframeRule::new(self.global().as_window(), Root::upcast(CSSKeyframeRule::new(self.global().as_window(),
parent_stylesheet, parent_stylesheet,
rules.read() rules.read_with(&guard)
.keyframes[idx as usize] .keyframes[idx as usize]
.clone())) .clone()))
} }

View file

@ -11,10 +11,9 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::cssrule::CSSRule; use dom::cssrule::CSSRule;
use dom::element::Element; use dom::element::Element;
use dom::node::{Node, window_from_node}; use dom::node::{Node, window_from_node, document_from_node};
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::sync::Arc; use std::sync::Arc;
@ -23,6 +22,7 @@ use style::parser::ParserContextExtraData;
use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId}; use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId};
use style::properties::{parse_one_declaration, parse_style_attribute}; use style::properties::{parse_one_declaration, parse_style_attribute};
use style::selector_parser::PseudoElement; use style::selector_parser::PseudoElement;
use style::shared_lock::Locked;
use style_traits::ToCss; use style_traits::ToCss;
// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface // http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
@ -40,7 +40,7 @@ pub enum CSSStyleOwner {
Element(JS<Element>), Element(JS<Element>),
CSSRule(JS<CSSRule>, CSSRule(JS<CSSRule>,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
Arc<RwLock<PropertyDeclarationBlock>>), Arc<Locked<PropertyDeclarationBlock>>),
} }
impl CSSStyleOwner { impl CSSStyleOwner {
@ -55,10 +55,13 @@ impl CSSStyleOwner {
let mut changed = true; let mut changed = true;
match *self { match *self {
CSSStyleOwner::Element(ref el) => { CSSStyleOwner::Element(ref el) => {
let document = document_from_node(&**el);
let shared_lock = document.style_shared_lock();
let mut attr = el.style_attribute().borrow_mut().take(); let mut attr = el.style_attribute().borrow_mut().take();
let result = if attr.is_some() { let result = if attr.is_some() {
let lock = attr.as_ref().unwrap(); let lock = attr.as_ref().unwrap();
let mut pdb = lock.write(); let mut guard = shared_lock.write();
let mut pdb = lock.write_with(&mut guard);
let result = f(&mut pdb, &mut changed); let result = f(&mut pdb, &mut changed);
result result
} else { } else {
@ -69,7 +72,7 @@ impl CSSStyleOwner {
// exact conditions under it changes. // exact conditions under it changes.
changed = !pdb.declarations().is_empty(); changed = !pdb.declarations().is_empty();
if changed { if changed {
attr = Some(Arc::new(RwLock::new(pdb))); attr = Some(Arc::new(shared_lock.wrap(pdb)));
} }
result result
@ -83,7 +86,8 @@ impl CSSStyleOwner {
// //
// [1]: https://github.com/whatwg/html/issues/2306 // [1]: https://github.com/whatwg/html/issues/2306
if let Some(pdb) = attr { if let Some(pdb) = attr {
let serialization = pdb.read().to_css_string(); let guard = shared_lock.read();
let serialization = pdb.read_with(&guard).to_css_string();
el.set_attribute(&local_name!("style"), el.set_attribute(&local_name!("style"),
AttrValue::Declaration(serialization, AttrValue::Declaration(serialization,
pdb)); pdb));
@ -96,7 +100,10 @@ impl CSSStyleOwner {
result result
} }
CSSStyleOwner::CSSRule(ref rule, ref pdb) => { CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
let result = f(&mut *pdb.write(), &mut changed); let result = {
let mut guard = rule.shared_lock().write();
f(&mut *pdb.write_with(&mut guard), &mut changed)
};
if changed { if changed {
rule.global().as_window().Document().invalidate_stylesheets(); rule.global().as_window().Document().invalidate_stylesheets();
} }
@ -111,15 +118,20 @@ impl CSSStyleOwner {
match *self { match *self {
CSSStyleOwner::Element(ref el) => { CSSStyleOwner::Element(ref el) => {
match *el.style_attribute().borrow() { match *el.style_attribute().borrow() {
Some(ref pdb) => f(&pdb.read()), Some(ref pdb) => {
let document = document_from_node(&**el);
let guard = document.style_shared_lock().read();
f(pdb.read_with(&guard))
}
None => { None => {
let pdb = PropertyDeclarationBlock::new(); let pdb = PropertyDeclarationBlock::new();
f(&pdb) f(&pdb)
} }
} }
} }
CSSStyleOwner::CSSRule(_, ref pdb) => { CSSStyleOwner::CSSRule(ref rule, ref pdb) => {
f(&pdb.read()) let guard = rule.shared_lock().read();
f(pdb.read_with(&guard))
} }
} }
} }

View file

@ -12,21 +12,20 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::StyleRule; use style::stylesheets::StyleRule;
use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct CSSStyleRule { pub struct CSSStyleRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
stylerule: Arc<RwLock<StyleRule>>, stylerule: Arc<Locked<StyleRule>>,
style_decl: MutNullableJS<CSSStyleDeclaration>, style_decl: MutNullableJS<CSSStyleDeclaration>,
} }
impl CSSStyleRule { impl CSSStyleRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<RwLock<StyleRule>>) fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc<Locked<StyleRule>>)
-> CSSStyleRule { -> CSSStyleRule {
CSSStyleRule { CSSStyleRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
@ -37,7 +36,7 @@ impl CSSStyleRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
stylerule: Arc<RwLock<StyleRule>>) -> Root<CSSStyleRule> { stylerule: Arc<Locked<StyleRule>>) -> Root<CSSStyleRule> {
reflect_dom_object(box CSSStyleRule::new_inherited(parent_stylesheet, stylerule), reflect_dom_object(box CSSStyleRule::new_inherited(parent_stylesheet, stylerule),
window, window,
CSSStyleRuleBinding::Wrap) CSSStyleRuleBinding::Wrap)
@ -51,7 +50,8 @@ impl SpecificCSSRule for CSSStyleRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.stylerule.read().to_css_string().into() let guard = self.cssrule.shared_lock().read();
self.stylerule.read_with(&guard).to_css_string(&guard).into()
} }
} }
@ -59,11 +59,16 @@ impl CSSStyleRuleMethods for CSSStyleRule {
// https://drafts.csswg.org/cssom/#dom-cssstylerule-style // https://drafts.csswg.org/cssom/#dom-cssstylerule-style
fn Style(&self) -> Root<CSSStyleDeclaration> { fn Style(&self) -> Root<CSSStyleDeclaration> {
self.style_decl.or_init(|| { self.style_decl.or_init(|| {
CSSStyleDeclaration::new(self.global().as_window(), let guard = self.cssrule.shared_lock().read();
CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()), CSSStyleDeclaration::new(
self.stylerule.read().block.clone()), self.global().as_window(),
None, CSSStyleOwner::CSSRule(
CSSModificationAccess::ReadWrite) JS::from_ref(self.upcast()),
self.stylerule.read_with(&guard).block.clone()
),
None,
CSSModificationAccess::ReadWrite
)
}) })
} }
} }

View file

@ -16,6 +16,7 @@ use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::cell::Cell; use std::cell::Cell;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::SharedRwLock;
use style::stylesheets::Stylesheet as StyleStyleSheet; use style::stylesheets::Stylesheet as StyleStyleSheet;
#[dom_struct] #[dom_struct]
@ -72,6 +73,10 @@ impl CSSStyleSheet {
} }
} }
pub fn shared_lock(&self) -> &SharedRwLock {
&self.style_stylesheet.shared_lock
}
pub fn style_stylesheet(&self) -> &StyleStyleSheet { pub fn style_stylesheet(&self) -> &StyleStyleSheet {
&self.style_stylesheet &self.style_stylesheet
} }

View file

@ -13,33 +13,34 @@ use dom::cssrule::SpecificCSSRule;
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::parser::ParserContext; use style::parser::ParserContext;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::stylesheets::SupportsRule; use style::stylesheets::SupportsRule;
use style::supports::SupportsCondition; use style::supports::SupportsCondition;
use style_traits::ToCss; use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct CSSSupportsRule { pub struct CSSSupportsRule {
cssrule: CSSConditionRule, cssconditionrule: CSSConditionRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
supportsrule: Arc<RwLock<SupportsRule>>, supportsrule: Arc<Locked<SupportsRule>>,
} }
impl CSSSupportsRule { impl CSSSupportsRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<RwLock<SupportsRule>>) fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc<Locked<SupportsRule>>)
-> CSSSupportsRule { -> CSSSupportsRule {
let list = supportsrule.read().rules.clone(); let guard = parent_stylesheet.shared_lock().read();
let list = supportsrule.read_with(&guard).rules.clone();
CSSSupportsRule { CSSSupportsRule {
cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list),
supportsrule: supportsrule, supportsrule: supportsrule,
} }
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
supportsrule: Arc<RwLock<SupportsRule>>) -> Root<CSSSupportsRule> { supportsrule: Arc<Locked<SupportsRule>>) -> Root<CSSSupportsRule> {
reflect_dom_object(box CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule), reflect_dom_object(box CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule),
window, window,
CSSSupportsRuleBinding::Wrap) CSSSupportsRuleBinding::Wrap)
@ -47,7 +48,8 @@ impl CSSSupportsRule {
/// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
pub fn get_condition_text(&self) -> DOMString { pub fn get_condition_text(&self) -> DOMString {
let rule = self.supportsrule.read(); let guard = self.cssconditionrule.shared_lock().read();
let rule = self.supportsrule.read_with(&guard);
rule.condition.to_css_string().into() rule.condition.to_css_string().into()
} }
@ -61,7 +63,8 @@ impl CSSSupportsRule {
let url = win.Document().url(); let url = win.Document().url();
let context = ParserContext::new_for_cssom(&url, win.css_error_reporter()); let context = ParserContext::new_for_cssom(&url, win.css_error_reporter());
let enabled = cond.eval(&context); let enabled = cond.eval(&context);
let mut rule = self.supportsrule.write(); let mut guard = self.cssconditionrule.shared_lock().write();
let rule = self.supportsrule.write_with(&mut guard);
rule.condition = cond; rule.condition = cond;
rule.enabled = enabled; rule.enabled = enabled;
} }
@ -75,6 +78,7 @@ impl SpecificCSSRule for CSSSupportsRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.supportsrule.read().to_css_string().into() let guard = self.cssconditionrule.shared_lock().read();
self.supportsrule.read_with(&guard).to_css_string(&guard).into()
} }
} }

View file

@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule};
use dom::cssstylesheet::CSSStyleSheet; use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::shared_lock::{Locked, ToCssWithGuard};
use style::viewport::ViewportRule; use style::viewport::ViewportRule;
use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct CSSViewportRule { pub struct CSSViewportRule {
cssrule: CSSRule, cssrule: CSSRule,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
viewportrule: Arc<RwLock<ViewportRule>>, viewportrule: Arc<Locked<ViewportRule>>,
} }
impl CSSViewportRule { impl CSSViewportRule {
fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule { fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc<Locked<ViewportRule>>) -> CSSViewportRule {
CSSViewportRule { CSSViewportRule {
cssrule: CSSRule::new_inherited(parent_stylesheet), cssrule: CSSRule::new_inherited(parent_stylesheet),
viewportrule: viewportrule, viewportrule: viewportrule,
@ -32,7 +31,7 @@ impl CSSViewportRule {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
viewportrule: Arc<RwLock<ViewportRule>>) -> Root<CSSViewportRule> { viewportrule: Arc<Locked<ViewportRule>>) -> Root<CSSViewportRule> {
reflect_dom_object(box CSSViewportRule::new_inherited(parent_stylesheet, viewportrule), reflect_dom_object(box CSSViewportRule::new_inherited(parent_stylesheet, viewportrule),
window, window,
CSSViewportRuleBinding::Wrap) CSSViewportRuleBinding::Wrap)
@ -46,6 +45,7 @@ impl SpecificCSSRule for CSSViewportRule {
} }
fn get_css(&self) -> DOMString { fn get_css(&self) -> DOMString {
self.viewportrule.read().to_css_string().into() let guard = self.cssrule.shared_lock().read();
self.viewportrule.read_with(&guard).to_css_string(&guard).into()
} }
} }

View file

@ -134,6 +134,8 @@ use style::attr::AttrValue;
use style::context::{QuirksMode, ReflowGoal}; use style::context::{QuirksMode, ReflowGoal};
use style::restyle_hints::{RestyleHint, RESTYLE_STYLE_ATTRIBUTE}; use style::restyle_hints::{RestyleHint, RESTYLE_STYLE_ATTRIBUTE};
use style::selector_parser::{RestyleDamage, Snapshot}; use style::selector_parser::{RestyleDamage, Snapshot};
use style::servo::AUTHOR_SHARED_LOCK;
use style::shared_lock::SharedRwLock as StyleSharedRwLock;
use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join}; use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join};
use style::stylesheets::Stylesheet; use style::stylesheets::Stylesheet;
use task_source::TaskSource; use task_source::TaskSource;
@ -220,6 +222,9 @@ pub struct Document {
scripts: MutNullableJS<HTMLCollection>, scripts: MutNullableJS<HTMLCollection>,
anchors: MutNullableJS<HTMLCollection>, anchors: MutNullableJS<HTMLCollection>,
applets: MutNullableJS<HTMLCollection>, applets: MutNullableJS<HTMLCollection>,
/// Lock use for style attributes and author-origin stylesheet objects in this document.
/// Can be acquired once for accessing many objects.
style_shared_lock: StyleSharedRwLock,
/// List of stylesheets associated with nodes in this document. |None| if the list needs to be refreshed. /// List of stylesheets associated with nodes in this document. |None| if the list needs to be refreshed.
stylesheets: DOMRefCell<Option<Vec<StylesheetInDocument>>>, stylesheets: DOMRefCell<Option<Vec<StylesheetInDocument>>>,
/// Whether the list of stylesheets has changed since the last reflow was triggered. /// Whether the list of stylesheets has changed since the last reflow was triggered.
@ -1964,6 +1969,7 @@ pub trait LayoutDocumentHelpers {
unsafe fn needs_paint_from_layout(&self); unsafe fn needs_paint_from_layout(&self);
unsafe fn will_paint(&self); unsafe fn will_paint(&self);
unsafe fn quirks_mode(&self) -> QuirksMode; unsafe fn quirks_mode(&self) -> QuirksMode;
unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock;
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -2000,6 +2006,11 @@ impl LayoutDocumentHelpers for LayoutJS<Document> {
unsafe fn quirks_mode(&self) -> QuirksMode { unsafe fn quirks_mode(&self) -> QuirksMode {
(*self.unsafe_get()).quirks_mode() (*self.unsafe_get()).quirks_mode()
} }
#[inline]
unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock {
(*self.unsafe_get()).style_shared_lock()
}
} }
// https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to // https://html.spec.whatwg.org/multipage/#is-a-registrable-domain-suffix-of-or-is-equal-to
@ -2121,6 +2132,7 @@ impl Document {
scripts: Default::default(), scripts: Default::default(),
anchors: Default::default(), anchors: Default::default(),
applets: Default::default(), applets: Default::default(),
style_shared_lock: AUTHOR_SHARED_LOCK.clone(),
stylesheets: DOMRefCell::new(None), stylesheets: DOMRefCell::new(None),
stylesheets_changed_since_reflow: Cell::new(false), stylesheets_changed_since_reflow: Cell::new(false),
stylesheet_list: MutNullableJS::new(None), stylesheet_list: MutNullableJS::new(None),
@ -2250,6 +2262,11 @@ impl Document {
}; };
} }
/// Return a reference to the per-document shared lock used in stylesheets.
pub fn style_shared_lock(&self) -> &StyleSharedRwLock {
&self.style_shared_lock
}
/// Returns the list of stylesheets associated with nodes in the document. /// Returns the list of stylesheets associated with nodes in the document.
pub fn stylesheets(&self) -> Vec<Arc<Stylesheet>> { pub fn stylesheets(&self) -> Vec<Arc<Stylesheet>> {
self.ensure_stylesheets(); self.ensure_stylesheets();

View file

@ -82,7 +82,6 @@ use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode};
use html5ever_atoms::{Prefix, LocalName, Namespace, QualName}; use html5ever_atoms::{Prefix, LocalName, Namespace, QualName};
use js::jsapi::{HandleValue, JSAutoCompartment}; use js::jsapi::{HandleValue, JSAutoCompartment};
use net_traits::request::CorsSettings; use net_traits::request::CorsSettings;
use parking_lot::RwLock;
use ref_filter_map::ref_filter_map; use ref_filter_map::ref_filter_map;
use script_layout_interface::message::ReflowQueryType; use script_layout_interface::message::ReflowQueryType;
use script_thread::Runnable; use script_thread::Runnable;
@ -108,6 +107,7 @@ use style::properties::longhands::{self, background_image, border_spacing, font_
use style::restyle_hints::RESTYLE_SELF; use style::restyle_hints::RESTYLE_SELF;
use style::rule_tree::CascadeLevel; use style::rule_tree::CascadeLevel;
use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser}; use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser};
use style::shared_lock::{SharedRwLock, Locked};
use style::sink::Push; use style::sink::Push;
use style::stylist::ApplicableDeclarationBlock; use style::stylist::ApplicableDeclarationBlock;
use style::thread_state; use style::thread_state;
@ -129,7 +129,7 @@ pub struct Element {
attrs: DOMRefCell<Vec<JS<Attr>>>, attrs: DOMRefCell<Vec<JS<Attr>>>,
id_attribute: DOMRefCell<Option<Atom>>, id_attribute: DOMRefCell<Option<Atom>>,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
style_attribute: DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>>, style_attribute: DOMRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>>,
attr_list: MutNullableJS<NamedNodeMap>, attr_list: MutNullableJS<NamedNodeMap>,
class_list: MutNullableJS<DOMTokenList>, class_list: MutNullableJS<DOMTokenList>,
state: Cell<ElementState>, state: Cell<ElementState>,
@ -352,7 +352,7 @@ pub trait LayoutElementHelpers {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool; unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
fn id_attribute(&self) -> *const Option<Atom>; fn id_attribute(&self) -> *const Option<Atom>;
fn style_attribute(&self) -> *const Option<Arc<RwLock<PropertyDeclarationBlock>>>; fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
fn local_name(&self) -> &LocalName; fn local_name(&self) -> &LocalName;
fn namespace(&self) -> &Namespace; fn namespace(&self) -> &Namespace;
fn get_lang_for_layout(&self) -> String; fn get_lang_for_layout(&self) -> String;
@ -384,14 +384,18 @@ impl LayoutElementHelpers for LayoutJS<Element> {
where V: Push<ApplicableDeclarationBlock> where V: Push<ApplicableDeclarationBlock>
{ {
#[inline] #[inline]
fn from_declaration(declaration: PropertyDeclaration) -> ApplicableDeclarationBlock { fn from_declaration(shared_lock: &SharedRwLock, declaration: PropertyDeclaration)
-> ApplicableDeclarationBlock {
ApplicableDeclarationBlock::from_declarations( ApplicableDeclarationBlock::from_declarations(
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
declaration, Importance::Normal declaration, Importance::Normal
))), ))),
CascadeLevel::PresHints) CascadeLevel::PresHints)
} }
let document = self.upcast::<Node>().owner_doc_for_layout();
let shared_lock = document.style_shared_lock();
let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() { let bgcolor = if let Some(this) = self.downcast::<HTMLBodyElement>() {
this.get_background_color() this.get_background_color()
} else if let Some(this) = self.downcast::<HTMLTableElement>() { } else if let Some(this) = self.downcast::<HTMLTableElement>() {
@ -408,6 +412,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(color) = bgcolor { if let Some(color) = bgcolor {
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BackgroundColor( PropertyDeclaration::BackgroundColor(
CSSColor { parsed: Color::RGBA(color), authored: None }))); CSSColor { parsed: Color::RGBA(color), authored: None })));
} }
@ -420,6 +425,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(url) = background { if let Some(url) = background {
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BackgroundImage( PropertyDeclaration::BackgroundImage(
background_image::SpecifiedValue(vec![ background_image::SpecifiedValue(vec![
background_image::single_value::SpecifiedValue(Some( background_image::single_value::SpecifiedValue(Some(
@ -442,6 +448,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(color) = color { if let Some(color) = color {
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Color( PropertyDeclaration::Color(
longhands::color::SpecifiedValue(CSSColor { longhands::color::SpecifiedValue(CSSColor {
parsed: Color::RGBA(color), parsed: Color::RGBA(color),
@ -459,6 +466,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(font_family) = font_family { if let Some(font_family) = font_family {
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::FontFamily( PropertyDeclaration::FontFamily(
font_family::computed_value::T(vec![ font_family::computed_value::T(vec![
font_family::computed_value::FontFamily::from_atom( font_family::computed_value::FontFamily::from_atom(
@ -469,6 +477,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(font_size) = font_size { if let Some(font_size) = font_size {
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::FontSize(font_size::SpecifiedValue(font_size.into())))) PropertyDeclaration::FontSize(font_size::SpecifiedValue(font_size.into()))))
} }
@ -481,6 +490,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(cellspacing) = cellspacing { if let Some(cellspacing) = cellspacing {
let width_value = specified::Length::from_px(cellspacing as f32); let width_value = specified::Length::from_px(cellspacing as f32);
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderSpacing( PropertyDeclaration::BorderSpacing(
Box::new(border_spacing::SpecifiedValue { Box::new(border_spacing::SpecifiedValue {
horizontal: width_value.clone(), horizontal: width_value.clone(),
@ -514,6 +524,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(size) = size { if let Some(size) = size {
let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size)); let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width( PropertyDeclaration::Width(
specified::LengthOrPercentageOrAuto::Length(value)))); specified::LengthOrPercentageOrAuto::Length(value))));
} }
@ -539,12 +550,14 @@ impl LayoutElementHelpers for LayoutJS<Element> {
let width_value = let width_value =
specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(width_value))); PropertyDeclaration::Width(width_value)));
} }
LengthOrPercentageOrAuto::Length(length) => { LengthOrPercentageOrAuto::Length(length) => {
let width_value = specified::LengthOrPercentageOrAuto::Length( let width_value = specified::LengthOrPercentageOrAuto::Length(
specified::NoCalcLength::Absolute(length)); specified::NoCalcLength::Absolute(length));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(width_value))); PropertyDeclaration::Width(width_value)));
} }
} }
@ -564,12 +577,14 @@ impl LayoutElementHelpers for LayoutJS<Element> {
let height_value = let height_value =
specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(height_value))); PropertyDeclaration::Height(height_value)));
} }
LengthOrPercentageOrAuto::Length(length) => { LengthOrPercentageOrAuto::Length(length) => {
let height_value = specified::LengthOrPercentageOrAuto::Length( let height_value = specified::LengthOrPercentageOrAuto::Length(
specified::NoCalcLength::Absolute(length)); specified::NoCalcLength::Absolute(length));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(height_value))); PropertyDeclaration::Height(height_value)));
} }
} }
@ -592,6 +607,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
// https://html.spec.whatwg.org/multipage/#textarea-effective-width // https://html.spec.whatwg.org/multipage/#textarea-effective-width
let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols)); let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(specified::LengthOrPercentageOrAuto::Length(value)))); PropertyDeclaration::Width(specified::LengthOrPercentageOrAuto::Length(value))));
} }
@ -610,6 +626,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
// https://html.spec.whatwg.org/multipage/#textarea-effective-height // https://html.spec.whatwg.org/multipage/#textarea-effective-height
let value = specified::NoCalcLength::FontRelative(specified::FontRelativeLength::Em(rows as CSSFloat)); let value = specified::NoCalcLength::FontRelative(specified::FontRelativeLength::Em(rows as CSSFloat));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(specified::LengthOrPercentageOrAuto::Length(value)))); PropertyDeclaration::Height(specified::LengthOrPercentageOrAuto::Length(value))));
} }
@ -623,12 +640,16 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(border) = border { if let Some(border) = border {
let width_value = specified::BorderWidth::from_length(specified::Length::from_px(border as f32)); let width_value = specified::BorderWidth::from_length(specified::Length::from_px(border as f32));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderTopWidth(Box::new(width_value.clone())))); PropertyDeclaration::BorderTopWidth(Box::new(width_value.clone()))));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderLeftWidth(Box::new(width_value.clone())))); PropertyDeclaration::BorderLeftWidth(Box::new(width_value.clone()))));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderBottomWidth(Box::new(width_value.clone())))); PropertyDeclaration::BorderBottomWidth(Box::new(width_value.clone()))));
hints.push(from_declaration( hints.push(from_declaration(
shared_lock,
PropertyDeclaration::BorderRightWidth(Box::new(width_value)))); PropertyDeclaration::BorderRightWidth(Box::new(width_value))));
} }
} }
@ -672,7 +693,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn style_attribute(&self) -> *const Option<Arc<RwLock<PropertyDeclarationBlock>>> { fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>> {
unsafe { unsafe {
(*self.unsafe_get()).style_attribute.borrow_for_layout() (*self.unsafe_get()).style_attribute.borrow_for_layout()
} }
@ -835,7 +856,7 @@ impl Element {
ns!() ns!()
} }
pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<RwLock<PropertyDeclarationBlock>>>> { pub fn style_attribute(&self) -> &DOMRefCell<Option<Arc<Locked<PropertyDeclarationBlock>>>> {
&self.style_attribute &self.style_attribute
} }
@ -2170,7 +2191,7 @@ impl VirtualMethods for Element {
block block
} else { } else {
let win = window_from_node(self); let win = window_from_node(self);
Arc::new(RwLock::new(parse_style_attribute( Arc::new(doc.style_shared_lock().wrap(parse_style_attribute(
&attr.value(), &attr.value(),
&doc.base_url(), &doc.base_url(),
win.css_error_reporter(), win.css_error_reporter(),

View file

@ -291,9 +291,8 @@ impl HTMLLinkElement {
// doesn't match. // doesn't match.
let loader = StylesheetLoader::for_element(self.upcast()); let loader = StylesheetLoader::for_element(self.upcast());
loader.load(StylesheetContextSource::LinkElement { loader.load(StylesheetContextSource::LinkElement {
url: url,
media: Some(media), media: Some(media),
}, cors_setting, integrity_metadata.to_owned()); }, url, cors_setting, integrity_metadata.to_owned());
} }
fn handle_favicon_url(&self, rel: &str, href: &str, sizes: &Option<String>) { fn handle_favicon_url(&self, rel: &str, href: &str, sizes: &Option<String>) {

View file

@ -19,7 +19,6 @@ use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use html5ever_atoms::LocalName; use html5ever_atoms::LocalName;
use parking_lot::RwLock;
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::sync::Arc; use std::sync::Arc;
@ -99,12 +98,16 @@ impl HTMLMetaElement {
let content = content.value(); let content = content.value();
if !content.is_empty() { if !content.is_empty() {
if let Some(translated_rule) = ViewportRule::from_meta(&**content) { if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
let document = self.upcast::<Node>().owner_doc();
let shared_lock = document.style_shared_lock();
let rule = CssRule::Viewport(Arc::new(shared_lock.wrap(translated_rule)));
*self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet { *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
rules: CssRules::new(vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))]), rules: CssRules::new(vec![rule], shared_lock),
origin: Origin::Author, origin: Origin::Author,
shared_lock: shared_lock.clone(),
base_url: window_from_node(self).get_url(), base_url: window_from_node(self).get_url(),
namespaces: Default::default(), namespaces: Default::default(),
media: Default::default(), media: Arc::new(shared_lock.wrap(Default::default())),
// Viewport constraints are always recomputed on resize; they don't need to // Viewport constraints are always recomputed on resize; they don't need to
// force all styles to be recomputed. // force all styles to be recomputed.
dirty_on_viewport_size_change: AtomicBool::new(false), dirty_on_viewport_size_change: AtomicBool::new(false),

View file

@ -84,9 +84,10 @@ impl HTMLStyleElement {
let data = node.GetTextContent().expect("Element.textContent must be a string"); let data = node.GetTextContent().expect("Element.textContent must be a string");
let mq = parse_media_query_list(&mut CssParser::new(&mq_str)); let mq = parse_media_query_list(&mut CssParser::new(&mq_str));
let shared_lock = node.owner_doc().style_shared_lock().clone();
let loader = StylesheetLoader::for_element(self.upcast()); let loader = StylesheetLoader::for_element(self.upcast());
let sheet = Stylesheet::from_str(&data, url, Origin::Author, mq, let sheet = Stylesheet::from_str(&data, url, Origin::Author, mq,
Some(&loader), shared_lock, Some(&loader),
win.css_error_reporter(), win.css_error_reporter(),
ParserContextExtraData::default()); ParserContextExtraData::default());

View file

@ -6,52 +6,62 @@ use core::default::Default;
use cssparser::Parser; use cssparser::Parser;
use dom::bindings::codegen::Bindings::MediaListBinding; use dom::bindings::codegen::Bindings::MediaListBinding;
use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods; use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods;
use dom::bindings::js::Root; use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString; use dom::bindings::str::DOMString;
use dom::cssstylesheet::CSSStyleSheet;
use dom::window::Window; use dom::window::Window;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::media_queries::{MediaQuery, parse_media_query_list}; use style::media_queries::{MediaQuery, parse_media_query_list};
use style::media_queries::MediaList as StyleMediaList; use style::media_queries::MediaList as StyleMediaList;
use style::shared_lock::{SharedRwLock, Locked};
use style_traits::ToCss; use style_traits::ToCss;
#[dom_struct] #[dom_struct]
pub struct MediaList { pub struct MediaList {
reflector_: Reflector, reflector_: Reflector,
parent_stylesheet: JS<CSSStyleSheet>,
#[ignore_heap_size_of = "Arc"] #[ignore_heap_size_of = "Arc"]
media_queries: Arc<RwLock<StyleMediaList>>, media_queries: Arc<Locked<StyleMediaList>>,
} }
impl MediaList { impl MediaList {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new_inherited(media_queries: Arc<RwLock<StyleMediaList>>) -> MediaList { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet,
media_queries: Arc<Locked<StyleMediaList>>) -> MediaList {
MediaList { MediaList {
parent_stylesheet: JS::from_ref(parent_stylesheet),
reflector_: Reflector::new(), reflector_: Reflector::new(),
media_queries: media_queries, media_queries: media_queries,
} }
} }
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
pub fn new(window: &Window, media_queries: Arc<RwLock<StyleMediaList>>) pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet,
media_queries: Arc<Locked<StyleMediaList>>)
-> Root<MediaList> { -> Root<MediaList> {
reflect_dom_object(box MediaList::new_inherited(media_queries), reflect_dom_object(box MediaList::new_inherited(parent_stylesheet, media_queries),
window, window,
MediaListBinding::Wrap) MediaListBinding::Wrap)
} }
fn shared_lock(&self) -> &SharedRwLock {
&self.parent_stylesheet.style_stylesheet().shared_lock
}
} }
impl MediaListMethods for MediaList { impl MediaListMethods for MediaList {
// https://drafts.csswg.org/cssom/#dom-medialist-mediatext // https://drafts.csswg.org/cssom/#dom-medialist-mediatext
fn MediaText(&self) -> DOMString { fn MediaText(&self) -> DOMString {
DOMString::from(self.media_queries.read().to_css_string()) let guard = self.shared_lock().read();
DOMString::from(self.media_queries.read_with(&guard).to_css_string())
} }
// https://drafts.csswg.org/cssom/#dom-medialist-mediatext // https://drafts.csswg.org/cssom/#dom-medialist-mediatext
fn SetMediaText(&self, value: DOMString) { fn SetMediaText(&self, value: DOMString) {
let mut media_queries = self.media_queries.write(); let mut guard = self.shared_lock().write();
let mut media_queries = self.media_queries.write_with(&mut guard);
// Step 2 // Step 2
if value.is_empty() { if value.is_empty() {
// Step 1 // Step 1
@ -65,13 +75,15 @@ impl MediaListMethods for MediaList {
// https://drafts.csswg.org/cssom/#dom-medialist-length // https://drafts.csswg.org/cssom/#dom-medialist-length
fn Length(&self) -> u32 { fn Length(&self) -> u32 {
self.media_queries.read().media_queries.len() as u32 let guard = self.shared_lock().read();
self.media_queries.read_with(&guard).media_queries.len() as u32
} }
// https://drafts.csswg.org/cssom/#dom-medialist-item // https://drafts.csswg.org/cssom/#dom-medialist-item
fn Item(&self, index: u32) -> Option<DOMString> { fn Item(&self, index: u32) -> Option<DOMString> {
self.media_queries.read().media_queries.get(index as usize) let guard = self.shared_lock().read();
.and_then(|query| { self.media_queries.read_with(&guard).media_queries
.get(index as usize).and_then(|query| {
let mut s = String::new(); let mut s = String::new();
query.to_css(&mut s).unwrap(); query.to_css(&mut s).unwrap();
Some(DOMString::from_string(s)) Some(DOMString::from_string(s))
@ -94,13 +106,14 @@ impl MediaListMethods for MediaList {
} }
// Step 3 // Step 3
let m_serialized = m.clone().unwrap().to_css_string(); let m_serialized = m.clone().unwrap().to_css_string();
let any = self.media_queries.read().media_queries.iter() let mut guard = self.shared_lock().write();
.any(|q| m_serialized == q.to_css_string()); let mq = self.media_queries.write_with(&mut guard);
let any = mq.media_queries.iter().any(|q| m_serialized == q.to_css_string());
if any { if any {
return; return;
} }
// Step 4 // Step 4
self.media_queries.write().media_queries.push(m.unwrap()); mq.media_queries.push(m.unwrap());
} }
// https://drafts.csswg.org/cssom/#dom-medialist-deletemedium // https://drafts.csswg.org/cssom/#dom-medialist-deletemedium
@ -114,7 +127,8 @@ impl MediaListMethods for MediaList {
} }
// Step 3 // Step 3
let m_serialized = m.unwrap().to_css_string(); let m_serialized = m.unwrap().to_css_string();
let mut media_list = self.media_queries.write(); let mut guard = self.shared_lock().write();
let mut media_list = self.media_queries.write_with(&mut guard);
let new_vec = media_list.media_queries.drain(..) let new_vec = media_list.media_queries.drain(..)
.filter(|q| m_serialized != q.to_css_string()) .filter(|q| m_serialized != q.to_css_string())
.collect(); .collect();

View file

@ -44,7 +44,6 @@ use dom::text::Text;
use gfx_traits::ByteIndex; use gfx_traits::ByteIndex;
use html5ever_atoms::{LocalName, Namespace}; use html5ever_atoms::{LocalName, Namespace};
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use parking_lot::RwLock;
use range::Range; use range::Range;
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress}; use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
@ -69,6 +68,7 @@ use style::dom::UnsafeNode;
use style::element_state::*; use style::element_state::*;
use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::properties::{ComputedValues, PropertyDeclarationBlock};
use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl}; use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::sink::Push; use style::sink::Push;
use style::str::is_whitespace; use style::str::is_whitespace;
use style::stylist::ApplicableDeclarationBlock; use style::stylist::ApplicableDeclarationBlock;
@ -330,6 +330,10 @@ impl<'ld> ServoLayoutDocument<'ld> {
unsafe { self.document.quirks_mode() } unsafe { self.document.quirks_mode() }
} }
pub fn style_shared_lock(&self) -> &StyleSharedRwLock {
unsafe { self.document.style_shared_lock() }
}
pub fn from_layout_js(doc: LayoutJS<Document>) -> ServoLayoutDocument<'ld> { pub fn from_layout_js(doc: LayoutJS<Document>) -> ServoLayoutDocument<'ld> {
ServoLayoutDocument { ServoLayoutDocument {
document: doc, document: doc,
@ -372,7 +376,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast()) ServoLayoutNode::from_layout_js(self.element.upcast())
} }
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> { fn style_attribute(&self) -> Option<&Arc<StyleLocked<PropertyDeclarationBlock>>> {
unsafe { unsafe {
(*self.element.style_attribute()).as_ref() (*self.element.style_attribute()).as_ref()
} }

View file

@ -22,13 +22,13 @@ use ipc_channel::router::ROUTER;
use net_traits::{FetchResponseListener, FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy}; use net_traits::{FetchResponseListener, FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType}; use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType};
use network_listener::{NetworkListener, PreInvoke}; use network_listener::{NetworkListener, PreInvoke};
use parking_lot::RwLock;
use script_layout_interface::message::Msg; use script_layout_interface::message::Msg;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::mem; use std::mem;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use style::media_queries::MediaList; use style::media_queries::MediaList;
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::shared_lock::Locked as StyleLocked;
use style::stylesheets::{ImportRule, Stylesheet, Origin}; use style::stylesheets::{ImportRule, Stylesheet, Origin};
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
@ -54,24 +54,8 @@ pub trait StylesheetOwner {
pub enum StylesheetContextSource { pub enum StylesheetContextSource {
// NB: `media` is just an option so we avoid cloning it. // NB: `media` is just an option so we avoid cloning it.
LinkElement { media: Option<MediaList>, url: ServoUrl }, LinkElement { media: Option<MediaList>, },
Import(Arc<RwLock<ImportRule>>), Import(Arc<Stylesheet>),
}
impl StylesheetContextSource {
fn url(&self) -> ServoUrl {
match *self {
StylesheetContextSource::LinkElement { ref url, .. } => url.clone(),
StylesheetContextSource::Import(ref import) => {
let import = import.read();
// Look at the parser in style::stylesheets, where we don't
// trigger a load if the url is invalid.
import.url.url()
.expect("Invalid urls shouldn't enter the loader")
.clone()
}
}
}
} }
/// The context required for asynchronously loading an external stylesheet. /// The context required for asynchronously loading an external stylesheet.
@ -79,6 +63,7 @@ pub struct StylesheetContext {
/// The element that initiated the request. /// The element that initiated the request.
elem: Trusted<HTMLElement>, elem: Trusted<HTMLElement>,
source: StylesheetContextSource, source: StylesheetContextSource,
url: ServoUrl,
metadata: Option<Metadata>, metadata: Option<Metadata>,
/// The response body received to date. /// The response body received to date.
data: Vec<u8>, data: Vec<u8>,
@ -145,19 +130,21 @@ impl FetchResponseListener for StylesheetContext {
let loader = StylesheetLoader::for_element(&elem); let loader = StylesheetLoader::for_element(&elem);
match self.source { match self.source {
StylesheetContextSource::LinkElement { ref mut media, .. } => { StylesheetContextSource::LinkElement { ref mut media } => {
let link = elem.downcast::<HTMLLinkElement>().unwrap(); let link = elem.downcast::<HTMLLinkElement>().unwrap();
// We must first check whether the generations of the context and the element match up, // We must first check whether the generations of the context and the element match up,
// else we risk applying the wrong stylesheet when responses come out-of-order. // else we risk applying the wrong stylesheet when responses come out-of-order.
let is_stylesheet_load_applicable = let is_stylesheet_load_applicable =
self.request_generation_id.map_or(true, |gen| gen == link.get_request_generation_id()); self.request_generation_id.map_or(true, |gen| gen == link.get_request_generation_id());
if is_stylesheet_load_applicable { if is_stylesheet_load_applicable {
let shared_lock = document.style_shared_lock().clone();
let sheet = let sheet =
Arc::new(Stylesheet::from_bytes(&data, final_url, Arc::new(Stylesheet::from_bytes(&data, final_url,
protocol_encoding_label, protocol_encoding_label,
Some(environment_encoding), Some(environment_encoding),
Origin::Author, Origin::Author,
media.take().unwrap(), media.take().unwrap(),
shared_lock,
Some(&loader), Some(&loader),
win.css_error_reporter(), win.css_error_reporter(),
ParserContextExtraData::default())); ParserContextExtraData::default()));
@ -171,9 +158,8 @@ impl FetchResponseListener for StylesheetContext {
win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap(); win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap();
} }
} }
StylesheetContextSource::Import(ref import) => { StylesheetContextSource::Import(ref stylesheet) => {
let import = import.read(); Stylesheet::update_from_bytes(&stylesheet,
Stylesheet::update_from_bytes(&import.stylesheet,
&data, &data,
protocol_encoding_label, protocol_encoding_label,
Some(environment_encoding), Some(environment_encoding),
@ -197,8 +183,7 @@ impl FetchResponseListener for StylesheetContext {
document.decrement_script_blocking_stylesheet_count(); document.decrement_script_blocking_stylesheet_count();
} }
let url = self.source.url(); document.finish_load(LoadType::Stylesheet(self.url.clone()));
document.finish_load(LoadType::Stylesheet(url));
if let Some(any_failed) = owner.load_finished(successful) { if let Some(any_failed) = owner.load_finished(successful) {
let event = if any_failed { atom!("error") } else { atom!("load") }; let event = if any_failed { atom!("error") } else { atom!("load") };
@ -220,15 +205,16 @@ impl<'a> StylesheetLoader<'a> {
} }
impl<'a> StylesheetLoader<'a> { impl<'a> StylesheetLoader<'a> {
pub fn load(&self, source: StylesheetContextSource, cors_setting: Option<CorsSettings>, pub fn load(&self, source: StylesheetContextSource, url: ServoUrl,
cors_setting: Option<CorsSettings>,
integrity_metadata: String) { integrity_metadata: String) {
let url = source.url();
let document = document_from_node(self.elem); let document = document_from_node(self.elem);
let gen = self.elem.downcast::<HTMLLinkElement>() let gen = self.elem.downcast::<HTMLLinkElement>()
.map(HTMLLinkElement::get_request_generation_id); .map(HTMLLinkElement::get_request_generation_id);
let context = Arc::new(Mutex::new(StylesheetContext { let context = Arc::new(Mutex::new(StylesheetContext {
elem: Trusted::new(&*self.elem), elem: Trusted::new(&*self.elem),
source: source, source: source,
url: url.clone(),
metadata: None, metadata: None,
data: vec![], data: vec![],
document: Trusted::new(&*document), document: Trusted::new(&*document),
@ -285,9 +271,20 @@ impl<'a> StylesheetLoader<'a> {
} }
impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> { impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> {
fn request_stylesheet(&self, import: &Arc<RwLock<ImportRule>>) { fn request_stylesheet(
&self,
media: MediaList,
make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<StyleLocked<ImportRule>>,
) -> Arc<StyleLocked<ImportRule>> {
let import = make_import(media);
let url = import.url.url().expect("Invalid urls shouldn't enter the loader").clone();
//TODO (mrnayak) : Whether we should use the original loader's CORS setting? //TODO (mrnayak) : Whether we should use the original loader's CORS setting?
//Fix this when spec has more details. //Fix this when spec has more details.
self.load(StylesheetContextSource::Import(import.clone()), None, "".to_owned()) let source = StylesheetContextSource::Import(import.stylesheet.clone());
self.load(source, url, None, "".to_owned());
make_arc(import)
} }
} }

View file

@ -405,6 +405,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
let mut data = self.get_style_data().unwrap().borrow_mut(); let mut data = self.get_style_data().unwrap().borrow_mut();
let new_style = let new_style =
context.stylist.precomputed_values_for_pseudo( context.stylist.precomputed_values_for_pseudo(
&context.guards,
&style_pseudo, &style_pseudo,
Some(data.styles().primary.values()), Some(data.styles().primary.values()),
CascadeFlags::empty()); CascadeFlags::empty());
@ -421,6 +422,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug +
let new_style = let new_style =
context.stylist context.stylist
.lazily_compute_pseudo_element_style( .lazily_compute_pseudo_element_style(
&context.guards,
unsafe { &self.unsafe_get() }, unsafe { &self.unsafe_get() },
&style_pseudo, &style_pseudo,
data.styles().primary.values()); data.styles().primary.values());

View file

@ -13,7 +13,7 @@ path = "lib.rs"
doctest = false doctest = false
[features] [features]
gecko = ["nsstring_vendor", "rayon/unstable"] gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus"]
use_bindgen = ["bindgen", "regex"] use_bindgen = ["bindgen", "regex"]
servo = ["serde/unstable", "serde", "serde_derive", "heapsize_derive", servo = ["serde/unstable", "serde", "serde_derive", "heapsize_derive",
"style_traits/servo", "servo_atoms", "html5ever-atoms", "style_traits/servo", "servo_atoms", "html5ever-atoms",
@ -37,10 +37,10 @@ lazy_static = "0.2"
log = "0.3" log = "0.3"
matches = "0.1" matches = "0.1"
nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true} nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true}
num_cpus = {version = "1.1.0", optional = true}
num-integer = "0.1.32" num-integer = "0.1.32"
num-traits = "0.1.32" num-traits = "0.1.32"
ordered-float = "0.4" ordered-float = "0.4"
owning_ref = "0.2.2"
parking_lot = "0.3.3" parking_lot = "0.3.3"
pdqsort = "0.1.0" pdqsort = "0.1.0"
rayon = "0.6" rayon = "0.6"

View file

@ -415,7 +415,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
match step.value { match step.value {
KeyframesStepValue::ComputedValues => style_from_cascade.clone(), KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
KeyframesStepValue::Declarations { block: ref declarations } => { KeyframesStepValue::Declarations { block: ref declarations } => {
let guard = declarations.read(); let guard = declarations.read_with(context.guards.author);
// No !important in keyframes. // No !important in keyframes.
debug_assert!(guard.declarations().iter() debug_assert!(guard.declarations().iter()

View file

@ -11,9 +11,9 @@ use app_units::Au;
use cssparser::{self, Color, RGBA}; use cssparser::{self, Color, RGBA};
use euclid::num::Zero; use euclid::num::Zero;
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use parking_lot::RwLock;
use properties::PropertyDeclarationBlock; use properties::PropertyDeclarationBlock;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use shared_lock::Locked;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
@ -61,7 +61,7 @@ pub enum AttrValue {
/// declarationblock for longer than needed. /// declarationblock for longer than needed.
Declaration(String, Declaration(String,
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
Arc<RwLock<PropertyDeclarationBlock>>) Arc<Locked<PropertyDeclarationBlock>>)
} }
/// Shared implementation to parse an integer according to /// Shared implementation to parse an integer according to

View file

@ -17,6 +17,7 @@ use parking_lot::RwLock;
use selector_parser::PseudoElement; use selector_parser::PseudoElement;
use selectors::matching::ElementSelectorFlags; use selectors::matching::ElementSelectorFlags;
use servo_config::opts; use servo_config::opts;
use shared_lock::StylesheetGuards;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::fmt; use std::fmt;
@ -61,10 +62,13 @@ pub enum QuirksMode {
/// ///
/// There's exactly one of these during a given restyle traversal, and it's /// There's exactly one of these during a given restyle traversal, and it's
/// shared among the worker threads. /// shared among the worker threads.
pub struct SharedStyleContext { pub struct SharedStyleContext<'a> {
/// The CSS selector stylist. /// The CSS selector stylist.
pub stylist: Arc<Stylist>, pub stylist: Arc<Stylist>,
/// Guards for pre-acquired locks
pub guards: StylesheetGuards<'a>,
/// The animations that are currently running. /// The animations that are currently running.
pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>, pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
@ -85,7 +89,7 @@ pub struct SharedStyleContext {
pub quirks_mode: QuirksMode, pub quirks_mode: QuirksMode,
} }
impl SharedStyleContext { impl<'a> SharedStyleContext<'a> {
/// Return a suitable viewport size in order to be used for viewport units. /// Return a suitable viewport size in order to be used for viewport units.
pub fn viewport_size(&self) -> Size2D<Au> { pub fn viewport_size(&self) -> Size2D<Au> {
self.stylist.device.au_viewport_size() self.stylist.device.au_viewport_size()
@ -306,7 +310,7 @@ impl<E: TElement> Drop for ThreadLocalStyleContext<E> {
/// shared style context, and a mutable reference to a local one. /// shared style context, and a mutable reference to a local one.
pub struct StyleContext<'a, E: TElement + 'a> { pub struct StyleContext<'a, E: TElement + 'a> {
/// The shared style context reference. /// The shared style context reference.
pub shared: &'a SharedStyleContext, pub shared: &'a SharedStyleContext<'a>,
/// The thread-local style context (mutable) reference. /// The thread-local style context (mutable) reference.
pub thread_local: &'a mut ThreadLocalStyleContext<E>, pub thread_local: &'a mut ThreadLocalStyleContext<E>,
} }

View file

@ -11,10 +11,10 @@ use {Atom, Namespace, LocalName};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use data::ElementData; use data::ElementData;
use element_state::ElementState; use element_state::ElementState;
use parking_lot::RwLock;
use properties::{ComputedValues, PropertyDeclarationBlock}; use properties::{ComputedValues, PropertyDeclarationBlock};
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement}; use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
use selectors::matching::ElementSelectorFlags; use selectors::matching::ElementSelectorFlags;
use shared_lock::Locked;
use sink::Push; use sink::Push;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
@ -230,8 +230,8 @@ pub trait PresentationalHintsSynthetizer {
/// The animation rules. The first one is for Animation cascade level, and the second one is for /// The animation rules. The first one is for Animation cascade level, and the second one is for
/// Transition cascade level. /// Transition cascade level.
pub struct AnimationRules(pub Option<Arc<RwLock<PropertyDeclarationBlock>>>, pub struct AnimationRules(pub Option<Arc<Locked<PropertyDeclarationBlock>>>,
pub Option<Arc<RwLock<PropertyDeclarationBlock>>>); pub Option<Arc<Locked<PropertyDeclarationBlock>>>);
/// The element trait, the main abstraction the style crate acts over. /// The element trait, the main abstraction the style crate acts over.
pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer { pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
@ -252,7 +252,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
} }
/// Get this element's style attribute. /// Get this element's style attribute.
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>; fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>>;
/// Get this element's animation rules. /// Get this element's animation rules.
fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules { fn get_animation_rules(&self, _pseudo: Option<&PseudoElement>) -> AnimationRules {
@ -261,13 +261,13 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
/// Get this element's animation rule. /// Get this element's animation rule.
fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>) fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> { -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
None None
} }
/// Get this element's transition rule. /// Get this element's transition rule.
fn get_transition_rule(&self, _pseudo: Option<&PseudoElement>) fn get_transition_rule(&self, _pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> { -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
None None
} }

View file

@ -12,6 +12,7 @@ use media_queries::MediaList;
use parser::ParserContextExtraData; use parser::ParserContextExtraData;
use self::encoding::{EncodingRef, DecoderTrap}; use self::encoding::{EncodingRef, DecoderTrap};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use shared_lock::SharedRwLock;
use std::str; use std::str;
use stylesheets::{Stylesheet, StylesheetLoader, Origin}; use stylesheets::{Stylesheet, StylesheetLoader, Origin};
@ -54,6 +55,7 @@ impl Stylesheet {
environment_encoding: Option<EncodingRef>, environment_encoding: Option<EncodingRef>,
origin: Origin, origin: Origin,
media: MediaList, media: MediaList,
shared_lock: SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter, error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) extra_data: ParserContextExtraData)
@ -64,6 +66,7 @@ impl Stylesheet {
base_url, base_url,
origin, origin,
media, media,
shared_lock,
stylesheet_loader, stylesheet_loader,
error_reporter, error_reporter,
extra_data) extra_data)

View file

@ -14,6 +14,7 @@ use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
#[cfg(feature = "gecko")] use cssparser::UnicodeRange; #[cfg(feature = "gecko")] use cssparser::UnicodeRange;
use parser::{ParserContext, log_css_error, Parse}; use parser::{ParserContext, log_css_error, Parse};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt; use std::fmt;
use std::iter; use std::iter;
use style_traits::{ToCss, OneOrMoreCommaSeparated}; use style_traits::{ToCss, OneOrMoreCommaSeparated};
@ -230,11 +231,10 @@ macro_rules! font_face_descriptors {
} }
} }
impl ToCss for FontFaceRule { impl ToCssWithGuard for FontFaceRule {
// Serialization of FontFaceRule is not specced. // Serialization of FontFaceRule is not specced.
fn to_css<W>(&self, dest: &mut W) -> fmt::Result fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write, where W: fmt::Write {
{
dest.write_str("@font-face {\n")?; dest.write_str("@font-face {\n")?;
$( $(
dest.write_str(concat!(" ", $m_name, ": "))?; dest.write_str(concat!(" ", $m_name, ": "))?;

View file

@ -17,6 +17,7 @@ use media_queries::MediaList;
use parking_lot::RwLock; use parking_lot::RwLock;
use properties::{ComputedValues, PropertyDeclarationBlock}; use properties::{ComputedValues, PropertyDeclarationBlock};
use properties::animated_properties::{AnimationValue, AnimationValueMap}; use properties::animated_properties::{AnimationValue, AnimationValueMap};
use shared_lock::Locked;
use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, MediaRule, NamespaceRule}; use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, MediaRule, NamespaceRule};
macro_rules! impl_arc_ffi { macro_rules! impl_arc_ffi {
@ -38,7 +39,7 @@ macro_rules! impl_arc_ffi {
} }
} }
impl_arc_ffi!(RwLock<CssRules> => ServoCssRules impl_arc_ffi!(Locked<CssRules> => ServoCssRules
[Servo_CssRules_AddRef, Servo_CssRules_Release]); [Servo_CssRules_AddRef, Servo_CssRules_Release]);
impl_arc_ffi!(Stylesheet => RawServoStyleSheet impl_arc_ffi!(Stylesheet => RawServoStyleSheet
@ -47,13 +48,13 @@ impl_arc_ffi!(Stylesheet => RawServoStyleSheet
impl_arc_ffi!(ComputedValues => ServoComputedValues impl_arc_ffi!(ComputedValues => ServoComputedValues
[Servo_ComputedValues_AddRef, Servo_ComputedValues_Release]); [Servo_ComputedValues_AddRef, Servo_ComputedValues_Release]);
impl_arc_ffi!(RwLock<PropertyDeclarationBlock> => RawServoDeclarationBlock impl_arc_ffi!(Locked<PropertyDeclarationBlock> => RawServoDeclarationBlock
[Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]); [Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]);
impl_arc_ffi!(RwLock<StyleRule> => RawServoStyleRule impl_arc_ffi!(Locked<StyleRule> => RawServoStyleRule
[Servo_StyleRule_AddRef, Servo_StyleRule_Release]); [Servo_StyleRule_AddRef, Servo_StyleRule_Release]);
impl_arc_ffi!(RwLock<ImportRule> => RawServoImportRule impl_arc_ffi!(Locked<ImportRule> => RawServoImportRule
[Servo_ImportRule_AddRef, Servo_ImportRule_Release]); [Servo_ImportRule_AddRef, Servo_ImportRule_Release]);
impl_arc_ffi!(AnimationValue => RawServoAnimationValue impl_arc_ffi!(AnimationValue => RawServoAnimationValue
@ -62,11 +63,11 @@ impl_arc_ffi!(AnimationValue => RawServoAnimationValue
impl_arc_ffi!(RwLock<AnimationValueMap> => RawServoAnimationValueMap impl_arc_ffi!(RwLock<AnimationValueMap> => RawServoAnimationValueMap
[Servo_AnimationValueMap_AddRef, Servo_AnimationValueMap_Release]); [Servo_AnimationValueMap_AddRef, Servo_AnimationValueMap_Release]);
impl_arc_ffi!(RwLock<MediaList> => RawServoMediaList impl_arc_ffi!(Locked<MediaList> => RawServoMediaList
[Servo_MediaList_AddRef, Servo_MediaList_Release]); [Servo_MediaList_AddRef, Servo_MediaList_Release]);
impl_arc_ffi!(RwLock<MediaRule> => RawServoMediaRule impl_arc_ffi!(Locked<MediaRule> => RawServoMediaRule
[Servo_MediaRule_AddRef, Servo_MediaRule_Release]); [Servo_MediaRule_AddRef, Servo_MediaRule_Release]);
impl_arc_ffi!(RwLock<NamespaceRule> => RawServoNamespaceRule impl_arc_ffi!(Locked<NamespaceRule> => RawServoNamespaceRule
[Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release]); [Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release]);

View file

@ -13,6 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use media_queries::Device; use media_queries::Device;
use parking_lot::RwLock; use parking_lot::RwLock;
use properties::ComputedValues; use properties::ComputedValues;
use shared_lock::{StylesheetGuards, SharedRwLockReadGuard};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel}; use std::sync::mpsc::{Receiver, Sender, channel};
@ -83,20 +84,20 @@ impl PerDocumentStyleDataImpl {
/// Reset the device state because it may have changed. /// Reset the device state because it may have changed.
/// ///
/// Implies also a stylesheet flush. /// Implies also a stylesheet flush.
pub fn reset_device(&mut self) { pub fn reset_device(&mut self, guard: &SharedRwLockReadGuard) {
{ {
let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); let mut stylist = Arc::get_mut(&mut self.stylist).unwrap();
Arc::get_mut(&mut stylist.device).unwrap().reset(); Arc::get_mut(&mut stylist.device).unwrap().reset();
} }
self.stylesheets_changed = true; self.stylesheets_changed = true;
self.flush_stylesheets(); self.flush_stylesheets(guard);
} }
/// Recreate the style data if the stylesheets have changed. /// Recreate the style data if the stylesheets have changed.
pub fn flush_stylesheets(&mut self) { pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) {
if self.stylesheets_changed { if self.stylesheets_changed {
let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); let mut stylist = Arc::get_mut(&mut self.stylist).unwrap();
stylist.update(&self.stylesheets, None, true); stylist.update(&self.stylesheets, &StylesheetGuards::same(guard), None, true);
self.stylesheets_changed = false; self.stylesheets_changed = false;
} }
} }

View file

@ -0,0 +1,50 @@
/* 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/. */
//! Global style data
use num_cpus;
use rayon;
use shared_lock::SharedRwLock;
use std::cmp;
use std::env;
/// Global style data
pub struct GlobalStyleData {
/// How many threads parallel styling can use.
pub num_threads: usize,
/// The parallel styling thread pool.
pub style_thread_pool: Option<rayon::ThreadPool>,
/// Shared RWLock for CSSOM objects
pub shared_lock: SharedRwLock,
}
lazy_static! {
/// Global style data
pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
let stylo_threads = env::var("STYLO_THREADS")
.map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
let num_threads = match stylo_threads {
Ok(num) => num,
_ => cmp::max(num_cpus::get() * 3 / 4, 1),
};
let pool = if num_threads <= 1 {
None
} else {
let configuration =
rayon::Configuration::new().set_num_threads(num_threads);
let pool = rayon::ThreadPool::new(configuration).ok();
pool
};
GlobalStyleData {
num_threads: num_threads,
style_thread_pool: pool,
shared_lock: SharedRwLock::new(),
}
};
}

View file

@ -10,6 +10,7 @@ mod non_ts_pseudo_class_list;
pub mod arc_types; pub mod arc_types;
pub mod conversions; pub mod conversions;
pub mod data; pub mod data;
pub mod global_style_data;
pub mod media_queries; pub mod media_queries;
pub mod restyle_damage; pub mod restyle_damage;
pub mod selector_parser; pub mod selector_parser;

View file

@ -13,14 +13,14 @@ use traversal::{DomTraversal, PerLevelTraversalData, TraversalDriver, recalc_sty
/// This is the simple struct that Gecko uses to encapsulate a DOM traversal for /// This is the simple struct that Gecko uses to encapsulate a DOM traversal for
/// styling. /// styling.
pub struct RecalcStyleOnly { pub struct RecalcStyleOnly<'a> {
shared: SharedStyleContext, shared: SharedStyleContext<'a>,
driver: TraversalDriver, driver: TraversalDriver,
} }
impl RecalcStyleOnly { impl<'a> RecalcStyleOnly<'a> {
/// Create a `RecalcStyleOnly` traversal from a `SharedStyleContext`. /// Create a `RecalcStyleOnly` traversal from a `SharedStyleContext`.
pub fn new(shared: SharedStyleContext, driver: TraversalDriver) -> Self { pub fn new(shared: SharedStyleContext<'a>, driver: TraversalDriver) -> Self {
RecalcStyleOnly { RecalcStyleOnly {
shared: shared, shared: shared,
driver: driver, driver: driver,
@ -28,10 +28,11 @@ impl RecalcStyleOnly {
} }
} }
impl<'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly { impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> {
type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>; type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>;
fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData, fn process_preorder(&self,
traversal_data: &mut PerLevelTraversalData,
thread_local: &mut Self::ThreadLocalContext, thread_local: &mut Self::ThreadLocalContext,
node: GeckoNode<'le>) node: GeckoNode<'le>)
{ {

View file

@ -20,6 +20,7 @@ use dom::{AnimationRules, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}
use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use dom::{OpaqueNode, PresentationalHintsSynthetizer};
use element_state::ElementState; use element_state::ElementState;
use error_reporting::StdoutErrorReporter; use error_reporting::StdoutErrorReporter;
use gecko::global_style_data::GLOBAL_STYLE_DATA;
use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement}; use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
use gecko::snapshot_helpers; use gecko::snapshot_helpers;
use gecko_bindings::bindings; use gecko_bindings::bindings;
@ -53,6 +54,7 @@ use selectors::Element;
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
use selectors::parser::{AttrSelector, NamespaceConstraint}; use selectors::parser::{AttrSelector, NamespaceConstraint};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use shared_lock::Locked;
use sink::Push; use sink::Push;
use std::fmt; use std::fmt;
use std::ptr; use std::ptr;
@ -407,12 +409,14 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
fn get_animation_rule(element: &GeckoElement, fn get_animation_rule(element: &GeckoElement,
pseudo: Option<&PseudoElement>, pseudo: Option<&PseudoElement>,
cascade_level: CascadeLevel) cascade_level: CascadeLevel)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> { -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo); let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
let animation_values = Arc::new(RwLock::new(AnimationValueMap::new())); let animation_values = Arc::new(RwLock::new(AnimationValueMap::new()));
if unsafe { Gecko_GetAnimationRule(element.0, atom_ptr, cascade_level, if unsafe { Gecko_GetAnimationRule(element.0, atom_ptr, cascade_level,
HasArcFFI::arc_as_borrowed(&animation_values)) } { HasArcFFI::arc_as_borrowed(&animation_values)) } {
Some(Arc::new(RwLock::new(PropertyDeclarationBlock::from_animation_value_map(&animation_values.read())))) let shared_lock = &GLOBAL_STYLE_DATA.shared_lock;
Some(Arc::new(shared_lock.wrap(
PropertyDeclarationBlock::from_animation_value_map(&animation_values.read()))))
} else { } else {
None None
} }
@ -425,7 +429,7 @@ impl<'le> TElement for GeckoElement<'le> {
unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) } unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) }
} }
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>> { fn style_attribute(&self) -> Option<&Arc<Locked<PropertyDeclarationBlock>>> {
let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) }; let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) };
declarations.map(|s| s.as_arc_opt()).unwrap_or(None) declarations.map(|s| s.as_arc_opt()).unwrap_or(None)
} }
@ -436,12 +440,12 @@ impl<'le> TElement for GeckoElement<'le> {
} }
fn get_animation_rule(&self, pseudo: Option<&PseudoElement>) fn get_animation_rule(&self, pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> { -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
get_animation_rule(self, pseudo, CascadeLevel::Animations) get_animation_rule(self, pseudo, CascadeLevel::Animations)
} }
fn get_transition_rule(&self, pseudo: Option<&PseudoElement>) fn get_transition_rule(&self, pseudo: Option<&PseudoElement>)
-> Option<Arc<RwLock<PropertyDeclarationBlock>>> { -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
get_animation_rule(self, pseudo, CascadeLevel::Transitions) get_animation_rule(self, pseudo, CascadeLevel::Transitions)
} }

View file

@ -8,13 +8,13 @@
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser}; use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule}; use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock;
use parser::{ParserContext, ParserContextExtraData, log_css_error}; use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, LonghandId, ParsedDeclaration}; use properties::{PropertyDeclarationId, LonghandId, ParsedDeclaration};
use properties::LonghandIdSet; use properties::LonghandIdSet;
use properties::animated_properties::TransitionProperty; use properties::animated_properties::TransitionProperty;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use shared_lock::{SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard};
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use style_traits::ToCss; use style_traits::ToCss;
@ -101,11 +101,12 @@ pub struct Keyframe {
/// ///
/// Note that `!important` rules in keyframes don't apply, but we keep this /// Note that `!important` rules in keyframes don't apply, but we keep this
/// `Arc` just for convenience. /// `Arc` just for convenience.
pub block: Arc<RwLock<PropertyDeclarationBlock>>, pub block: Arc<Locked<PropertyDeclarationBlock>>,
} }
impl ToCss for Keyframe { impl ToCssWithGuard for Keyframe {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
let mut iter = self.selector.percentages().iter(); let mut iter = self.selector.percentages().iter();
try!(iter.next().unwrap().to_css(dest)); try!(iter.next().unwrap().to_css(dest));
for percentage in iter { for percentage in iter {
@ -113,7 +114,7 @@ impl ToCss for Keyframe {
try!(percentage.to_css(dest)); try!(percentage.to_css(dest));
} }
try!(dest.write_str(" { ")); try!(dest.write_str(" { "));
try!(self.block.read().to_css(dest)); try!(self.block.read_with(guard).to_css(dest));
try!(dest.write_str(" }")); try!(dest.write_str(" }"));
Ok(()) Ok(())
} }
@ -125,7 +126,7 @@ impl Keyframe {
pub fn parse(css: &str, pub fn parse(css: &str,
parent_stylesheet: &Stylesheet, parent_stylesheet: &Stylesheet,
extra_data: ParserContextExtraData) extra_data: ParserContextExtraData)
-> Result<Arc<RwLock<Self>>, ()> { -> Result<Arc<Locked<Self>>, ()> {
let error_reporter = MemoryHoleReporter; let error_reporter = MemoryHoleReporter;
let context = ParserContext::new_with_extra_data(parent_stylesheet.origin, let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
&parent_stylesheet.base_url, &parent_stylesheet.base_url,
@ -135,6 +136,7 @@ impl Keyframe {
let mut rule_parser = KeyframeListParser { let mut rule_parser = KeyframeListParser {
context: &context, context: &context,
shared_lock: &parent_stylesheet.shared_lock,
}; };
parse_one_rule(&mut input, &mut rule_parser) parse_one_rule(&mut input, &mut rule_parser)
} }
@ -152,7 +154,7 @@ pub enum KeyframesStepValue {
Declarations { Declarations {
/// The declaration block per se. /// The declaration block per se.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
block: Arc<RwLock<PropertyDeclarationBlock>> block: Arc<Locked<PropertyDeclarationBlock>>
}, },
/// A synthetic step computed from the current computed values at the time /// A synthetic step computed from the current computed values at the time
/// of the animation. /// of the animation.
@ -178,10 +180,11 @@ pub struct KeyframesStep {
impl KeyframesStep { impl KeyframesStep {
#[inline] #[inline]
fn new(percentage: KeyframePercentage, fn new(percentage: KeyframePercentage,
value: KeyframesStepValue) -> Self { value: KeyframesStepValue,
guard: &SharedRwLockReadGuard) -> Self {
let declared_timing_function = match value { let declared_timing_function = match value {
KeyframesStepValue::Declarations { ref block } => { KeyframesStepValue::Declarations { ref block } => {
block.read().declarations().iter().any(|&(ref prop_decl, _)| { block.read_with(guard).declarations().iter().any(|&(ref prop_decl, _)| {
match *prop_decl { match *prop_decl {
PropertyDeclaration::AnimationTimingFunction(..) => true, PropertyDeclaration::AnimationTimingFunction(..) => true,
_ => false, _ => false,
@ -199,13 +202,14 @@ impl KeyframesStep {
} }
/// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'. /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'.
pub fn get_animation_timing_function(&self) -> Option<SpecifiedTimingFunction> { pub fn get_animation_timing_function(&self, guard: &SharedRwLockReadGuard)
-> Option<SpecifiedTimingFunction> {
if !self.declared_timing_function { if !self.declared_timing_function {
return None; return None;
} }
match self.value { match self.value {
KeyframesStepValue::Declarations { ref block } => { KeyframesStepValue::Declarations { ref block } => {
let guard = block.read(); let guard = block.read_with(guard);
let &(ref declaration, _) = let &(ref declaration, _) =
guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap(); guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap();
match *declaration { match *declaration {
@ -239,14 +243,16 @@ pub struct KeyframesAnimation {
} }
/// Get all the animated properties in a keyframes animation. /// Get all the animated properties in a keyframes animation.
fn get_animated_properties(keyframes: &[Arc<RwLock<Keyframe>>]) -> Vec<TransitionProperty> { fn get_animated_properties(keyframes: &[Arc<Locked<Keyframe>>], guard: &SharedRwLockReadGuard)
-> Vec<TransitionProperty> {
let mut ret = vec![]; let mut ret = vec![];
let mut seen = LonghandIdSet::new(); let mut seen = LonghandIdSet::new();
// NB: declarations are already deduplicated, so we don't have to check for // NB: declarations are already deduplicated, so we don't have to check for
// it here. // it here.
for keyframe in keyframes { for keyframe in keyframes {
let keyframe = keyframe.read(); let keyframe = keyframe.read_with(&guard);
for &(ref declaration, importance) in keyframe.block.read().declarations().iter() { let block = keyframe.block.read_with(guard);
for &(ref declaration, importance) in block.declarations().iter() {
assert!(!importance.important()); assert!(!importance.important());
if let Some(property) = TransitionProperty::from_declaration(declaration) { if let Some(property) = TransitionProperty::from_declaration(declaration) {
@ -270,7 +276,8 @@ impl KeyframesAnimation {
/// ///
/// Otherwise, this will compute and sort the steps used for the animation, /// Otherwise, this will compute and sort the steps used for the animation,
/// and return the animation object. /// and return the animation object.
pub fn from_keyframes(keyframes: &[Arc<RwLock<Keyframe>>]) -> Self { pub fn from_keyframes(keyframes: &[Arc<Locked<Keyframe>>], guard: &SharedRwLockReadGuard)
-> Self {
let mut result = KeyframesAnimation { let mut result = KeyframesAnimation {
steps: vec![], steps: vec![],
properties_changed: vec![], properties_changed: vec![],
@ -280,17 +287,17 @@ impl KeyframesAnimation {
return result; return result;
} }
result.properties_changed = get_animated_properties(keyframes); result.properties_changed = get_animated_properties(keyframes, guard);
if result.properties_changed.is_empty() { if result.properties_changed.is_empty() {
return result; return result;
} }
for keyframe in keyframes { for keyframe in keyframes {
let keyframe = keyframe.read(); let keyframe = keyframe.read_with(&guard);
for percentage in keyframe.selector.0.iter() { for percentage in keyframe.selector.0.iter() {
result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations { result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations {
block: keyframe.block.clone(), block: keyframe.block.clone(),
})); }, guard));
} }
} }
@ -300,12 +307,14 @@ impl KeyframesAnimation {
// Prepend autogenerated keyframes if appropriate. // Prepend autogenerated keyframes if appropriate.
if result.steps[0].start_percentage.0 != 0. { if result.steps[0].start_percentage.0 != 0. {
result.steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.), result.steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.),
KeyframesStepValue::ComputedValues)); KeyframesStepValue::ComputedValues,
guard));
} }
if result.steps.last().unwrap().start_percentage.0 != 1. { if result.steps.last().unwrap().start_percentage.0 != 1. {
result.steps.push(KeyframesStep::new(KeyframePercentage::new(1.), result.steps.push(KeyframesStep::new(KeyframePercentage::new(1.),
KeyframesStepValue::ComputedValues)); KeyframesStepValue::ComputedValues,
guard));
} }
result result
@ -322,24 +331,27 @@ impl KeyframesAnimation {
/// } /// }
struct KeyframeListParser<'a> { struct KeyframeListParser<'a> {
context: &'a ParserContext<'a>, context: &'a ParserContext<'a>,
shared_lock: &'a SharedRwLock,
} }
/// Parses a keyframe list from CSS input. /// Parses a keyframe list from CSS input.
pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec<Arc<RwLock<Keyframe>>> { pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser, shared_lock: &SharedRwLock)
RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context }) -> Vec<Arc<Locked<Keyframe>>> {
.filter_map(Result::ok) RuleListParser::new_for_nested_rule(input, KeyframeListParser {
.collect() context: context,
shared_lock: shared_lock,
}).filter_map(Result::ok).collect()
} }
enum Void {} enum Void {}
impl<'a> AtRuleParser for KeyframeListParser<'a> { impl<'a> AtRuleParser for KeyframeListParser<'a> {
type Prelude = Void; type Prelude = Void;
type AtRule = Arc<RwLock<Keyframe>>; type AtRule = Arc<Locked<Keyframe>>;
} }
impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
type Prelude = KeyframeSelector; type Prelude = KeyframeSelector;
type QualifiedRule = Arc<RwLock<Keyframe>>; type QualifiedRule = Arc<Locked<Keyframe>>;
fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> { fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
let start = input.position(); let start = input.position();
@ -372,9 +384,9 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
} }
// `parse_important` is not called here, `!important` is not allowed in keyframe blocks. // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
} }
Ok(Arc::new(RwLock::new(Keyframe { Ok(Arc::new(self.shared_lock.wrap(Keyframe {
selector: prelude, selector: prelude,
block: Arc::new(RwLock::new(block)), block: Arc::new(self.shared_lock.wrap(block)),
}))) })))
} }
} }

View file

@ -57,10 +57,10 @@ extern crate log;
#[macro_use] #[macro_use]
extern crate matches; extern crate matches;
#[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring; #[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring;
#[cfg(feature = "gecko")] extern crate num_cpus;
extern crate num_integer; extern crate num_integer;
extern crate num_traits; extern crate num_traits;
extern crate ordered_float; extern crate ordered_float;
extern crate owning_ref;
extern crate parking_lot; extern crate parking_lot;
extern crate pdqsort; extern crate pdqsort;
extern crate rayon; extern crate rayon;
@ -99,13 +99,13 @@ pub mod keyframes;
pub mod logical_geometry; pub mod logical_geometry;
pub mod matching; pub mod matching;
pub mod media_queries; pub mod media_queries;
pub mod owning_handle;
pub mod parallel; pub mod parallel;
pub mod parser; pub mod parser;
pub mod restyle_hints; pub mod restyle_hints;
pub mod rule_tree; pub mod rule_tree;
pub mod scoped_tls; pub mod scoped_tls;
pub mod selector_parser; pub mod selector_parser;
pub mod shared_lock;
pub mod stylist; pub mod stylist;
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo; #[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
pub mod sequential; pub mod sequential;
@ -168,6 +168,8 @@ macro_rules! reexport_computed_values {
longhand_properties_idents!(reexport_computed_values); longhand_properties_idents!(reexport_computed_values);
/// Returns whether the two arguments point to the same value. /// Returns whether the two arguments point to the same value.
///
/// FIXME: Remove this and use Arc::ptr_eq once we require Rust 1.17
#[inline] #[inline]
pub fn arc_ptr_eq<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool { pub fn arc_ptr_eq<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool {
let a: &T = &**a; let a: &T = &**a;

View file

@ -541,6 +541,7 @@ trait PrivateMatchMethods: TElement {
let values = let values =
Arc::new(cascade(&shared_context.stylist.device, Arc::new(cascade(&shared_context.stylist.device,
rule_node, rule_node,
&shared_context.guards,
inherited_values, inherited_values,
layout_parent_style, layout_parent_style,
Some(&mut cascade_info), Some(&mut cascade_info),
@ -784,6 +785,7 @@ pub trait MatchMethods : TElement {
style_attribute, style_attribute,
animation_rules, animation_rules,
None, None,
&context.shared.guards,
&mut applicable_declarations, &mut applicable_declarations,
&mut flags); &mut flags);
let primary_rule_node = compute_rule_node(context, &mut applicable_declarations); let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
@ -809,6 +811,7 @@ pub trait MatchMethods : TElement {
Some(context.thread_local.bloom_filter.filter()), Some(context.thread_local.bloom_filter.filter()),
None, pseudo_animation_rules, None, pseudo_animation_rules,
Some(&pseudo), Some(&pseudo),
&context.shared.guards,
&mut applicable_declarations, &mut applicable_declarations,
&mut flags); &mut flags);
@ -883,7 +886,8 @@ pub trait MatchMethods : TElement {
let new_node = context.shared.stylist.rule_tree let new_node = context.shared.stylist.rule_tree
.update_rule_at_level(CascadeLevel::StyleAttributeNormal, .update_rule_at_level(CascadeLevel::StyleAttributeNormal,
style_attribute, style_attribute,
primary_rules); primary_rules,
&context.shared.guards);
if let Some(n) = new_node { if let Some(n) = new_node {
*primary_rules = n; *primary_rules = n;
rule_node_changed = true; rule_node_changed = true;
@ -892,7 +896,8 @@ pub trait MatchMethods : TElement {
let new_node = context.shared.stylist.rule_tree let new_node = context.shared.stylist.rule_tree
.update_rule_at_level(CascadeLevel::StyleAttributeImportant, .update_rule_at_level(CascadeLevel::StyleAttributeImportant,
style_attribute, style_attribute,
primary_rules); primary_rules,
&context.shared.guards);
if let Some(n) = new_node { if let Some(n) = new_node {
*primary_rules = n; *primary_rules = n;
rule_node_changed = true; rule_node_changed = true;

View file

@ -1,89 +0,0 @@
/* 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/. */
#![allow(unsafe_code)]
#![deny(missing_docs)]
//! A handle that encapsulate a reference to a given data along with its owner.
use owning_ref::StableAddress;
use std::ops::{Deref, DerefMut};
/// `OwningHandle` is a complement to `OwningRef`. Where `OwningRef` allows
/// consumers to pass around an owned object and a dependent reference,
/// `OwningHandle` contains an owned object and a dependent _object_.
///
/// `OwningHandle` can encapsulate a `RefMut` along with its associated
/// `RefCell`, or an `RwLockReadGuard` along with its associated `RwLock`.
/// However, the API is completely generic and there are no restrictions on
/// what types of owning and dependent objects may be used.
///
/// `OwningHandle` is created by passing an owner object (which dereferences
/// to a stable address) along with a callback which receives a pointer to
/// that stable location. The callback may then dereference the pointer and
/// mint a dependent object, with the guarantee that the returned object will
/// not outlive the referent of the pointer.
///
/// This does foist some unsafety onto the callback, which needs an `unsafe`
/// block to dereference the pointer. It would be almost good enough for
/// OwningHandle to pass a transmuted &'static reference to the callback
/// since the lifetime is infinite as far as the minted handle is concerned.
/// However, even an `Fn` callback can still allow the reference to escape
/// via a `StaticMutex` or similar, which technically violates the safety
/// contract. Some sort of language support in the lifetime system could
/// make this API a bit nicer.
pub struct OwningHandle<O, H>
where O: StableAddress,
H: Deref,
{
handle: H,
_owner: O,
}
impl<O, H> Deref for OwningHandle<O, H>
where O: StableAddress,
H: Deref,
{
type Target = H::Target;
fn deref(&self) -> &H::Target {
self.handle.deref()
}
}
unsafe impl<O, H> StableAddress for OwningHandle<O, H>
where O: StableAddress,
H: StableAddress,
{}
impl<O, H> DerefMut for OwningHandle<O, H>
where O: StableAddress,
H: DerefMut,
{
fn deref_mut(&mut self) -> &mut H::Target {
self.handle.deref_mut()
}
}
impl<O, H> OwningHandle<O, H>
where O: StableAddress,
H: Deref,
{
/// Create a new OwningHandle. The provided callback will be invoked with
/// a pointer to the object owned by `o`, and the returned value is stored
/// as the object to which this `OwningHandle` will forward `Deref` and
/// `DerefMut`.
pub fn new<F>(o: O, f: F) -> Self
where F: Fn(*const O::Target) -> H,
{
let h: H;
{
h = f(o.deref() as *const O::Target);
}
OwningHandle {
handle: h,
_owner: o,
}
}
}

View file

@ -31,6 +31,7 @@ use parser::{Parse, ParserContext, ParserContextExtraData};
use properties::animated_properties::TransitionProperty; use properties::animated_properties::TransitionProperty;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS; #[cfg(feature = "servo")] use servo_config::prefs::PREFS;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use shared_lock::StylesheetGuards;
use style_traits::ToCss; use style_traits::ToCss;
use stylesheets::Origin; use stylesheets::Origin;
#[cfg(feature = "servo")] use values::Either; #[cfg(feature = "servo")] use values::Either;
@ -1860,6 +1861,7 @@ bitflags! {
/// ///
pub fn cascade(device: &Device, pub fn cascade(device: &Device,
rule_node: &StrongRuleNode, rule_node: &StrongRuleNode,
guards: &StylesheetGuards,
parent_style: Option<<&ComputedValues>, parent_style: Option<<&ComputedValues>,
layout_parent_style: Option<<&ComputedValues>, layout_parent_style: Option<<&ComputedValues>,
cascade_info: Option<<&mut CascadeInfo>, cascade_info: Option<<&mut CascadeInfo>,
@ -1882,11 +1884,12 @@ pub fn cascade(device: &Device,
// Hold locks until after the apply_declarations() call returns. // Hold locks until after the apply_declarations() call returns.
// Use filter_map because the root node has no style source. // Use filter_map because the root node has no style source.
let lock_guards = rule_node.self_and_ancestors().filter_map(|node| { let declaration_blocks = rule_node.self_and_ancestors().filter_map(|node| {
node.style_source().map(|source| (source.read(), node.importance())) let guard = node.cascade_level().guard(guards);
node.style_source().map(|source| (source.read(guard), node.importance()))
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
let iter_declarations = || { let iter_declarations = || {
lock_guards.iter().flat_map(|&(ref source, source_importance)| { declaration_blocks.iter().flat_map(|&(ref source, source_importance)| {
source.declarations().iter() source.declarations().iter()
// Yield declarations later in source order (with more precedence) first. // Yield declarations later in source order (with more precedence) first.
.rev() .rev()

View file

@ -10,9 +10,8 @@
use arc_ptr_eq; use arc_ptr_eq;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use owning_handle::OwningHandle;
use parking_lot::{RwLock, RwLockReadGuard};
use properties::{Importance, PropertyDeclarationBlock}; use properties::{Importance, PropertyDeclarationBlock};
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use std::io::{self, Write}; use std::io::{self, Write};
use std::ptr; use std::ptr;
use std::sync::Arc; use std::sync::Arc;
@ -52,33 +51,9 @@ pub struct RuleTree {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum StyleSource { pub enum StyleSource {
/// A style rule stable pointer. /// A style rule stable pointer.
Style(Arc<RwLock<StyleRule>>), Style(Arc<Locked<StyleRule>>),
/// A declaration block stable pointer. /// A declaration block stable pointer.
Declarations(Arc<RwLock<PropertyDeclarationBlock>>), Declarations(Arc<Locked<PropertyDeclarationBlock>>),
}
type StyleSourceGuardHandle<'a> =
OwningHandle<
RwLockReadGuard<'a, StyleRule>,
RwLockReadGuard<'a, PropertyDeclarationBlock>>;
/// A guard for a given style source.
pub enum StyleSourceGuard<'a> {
/// A guard for a style rule.
Style(StyleSourceGuardHandle<'a>),
/// A guard for a declaration block.
Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>),
}
impl<'a> ::std::ops::Deref for StyleSourceGuard<'a> {
type Target = PropertyDeclarationBlock;
fn deref(&self) -> &Self::Target {
match *self {
StyleSourceGuard::Declarations(ref block) => &*block,
StyleSourceGuard::Style(ref handle) => &*handle,
}
}
} }
impl StyleSource { impl StyleSource {
@ -92,28 +67,26 @@ impl StyleSource {
} }
} }
fn dump<W: Write>(&self, writer: &mut W) { fn dump<W: Write>(&self, guard: &SharedRwLockReadGuard, writer: &mut W) {
use self::StyleSource::*; use self::StyleSource::*;
if let Style(ref rule) = *self { if let Style(ref rule) = *self {
let _ = write!(writer, "{:?}", rule.read().selectors); let rule = rule.read_with(guard);
let _ = write!(writer, "{:?}", rule.selectors);
} }
let _ = write!(writer, " -> {:?}", self.read().declarations()); let _ = write!(writer, " -> {:?}", self.read(guard).declarations());
} }
/// Read the style source guard, and obtain thus read access to the /// Read the style source guard, and obtain thus read access to the
/// underlying property declaration block. /// underlying property declaration block.
#[inline] #[inline]
pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> { pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock {
use self::StyleSource::*; let block = match *self {
match *self { StyleSource::Style(ref rule) => &rule.read_with(guard).block,
Style(ref rule) => { StyleSource::Declarations(ref block) => block,
let owning_ref = OwningHandle::new(rule.read(), |r| unsafe { &*r }.block.read()); };
StyleSourceGuard::Style(owning_ref) block.read_with(guard)
}
Declarations(ref block) => StyleSourceGuard::Declarations(block.read()),
}
} }
} }
@ -137,15 +110,15 @@ impl RuleTree {
self.root.clone() self.root.clone()
} }
fn dump<W: Write>(&self, writer: &mut W) { fn dump<W: Write>(&self, guards: &StylesheetGuards, writer: &mut W) {
let _ = writeln!(writer, " + RuleTree"); let _ = writeln!(writer, " + RuleTree");
self.root.get().dump(writer, 0); self.root.get().dump(guards, writer, 0);
} }
/// Dump the rule tree to stdout. /// Dump the rule tree to stdout.
pub fn dump_stdout(&self) { pub fn dump_stdout(&self, guards: &StylesheetGuards) {
let mut stdout = io::stdout(); let mut stdout = io::stdout();
self.dump(&mut stdout); self.dump(guards, &mut stdout);
} }
/// Insert the given rules, that must be in proper order by specifity, and /// Insert the given rules, that must be in proper order by specifity, and
@ -187,8 +160,9 @@ impl RuleTree {
/// the old path is still valid. /// the old path is still valid.
pub fn update_rule_at_level(&self, pub fn update_rule_at_level(&self,
level: CascadeLevel, level: CascadeLevel,
pdb: Option<&Arc<RwLock<PropertyDeclarationBlock>>>, pdb: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
path: &StrongRuleNode) path: &StrongRuleNode,
guards: &StylesheetGuards)
-> Option<StrongRuleNode> { -> Option<StrongRuleNode> {
debug_assert!(level.is_unique_per_element()); debug_assert!(level.is_unique_per_element());
// TODO(emilio): Being smarter with lifetimes we could avoid a bit of // TODO(emilio): Being smarter with lifetimes we could avoid a bit of
@ -247,13 +221,13 @@ impl RuleTree {
// pretty bad styling cases already. // pretty bad styling cases already.
if let Some(pdb) = pdb { if let Some(pdb) = pdb {
if level.is_important() { if level.is_important() {
if pdb.read().any_important() { if pdb.read_with(level.guard(guards)).any_important() {
current = current.ensure_child(self.root.downgrade(), current = current.ensure_child(self.root.downgrade(),
StyleSource::Declarations(pdb.clone()), StyleSource::Declarations(pdb.clone()),
level); level);
} }
} else { } else {
if pdb.read().any_normal() { if pdb.read_with(level.guard(guards)).any_normal() {
current = current.ensure_child(self.root.downgrade(), current = current.ensure_child(self.root.downgrade(),
StyleSource::Declarations(pdb.clone()), StyleSource::Declarations(pdb.clone()),
level); level);
@ -307,6 +281,17 @@ pub enum CascadeLevel {
} }
impl CascadeLevel { impl CascadeLevel {
/// Select a lock guard for this level
pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
match *self {
CascadeLevel::UANormal |
CascadeLevel::UserNormal |
CascadeLevel::UserImportant |
CascadeLevel::UAImportant => guards.ua_or_user,
_ => guards.author,
}
}
/// Returns whether this cascade level is unique per element, in which case /// Returns whether this cascade level is unique per element, in which case
/// we can replace the path in the cascade without fear. /// we can replace the path in the cascade without fear.
pub fn is_unique_per_element(&self) -> bool { pub fn is_unique_per_element(&self) -> bool {
@ -450,7 +435,7 @@ impl RuleNode {
} }
} }
fn dump<W: Write>(&self, writer: &mut W, indent: usize) { fn dump<W: Write>(&self, guards: &StylesheetGuards, writer: &mut W, indent: usize) {
const INDENT_INCREMENT: usize = 4; const INDENT_INCREMENT: usize = 4;
for _ in 0..indent { for _ in 0..indent {
@ -467,7 +452,7 @@ impl RuleNode {
match self.source { match self.source {
Some(ref source) => { Some(ref source) => {
source.dump(writer); source.dump(self.level.guard(guards), writer);
} }
None => { None => {
if indent != 0 { if indent != 0 {
@ -479,7 +464,7 @@ impl RuleNode {
let _ = write!(writer, "\n"); let _ = write!(writer, "\n");
for child in self.iter_children() { for child in self.iter_children() {
child.get().dump(writer, indent + INDENT_INCREMENT); child.get().dump(guards, writer, indent + INDENT_INCREMENT);
} }
} }
@ -627,6 +612,11 @@ impl StrongRuleNode {
self.get().source.as_ref() self.get().source.as_ref()
} }
/// The cascade level for this node
pub fn cascade_level(&self) -> CascadeLevel {
self.get().level
}
/// Get the importance that this rule node represents. /// Get the importance that this rule node represents.
pub fn importance(&self) -> Importance { pub fn importance(&self) -> Importance {
self.get().level.importance() self.get().level.importance()

View file

@ -9,3 +9,13 @@
pub mod media_queries; pub mod media_queries;
pub mod restyle_damage; pub mod restyle_damage;
pub mod selector_parser; pub mod selector_parser;
use shared_lock::SharedRwLock;
lazy_static! {
/// Per-process shared lock for author-origin stylesheets
///
/// FIXME: make it per-document or per-pipeline instead:
/// https://github.com/servo/servo/issues/16027
pub static ref AUTHOR_SHARED_LOCK: SharedRwLock = SharedRwLock::new();
}

View file

@ -0,0 +1,199 @@
/* 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/. */
//! Different objects protected by the same lock
use parking_lot::RwLock;
use std::cell::UnsafeCell;
use std::fmt;
use std::sync::Arc;
/// A shared read/write lock that can protect multiple objects.
#[derive(Clone)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SharedRwLock {
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
arc: Arc<RwLock<()>>,
}
impl fmt::Debug for SharedRwLock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("SharedRwLock")
}
}
impl SharedRwLock {
/// Create a new shared lock
pub fn new() -> Self {
SharedRwLock {
arc: Arc::new(RwLock::new(()))
}
}
/// Wrap the given data to make its access protected by this lock.
pub fn wrap<T>(&self, data: T) -> Locked<T> {
Locked {
shared_lock: self.clone(),
data: UnsafeCell::new(data),
}
}
/// Obtain the lock for reading
pub fn read(&self) -> SharedRwLockReadGuard {
self.arc.raw_read();
SharedRwLockReadGuard {
shared_lock: self
}
}
/// Obtain the lock for writing
pub fn write(&self) -> SharedRwLockWriteGuard {
self.arc.raw_write();
SharedRwLockWriteGuard {
shared_lock: self
}
}
}
/// Data protect by a shared lock.
pub struct Locked<T> {
shared_lock: SharedRwLock,
data: UnsafeCell<T>,
}
// Unsafe: the data inside `UnsafeCell` is only accessed in `read_with` and `write_with`,
// where guards ensure synchronization.
unsafe impl<T: Send> Send for Locked<T> {}
unsafe impl<T: Send + Sync> Sync for Locked<T> {}
impl<T: fmt::Debug> fmt::Debug for Locked<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let guard = self.shared_lock.read();
self.read_with(&guard).fmt(f)
}
}
impl<T> Locked<T> {
fn same_lock_as(&self, lock: &SharedRwLock) -> bool {
::arc_ptr_eq(&self.shared_lock.arc, &lock.arc)
}
/// Access the data for reading.
pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
assert!(self.same_lock_as(&guard.shared_lock),
"Locked::read_with called with a guard from an unrelated SharedRwLock");
let ptr = self.data.get();
// Unsafe:
//
// * The guard guarantees that the lock is taken for reading,
// and weve checked that its the correct lock.
// * The returned reference borrows *both* the data and the guard,
// so that it can outlive neither.
unsafe {
&*ptr
}
}
/// Access the data for writing.
pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
assert!(self.same_lock_as(&guard.shared_lock),
"Locked::write_with called with a guard from an unrelated SharedRwLock");
let ptr = self.data.get();
// Unsafe:
//
// * The guard guarantees that the lock is taken for writing,
// and weve checked that its the correct lock.
// * The returned reference borrows *both* the data and the guard,
// so that it can outlive neither.
// * We require a mutable borrow of the guard,
// so that one write guard can only be used once at a time.
unsafe {
&mut *ptr
}
}
}
/// Proof that a shared lock was obtained for reading.
pub struct SharedRwLockReadGuard<'a> {
shared_lock: &'a SharedRwLock,
}
/// Proof that a shared lock was obtained for writing.
pub struct SharedRwLockWriteGuard<'a> {
shared_lock: &'a SharedRwLock,
}
impl<'a> Drop for SharedRwLockReadGuard<'a> {
fn drop(&mut self) {
// Unsafe: self.lock is private to this module, only ever set after `raw_read()`,
// and never copied or cloned (see `compile_time_assert` below).
unsafe {
self.shared_lock.arc.raw_unlock_read()
}
}
}
impl<'a> Drop for SharedRwLockWriteGuard<'a> {
fn drop(&mut self) {
// Unsafe: self.lock is private to this module, only ever set after `raw_write()`,
// and never copied or cloned (see `compile_time_assert` below).
unsafe {
self.shared_lock.arc.raw_unlock_write()
}
}
}
#[allow(dead_code)]
mod compile_time_assert {
use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
trait Marker1 {}
impl<T: Clone> Marker1 for T {}
impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Clone
impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Clone
trait Marker2 {}
impl<T: Copy> Marker2 for T {}
impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Copy
impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy
}
/// Like ToCss, but with a lock guard given by the caller.
pub trait ToCssWithGuard {
/// Serialize `self` in CSS syntax, writing to `dest`, using the given lock guard.
fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write;
/// Serialize `self` in CSS syntax using the given lock guard and return a string.
///
/// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
#[inline]
fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> String {
let mut s = String::new();
self.to_css(guard, &mut s).unwrap();
s
}
}
/// Guards for a document
#[derive(Clone)]
pub struct StylesheetGuards<'a> {
/// For author-origin stylesheets
pub author: &'a SharedRwLockReadGuard<'a>,
/// For user-agent-origin and user-origin stylesheets
pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
}
impl<'a> StylesheetGuards<'a> {
/// Same guard for all origins
pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
StylesheetGuards {
author: guard,
ua_or_user: guard,
}
}
}

View file

@ -21,6 +21,7 @@ use selector_parser::{SelectorImpl, SelectorParser};
use selectors::parser::SelectorList; use selectors::parser::SelectorList;
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use shared_lock::{SharedRwLock, Locked, ToCssWithGuard, SharedRwLockReadGuard};
use std::cell::Cell; use std::cell::Cell;
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
@ -86,8 +87,8 @@ impl From<SingleRuleParseError> for RulesMutateError {
impl CssRules { impl CssRules {
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn new(rules: Vec<CssRule>) -> Arc<RwLock<CssRules>> { pub fn new(rules: Vec<CssRule>, shared_lock: &SharedRwLock) -> Arc<Locked<CssRules>> {
Arc::new(RwLock::new(CssRules(rules))) Arc::new(shared_lock.wrap(CssRules(rules)))
} }
fn only_ns_or_import(&self) -> bool { fn only_ns_or_import(&self) -> bool {
@ -173,13 +174,15 @@ impl CssRules {
pub struct Stylesheet { pub struct Stylesheet {
/// List of rules in the order they were found (important for /// List of rules in the order they were found (important for
/// cascading order) /// cascading order)
pub rules: Arc<RwLock<CssRules>>, pub rules: Arc<Locked<CssRules>>,
/// List of media associated with the Stylesheet. /// List of media associated with the Stylesheet.
pub media: Arc<RwLock<MediaList>>, pub media: Arc<Locked<MediaList>>,
/// The origin of this stylesheet. /// The origin of this stylesheet.
pub origin: Origin, pub origin: Origin,
/// The base url this stylesheet should use. /// The base url this stylesheet should use.
pub base_url: ServoUrl, pub base_url: ServoUrl,
/// The lock used for objects inside this stylesheet
pub shared_lock: SharedRwLock,
/// The namespaces that apply to this stylesheet. /// The namespaces that apply to this stylesheet.
pub namespaces: RwLock<Namespaces>, pub namespaces: RwLock<Namespaces>,
/// Whether this stylesheet would be dirty when the viewport size changes. /// Whether this stylesheet would be dirty when the viewport size changes.
@ -191,6 +194,8 @@ pub struct Stylesheet {
/// This structure holds the user-agent and user stylesheets. /// This structure holds the user-agent and user stylesheets.
pub struct UserAgentStylesheets { pub struct UserAgentStylesheets {
/// The lock used for user-agent stylesheets.
pub shared_lock: SharedRwLock,
/// The user or user agent stylesheets. /// The user or user agent stylesheets.
pub user_or_user_agent_stylesheets: Vec<Stylesheet>, pub user_or_user_agent_stylesheets: Vec<Stylesheet>,
/// The quirks mode stylesheet. /// The quirks mode stylesheet.
@ -207,14 +212,14 @@ pub enum CssRule {
// No Charset here, CSSCharsetRule has been removed from CSSOM // No Charset here, CSSCharsetRule has been removed from CSSOM
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013 // https://drafts.csswg.org/cssom/#changes-from-5-december-2013
Namespace(Arc<RwLock<NamespaceRule>>), Namespace(Arc<Locked<NamespaceRule>>),
Import(Arc<RwLock<ImportRule>>), Import(Arc<Locked<ImportRule>>),
Style(Arc<RwLock<StyleRule>>), Style(Arc<Locked<StyleRule>>),
Media(Arc<RwLock<MediaRule>>), Media(Arc<Locked<MediaRule>>),
FontFace(Arc<RwLock<FontFaceRule>>), FontFace(Arc<Locked<FontFaceRule>>),
Viewport(Arc<RwLock<ViewportRule>>), Viewport(Arc<Locked<ViewportRule>>),
Keyframes(Arc<RwLock<KeyframesRule>>), Keyframes(Arc<Locked<KeyframesRule>>),
Supports(Arc<RwLock<SupportsRule>>), Supports(Arc<Locked<SupportsRule>>),
} }
#[allow(missing_docs)] #[allow(missing_docs)]
@ -291,13 +296,13 @@ impl CssRule {
/// used for others. /// used for others.
/// ///
/// This will not recurse down unsupported @supports rules /// This will not recurse down unsupported @supports rules
pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R pub fn with_nested_rules_and_mq<F, R>(&self, guard: &SharedRwLockReadGuard, mut f: F) -> R
where F: FnMut(&[CssRule], Option<&MediaList>) -> R { where F: FnMut(&[CssRule], Option<&MediaList>) -> R {
match *self { match *self {
CssRule::Import(ref lock) => { CssRule::Import(ref lock) => {
let rule = lock.read(); let rule = lock.read_with(guard);
let media = rule.stylesheet.media.read(); let media = rule.stylesheet.media.read_with(guard);
let rules = rule.stylesheet.rules.read(); let rules = rule.stylesheet.rules.read_with(guard);
// FIXME(emilio): Include the nested rules if the stylesheet is // FIXME(emilio): Include the nested rules if the stylesheet is
// loaded. // loaded.
f(&rules.0, Some(&media)) f(&rules.0, Some(&media))
@ -310,16 +315,16 @@ impl CssRule {
f(&[], None) f(&[], None)
} }
CssRule::Media(ref lock) => { CssRule::Media(ref lock) => {
let media_rule = lock.read(); let media_rule = lock.read_with(guard);
let mq = media_rule.media_queries.read(); let mq = media_rule.media_queries.read_with(guard);
let rules = &media_rule.rules.read().0; let rules = &media_rule.rules.read_with(guard).0;
f(rules, Some(&mq)) f(rules, Some(&mq))
} }
CssRule::Supports(ref lock) => { CssRule::Supports(ref lock) => {
let supports_rule = lock.read(); let supports_rule = lock.read_with(guard);
let enabled = supports_rule.enabled; let enabled = supports_rule.enabled;
if enabled { if enabled {
let rules = &supports_rule.rules.read().0; let rules = &supports_rule.rules.read_with(guard).0;
f(rules, None) f(rules, None)
} else { } else {
f(&[], None) f(&[], None)
@ -349,6 +354,7 @@ impl CssRule {
let mut rule_parser = TopLevelRuleParser { let mut rule_parser = TopLevelRuleParser {
stylesheet_origin: parent_stylesheet.origin, stylesheet_origin: parent_stylesheet.origin,
context: context, context: context,
shared_lock: &parent_stylesheet.shared_lock,
loader: None, loader: None,
state: Cell::new(state), state: Cell::new(state),
namespaces: &mut namespaces, namespaces: &mut namespaces,
@ -366,18 +372,19 @@ impl CssRule {
} }
} }
impl ToCss for CssRule { impl ToCssWithGuard for CssRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule // https://drafts.csswg.org/cssom/#serialize-a-css-rule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
match *self { match *self {
CssRule::Namespace(ref lock) => lock.read().to_css(dest), CssRule::Namespace(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Import(ref lock) => lock.read().to_css(dest), CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Style(ref lock) => lock.read().to_css(dest), CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::FontFace(ref lock) => lock.read().to_css(dest), CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Viewport(ref lock) => lock.read().to_css(dest), CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Keyframes(ref lock) => lock.read().to_css(dest), CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Media(ref lock) => lock.read().to_css(dest), CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Supports(ref lock) => lock.read().to_css(dest), CssRule::Supports(ref lock) => lock.read_with(guard).to_css(guard, dest),
} }
} }
} }
@ -390,9 +397,10 @@ pub struct NamespaceRule {
pub url: Namespace, pub url: Namespace,
} }
impl ToCss for NamespaceRule { impl ToCssWithGuard for NamespaceRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@namespace ")); try!(dest.write_str("@namespace "));
if let Some(ref prefix) = self.prefix { if let Some(ref prefix) = self.prefix {
try!(dest.write_str(&*prefix.to_string())); try!(dest.write_str(&*prefix.to_string()));
@ -420,11 +428,12 @@ pub struct ImportRule {
pub stylesheet: Arc<Stylesheet>, pub stylesheet: Arc<Stylesheet>,
} }
impl ToCss for ImportRule { impl ToCssWithGuard for ImportRule {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@import ")); try!(dest.write_str("@import "));
try!(self.url.to_css(dest)); try!(self.url.to_css(dest));
let media = self.stylesheet.media.read(); let media = self.stylesheet.media.read_with(guard);
if !media.is_empty() { if !media.is_empty() {
try!(dest.write_str(" ")); try!(dest.write_str(" "));
try!(media.to_css(dest)); try!(media.to_css(dest));
@ -441,12 +450,13 @@ pub struct KeyframesRule {
/// The name of the current animation. /// The name of the current animation.
pub name: Atom, pub name: Atom,
/// The keyframes specified for this CSS rule. /// The keyframes specified for this CSS rule.
pub keyframes: Vec<Arc<RwLock<Keyframe>>>, pub keyframes: Vec<Arc<Locked<Keyframe>>>,
} }
impl ToCss for KeyframesRule { impl ToCssWithGuard for KeyframesRule {
// Serialization of KeyframesRule is not specced. // Serialization of KeyframesRule is not specced.
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@keyframes ")); try!(dest.write_str("@keyframes "));
try!(dest.write_str(&*self.name.to_string())); try!(dest.write_str(&*self.name.to_string()));
try!(dest.write_str(" { ")); try!(dest.write_str(" { "));
@ -457,8 +467,8 @@ impl ToCss for KeyframesRule {
try!(dest.write_str(" ")); try!(dest.write_str(" "));
} }
first = false; first = false;
let keyframe = lock.read(); let keyframe = lock.read_with(&guard);
try!(keyframe.to_css(dest)); try!(keyframe.to_css(guard, dest));
} }
dest.write_str(" }") dest.write_str(" }")
} }
@ -467,20 +477,21 @@ impl ToCss for KeyframesRule {
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug)] #[derive(Debug)]
pub struct MediaRule { pub struct MediaRule {
pub media_queries: Arc<RwLock<MediaList>>, pub media_queries: Arc<Locked<MediaList>>,
pub rules: Arc<RwLock<CssRules>>, pub rules: Arc<Locked<CssRules>>,
} }
impl ToCss for MediaRule { impl ToCssWithGuard for MediaRule {
// Serialization of MediaRule is not specced. // Serialization of MediaRule is not specced.
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@media ")); try!(dest.write_str("@media "));
try!(self.media_queries.read().to_css(dest)); try!(self.media_queries.read_with(guard).to_css(dest));
try!(dest.write_str(" {")); try!(dest.write_str(" {"));
for rule in self.rules.read().0.iter() { for rule in self.rules.read_with(guard).0.iter() {
try!(dest.write_str(" ")); try!(dest.write_str(" "));
try!(rule.to_css(dest)); try!(rule.to_css(guard, dest));
} }
dest.write_str(" }") dest.write_str(" }")
} }
@ -493,19 +504,20 @@ pub struct SupportsRule {
/// The parsed condition /// The parsed condition
pub condition: SupportsCondition, pub condition: SupportsCondition,
/// Child rules /// Child rules
pub rules: Arc<RwLock<CssRules>>, pub rules: Arc<Locked<CssRules>>,
/// The result of evaluating the condition /// The result of evaluating the condition
pub enabled: bool, pub enabled: bool,
} }
impl ToCss for SupportsRule { impl ToCssWithGuard for SupportsRule {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@supports ")); try!(dest.write_str("@supports "));
try!(self.condition.to_css(dest)); try!(self.condition.to_css(dest));
try!(dest.write_str(" {")); try!(dest.write_str(" {"));
for rule in self.rules.read().0.iter() { for rule in self.rules.read_with(guard).0.iter() {
try!(dest.write_str(" ")); try!(dest.write_str(" "));
try!(rule.to_css(dest)); try!(rule.to_css(guard, dest));
} }
dest.write_str(" }") dest.write_str(" }")
} }
@ -515,18 +527,19 @@ impl ToCss for SupportsRule {
#[derive(Debug)] #[derive(Debug)]
pub struct StyleRule { pub struct StyleRule {
pub selectors: SelectorList<SelectorImpl>, pub selectors: SelectorList<SelectorImpl>,
pub block: Arc<RwLock<PropertyDeclarationBlock>>, pub block: Arc<Locked<PropertyDeclarationBlock>>,
} }
impl ToCss for StyleRule { impl ToCssWithGuard for StyleRule {
// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
// Step 1 // Step 1
try!(self.selectors.to_css(dest)); try!(self.selectors.to_css(dest));
// Step 2 // Step 2
try!(dest.write_str(" { ")); try!(dest.write_str(" { "));
// Step 3 // Step 3
let declaration_block = self.block.read(); let declaration_block = self.block.read_with(guard);
try!(declaration_block.to_css(dest)); try!(declaration_block.to_css(dest));
// Step 4 // Step 4
if declaration_block.declarations().len() > 0 { if declaration_block.declarations().len() > 0 {
@ -545,18 +558,39 @@ impl Stylesheet {
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter, error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) { extra_data: ParserContextExtraData) {
let mut rules = existing.rules.write(); let mut namespaces = Namespaces::default();
let mut namespaces = existing.namespaces.write(); let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
css, &existing.base_url, existing.origin, &mut namespaces, &existing.shared_lock,
stylesheet_loader, error_reporter, extra_data,
);
assert!(rules.is_empty()); *existing.namespaces.write() = namespaces;
existing.dirty_on_viewport_size_change
.store(dirty_on_viewport_size_change, Ordering::Release);
// Acquire the lock *after* parsing, to minimize the exclusive section.
let mut guard = existing.shared_lock.write();
*existing.rules.write_with(&mut guard) = CssRules(rules);
}
fn parse_rules(css: &str,
base_url: &ServoUrl,
origin: Origin,
namespaces: &mut Namespaces,
shared_lock: &SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData)
-> (Vec<CssRule>, bool) {
let mut rules = Vec::new();
let mut input = Parser::new(css); let mut input = Parser::new(css);
let rule_parser = TopLevelRuleParser { let rule_parser = TopLevelRuleParser {
stylesheet_origin: existing.origin, stylesheet_origin: origin,
namespaces: &mut namespaces, namespaces: namespaces,
shared_lock: shared_lock,
loader: stylesheet_loader, loader: stylesheet_loader,
context: ParserContext::new_with_extra_data(existing.origin, context: ParserContext::new_with_extra_data(origin,
&existing.base_url, base_url,
error_reporter, error_reporter,
extra_data), extra_data),
state: Cell::new(State::Start), state: Cell::new(State::Start),
@ -568,7 +602,7 @@ impl Stylesheet {
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
match result { match result {
Ok(rule) => rules.0.push(rule), Ok(rule) => rules.push(rule),
Err(range) => { Err(range) => {
let pos = range.start; let pos = range.start;
let message = format!("Invalid rule: '{}'", iter.input.slice(range)); let message = format!("Invalid rule: '{}'", iter.input.slice(range));
@ -578,8 +612,7 @@ impl Stylesheet {
} }
} }
existing.dirty_on_viewport_size_change (rules, input.seen_viewport_percentages())
.store(input.seen_viewport_percentages(), Ordering::Release);
} }
/// Creates an empty stylesheet and parses it with a given base url, origin /// Creates an empty stylesheet and parses it with a given base url, origin
@ -591,26 +624,25 @@ impl Stylesheet {
base_url: ServoUrl, base_url: ServoUrl,
origin: Origin, origin: Origin,
media: MediaList, media: MediaList,
shared_lock: SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter, error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) -> Stylesheet { extra_data: ParserContextExtraData) -> Stylesheet {
let s = Stylesheet { let mut namespaces = Namespaces::default();
let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
css, &base_url, origin, &mut namespaces, &shared_lock,
stylesheet_loader, error_reporter, extra_data,
);
Stylesheet {
origin: origin, origin: origin,
base_url: base_url, base_url: base_url,
namespaces: RwLock::new(Namespaces::default()), namespaces: RwLock::new(namespaces),
rules: CssRules::new(vec![]), rules: CssRules::new(rules, &shared_lock),
media: Arc::new(RwLock::new(media)), media: Arc::new(shared_lock.wrap(media)),
dirty_on_viewport_size_change: AtomicBool::new(false), shared_lock: shared_lock,
dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change),
disabled: AtomicBool::new(false), disabled: AtomicBool::new(false),
}; }
Self::update_from_str(&s,
css,
stylesheet_loader,
error_reporter,
extra_data);
s
} }
/// Whether this stylesheet can be dirty on viewport size change. /// Whether this stylesheet can be dirty on viewport size change.
@ -637,8 +669,8 @@ impl Stylesheet {
/// on the associated MediaList. /// on the associated MediaList.
/// ///
/// Always true if no associated MediaList exists. /// Always true if no associated MediaList exists.
pub fn is_effective_for_device(&self, device: &Device) -> bool { pub fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool {
self.media.read().evaluate(device) self.media.read_with(guard).evaluate(device)
} }
/// Return an iterator over the effective rules within the style-sheet, as /// Return an iterator over the effective rules within the style-sheet, as
@ -648,8 +680,9 @@ impl Stylesheet {
/// nested rules will be skipped. Use `rules` if all rules need to be /// nested rules will be skipped. Use `rules` if all rules need to be
/// examined. /// examined.
#[inline] #[inline]
pub fn effective_rules<F>(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) { pub fn effective_rules<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
effective_rules(&self.rules.read().0, device, &mut f); where F: FnMut(&CssRule) {
effective_rules(&self.rules.read_with(guard).0, device, guard, &mut f);
} }
/// Returns whether the stylesheet has been explicitly disabled through the /// Returns whether the stylesheet has been explicitly disabled through the
@ -670,16 +703,17 @@ impl Stylesheet {
} }
} }
fn effective_rules<F>(rules: &[CssRule], device: &Device, f: &mut F) where F: FnMut(&CssRule) { fn effective_rules<F>(rules: &[CssRule], device: &Device, guard: &SharedRwLockReadGuard, f: &mut F)
where F: FnMut(&CssRule) {
for rule in rules { for rule in rules {
f(rule); f(rule);
rule.with_nested_rules_and_mq(|rules, mq| { rule.with_nested_rules_and_mq(guard, |rules, mq| {
if let Some(media_queries) = mq { if let Some(media_queries) = mq {
if !media_queries.evaluate(device) { if !media_queries.evaluate(device) {
return return
} }
} }
effective_rules(rules, device, f) effective_rules(rules, device, guard, f)
}) })
} }
} }
@ -689,10 +723,11 @@ macro_rules! rule_filter {
impl Stylesheet { impl Stylesheet {
$( $(
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn $method<F>(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) { pub fn $method<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
self.effective_rules(device, |rule| { where F: FnMut(&$rule_type) {
self.effective_rules(device, guard, |rule| {
if let CssRule::$variant(ref lock) = *rule { if let CssRule::$variant(ref lock) = *rule {
let rule = lock.read(); let rule = lock.read_with(guard);
f(&rule) f(&rule)
} }
}) })
@ -718,12 +753,35 @@ pub trait StylesheetLoader {
/// ///
/// The called code is responsible to update the `stylesheet` rules field /// The called code is responsible to update the `stylesheet` rules field
/// when the sheet is done loading. /// when the sheet is done loading.
fn request_stylesheet(&self, import: &Arc<RwLock<ImportRule>>); ///
/// The convoluted signature allows impls to look at MediaList and ImportRule
/// before theyre locked, while keeping the trait object-safe.
fn request_stylesheet(
&self,
media: MediaList,
make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<Locked<ImportRule>>,
) -> Arc<Locked<ImportRule>>;
} }
struct NoOpLoader;
impl StylesheetLoader for NoOpLoader {
fn request_stylesheet(
&self,
media: MediaList,
make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<Locked<ImportRule>>,
) -> Arc<Locked<ImportRule>> {
make_arc(make_import(media))
}
}
struct TopLevelRuleParser<'a> { struct TopLevelRuleParser<'a> {
stylesheet_origin: Origin, stylesheet_origin: Origin,
namespaces: &'a mut Namespaces, namespaces: &'a mut Namespaces,
shared_lock: &'a SharedRwLock,
loader: Option<&'a StylesheetLoader>, loader: Option<&'a StylesheetLoader>,
context: ParserContext<'a>, context: ParserContext<'a>,
state: Cell<State>, state: Cell<State>,
@ -733,6 +791,7 @@ impl<'b> TopLevelRuleParser<'b> {
fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> { fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> {
NestedRuleParser { NestedRuleParser {
stylesheet_origin: self.stylesheet_origin, stylesheet_origin: self.stylesheet_origin,
shared_lock: self.shared_lock,
context: &self.context, context: &self.context,
namespaces: self.namespaces, namespaces: self.namespaces,
} }
@ -754,7 +813,7 @@ enum AtRulePrelude {
/// A @font-face rule prelude. /// A @font-face rule prelude.
FontFace, FontFace,
/// A @media rule prelude, with its media queries. /// A @media rule prelude, with its media queries.
Media(Arc<RwLock<MediaList>>), Media(Arc<Locked<MediaList>>),
/// An @supports rule, with its conditional /// An @supports rule, with its conditional
Supports(SupportsCondition), Supports(SupportsCondition),
/// A @viewport rule prelude. /// A @viewport rule prelude.
@ -774,22 +833,27 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
"import" => { "import" => {
if self.state.get() <= State::Imports { if self.state.get() <= State::Imports {
self.state.set(State::Imports); self.state.set(State::Imports);
let url = try!(input.expect_url_or_string()); let url_string = input.expect_url_or_string()?;
let url = let specified_url = SpecifiedUrl::parse_from_string(url_string, &self.context)?;
try!(SpecifiedUrl::parse_from_string(url,
&self.context));
let media = let media = parse_media_query_list(input);
Arc::new(RwLock::new(parse_media_query_list(input)));
let is_valid_url = url.url().is_some(); let noop_loader = NoOpLoader;
let is_valid_url = specified_url.url().is_some();
let loader = if is_valid_url {
self.loader.expect("Expected a stylesheet loader for @import")
} else {
&noop_loader
};
let import_rule = Arc::new(RwLock::new( let mut specified_url = Some(specified_url);
let arc = loader.request_stylesheet(media, &mut |media| {
ImportRule { ImportRule {
url: url, url: specified_url.take().unwrap(),
stylesheet: Arc::new(Stylesheet { stylesheet: Arc::new(Stylesheet {
rules: Arc::new(RwLock::new(CssRules(vec![]))), rules: CssRules::new(Vec::new(), self.shared_lock),
media: media, media: Arc::new(self.shared_lock.wrap(media)),
shared_lock: self.shared_lock.clone(),
origin: self.context.stylesheet_origin, origin: self.context.stylesheet_origin,
base_url: self.context.base_url.clone(), base_url: self.context.base_url.clone(),
namespaces: RwLock::new(Namespaces::default()), namespaces: RwLock::new(Namespaces::default()),
@ -797,15 +861,10 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
disabled: AtomicBool::new(false), disabled: AtomicBool::new(false),
}) })
} }
)); }, &mut |import_rule| {
Arc::new(self.shared_lock.wrap(import_rule))
if is_valid_url { });
let loader = self.loader return Ok(AtRuleType::WithoutBlock(CssRule::Import(arc)))
.expect("Expected a stylesheet loader for @import");
loader.request_stylesheet(&import_rule);
}
return Ok(AtRuleType::WithoutBlock(CssRule::Import(import_rule)))
} else { } else {
self.state.set(State::Invalid); self.state.set(State::Invalid);
return Err(()) // "@import must be before any rule but @charset" return Err(()) // "@import must be before any rule but @charset"
@ -827,12 +886,12 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
None None
}; };
return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new(RwLock::new( return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new(
NamespaceRule { self.shared_lock.wrap(NamespaceRule {
prefix: opt_prefix, prefix: opt_prefix,
url: url, url: url,
} })
))))) ))))
} else { } else {
self.state.set(State::Invalid); self.state.set(State::Invalid);
return Err(()) // "@namespace must be before any rule but @charset and @import" return Err(()) // "@namespace must be before any rule but @charset and @import"
@ -879,12 +938,13 @@ impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
#[derive(Clone)] // shallow, relatively cheap .clone #[derive(Clone)] // shallow, relatively cheap .clone
struct NestedRuleParser<'a, 'b: 'a> { struct NestedRuleParser<'a, 'b: 'a> {
stylesheet_origin: Origin, stylesheet_origin: Origin,
shared_lock: &'a SharedRwLock,
context: &'a ParserContext<'b>, context: &'a ParserContext<'b>,
namespaces: &'b Namespaces, namespaces: &'b Namespaces,
} }
impl<'a, 'b> NestedRuleParser<'a, 'b> { impl<'a, 'b> NestedRuleParser<'a, 'b> {
fn parse_nested_rules(&self, input: &mut Parser) -> Arc<RwLock<CssRules>> { fn parse_nested_rules(&self, input: &mut Parser) -> Arc<Locked<CssRules>> {
let mut iter = RuleListParser::new_for_nested_rule(input, self.clone()); let mut iter = RuleListParser::new_for_nested_rule(input, self.clone());
let mut rules = Vec::new(); let mut rules = Vec::new();
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
@ -897,7 +957,7 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> {
} }
} }
} }
CssRules::new(rules) CssRules::new(rules, self.shared_lock)
} }
} }
@ -910,7 +970,8 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
match_ignore_ascii_case! { name, match_ignore_ascii_case! { name,
"media" => { "media" => {
let media_queries = parse_media_query_list(input); let media_queries = parse_media_query_list(input);
Ok(AtRuleType::WithBlock(AtRulePrelude::Media(Arc::new(RwLock::new(media_queries))))) let arc = Arc::new(self.shared_lock.wrap(media_queries));
Ok(AtRuleType::WithBlock(AtRulePrelude::Media(arc)))
}, },
"supports" => { "supports" => {
let cond = SupportsCondition::parse(input)?; let cond = SupportsCondition::parse(input)?;
@ -943,31 +1004,31 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> { fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> {
match prelude { match prelude {
AtRulePrelude::FontFace => { AtRulePrelude::FontFace => {
Ok(CssRule::FontFace(Arc::new(RwLock::new( Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
try!(parse_font_face_block(self.context, input)))))) try!(parse_font_face_block(self.context, input))))))
} }
AtRulePrelude::Media(media_queries) => { AtRulePrelude::Media(media_queries) => {
Ok(CssRule::Media(Arc::new(RwLock::new(MediaRule { Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
media_queries: media_queries, media_queries: media_queries,
rules: self.parse_nested_rules(input), rules: self.parse_nested_rules(input),
})))) }))))
} }
AtRulePrelude::Supports(cond) => { AtRulePrelude::Supports(cond) => {
let enabled = cond.eval(self.context); let enabled = cond.eval(self.context);
Ok(CssRule::Supports(Arc::new(RwLock::new(SupportsRule { Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(SupportsRule {
condition: cond, condition: cond,
rules: self.parse_nested_rules(input), rules: self.parse_nested_rules(input),
enabled: enabled, enabled: enabled,
})))) }))))
} }
AtRulePrelude::Viewport => { AtRulePrelude::Viewport => {
Ok(CssRule::Viewport(Arc::new(RwLock::new( Ok(CssRule::Viewport(Arc::new(self.shared_lock.wrap(
try!(ViewportRule::parse(input, self.context)))))) try!(ViewportRule::parse(input, self.context))))))
} }
AtRulePrelude::Keyframes(name) => { AtRulePrelude::Keyframes(name) => {
Ok(CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule { Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule {
name: name, name: name,
keyframes: parse_keyframe_list(&self.context, input), keyframes: parse_keyframe_list(&self.context, input, self.shared_lock),
})))) }))))
} }
} }
@ -988,9 +1049,10 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser) fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser)
-> Result<CssRule, ()> { -> Result<CssRule, ()> {
Ok(CssRule::Style(Arc::new(RwLock::new(StyleRule { let declarations = parse_property_declaration_list(self.context, input);
Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
selectors: prelude, selectors: prelude,
block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input))) block: Arc::new(self.shared_lock.wrap(declarations))
})))) }))))
} }
} }

View file

@ -12,7 +12,6 @@ use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement};
use error_reporting::StdoutErrorReporter; use error_reporting::StdoutErrorReporter;
use keyframes::KeyframesAnimation; use keyframes::KeyframesAnimation;
use media_queries::Device; use media_queries::Device;
use parking_lot::RwLock;
use pdqsort::sort_by; use pdqsort::sort_by;
use properties::{self, CascadeFlags, ComputedValues}; use properties::{self, CascadeFlags, ComputedValues};
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
@ -28,6 +27,7 @@ use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONA
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
use selectors::parser::SelectorMethods; use selectors::parser::SelectorMethods;
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use sink::Push; use sink::Push;
use smallvec::VecLike; use smallvec::VecLike;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -158,6 +158,7 @@ impl Stylist {
/// device is dirty, which means we need to re-evaluate media queries. /// device is dirty, which means we need to re-evaluate media queries.
pub fn update(&mut self, pub fn update(&mut self,
doc_stylesheets: &[Arc<Stylesheet>], doc_stylesheets: &[Arc<Stylesheet>],
guards: &StylesheetGuards,
ua_stylesheets: Option<&UserAgentStylesheets>, ua_stylesheets: Option<&UserAgentStylesheets>,
stylesheets_changed: bool) -> bool { stylesheets_changed: bool) -> bool {
if !(self.is_device_dirty || stylesheets_changed) { if !(self.is_device_dirty || stylesheets_changed) {
@ -165,7 +166,9 @@ impl Stylist {
} }
let cascaded_rule = ViewportRule { let cascaded_rule = ViewportRule {
declarations: viewport::Cascade::from_stylesheets(doc_stylesheets, &self.device).finish(), declarations: viewport::Cascade::from_stylesheets(
doc_stylesheets, guards.author, &self.device
).finish(),
}; };
self.viewport_constraints = self.viewport_constraints =
@ -193,16 +196,16 @@ impl Stylist {
if let Some(ua_stylesheets) = ua_stylesheets { if let Some(ua_stylesheets) = ua_stylesheets {
for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets { for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
self.add_stylesheet(&stylesheet); self.add_stylesheet(&stylesheet, guards.ua_or_user);
} }
if self.quirks_mode { if self.quirks_mode {
self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet); self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user);
} }
} }
for ref stylesheet in doc_stylesheets.iter() { for ref stylesheet in doc_stylesheets.iter() {
self.add_stylesheet(stylesheet); self.add_stylesheet(stylesheet, guards.author);
} }
debug!("Stylist stats:"); debug!("Stylist stats:");
@ -216,8 +219,9 @@ impl Stylist {
SelectorImpl::each_precomputed_pseudo_element(|pseudo| { SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
if let Some(map) = self.pseudos_map.remove(&pseudo) { if let Some(map) = self.pseudos_map.remove(&pseudo) {
let declarations = let declarations =
map.user_agent.get_universal_rules(CascadeLevel::UANormal, map.user_agent.get_universal_rules(
CascadeLevel::UAImportant); guards.ua_or_user, CascadeLevel::UANormal, CascadeLevel::UAImportant
);
self.precomputed_pseudo_element_decls.insert(pseudo, declarations); self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
} }
}); });
@ -226,19 +230,19 @@ impl Stylist {
true true
} }
fn add_stylesheet(&mut self, stylesheet: &Stylesheet) { fn add_stylesheet(&mut self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard) {
if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device) { if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device, guard) {
return; return;
} }
// Cheap `Arc` clone so that the closure below can borrow `&mut Stylist`. // Cheap `Arc` clone so that the closure below can borrow `&mut Stylist`.
let device = self.device.clone(); let device = self.device.clone();
stylesheet.effective_rules(&device, |rule| { stylesheet.effective_rules(&device, guard, |rule| {
match *rule { match *rule {
CssRule::Style(ref style_rule) => { CssRule::Style(ref locked) => {
let guard = style_rule.read(); let style_rule = locked.read_with(&guard);
for selector in &guard.selectors.0 { for selector in &style_rule.selectors.0 {
let map = if let Some(ref pseudo) = selector.pseudo_element { let map = if let Some(ref pseudo) = selector.pseudo_element {
self.pseudos_map self.pseudos_map
.entry(pseudo.clone()) .entry(pseudo.clone())
@ -250,14 +254,14 @@ impl Stylist {
map.insert(Rule { map.insert(Rule {
selector: selector.complex_selector.clone(), selector: selector.complex_selector.clone(),
style_rule: style_rule.clone(), style_rule: locked.clone(),
specificity: selector.specificity, specificity: selector.specificity,
source_order: self.rules_source_order, source_order: self.rules_source_order,
}); });
} }
self.rules_source_order += 1; self.rules_source_order += 1;
for selector in &guard.selectors.0 { for selector in &style_rule.selectors.0 {
self.state_deps.note_selector(&selector.complex_selector); self.state_deps.note_selector(&selector.complex_selector);
if selector.affects_siblings() { if selector.affects_siblings() {
self.sibling_affecting_selectors.push(selector.clone()); self.sibling_affecting_selectors.push(selector.clone());
@ -269,13 +273,14 @@ impl Stylist {
} }
} }
CssRule::Import(ref import) => { CssRule::Import(ref import) => {
let import = import.read(); let import = import.read_with(guard);
self.add_stylesheet(&import.stylesheet) self.add_stylesheet(&import.stylesheet, guard)
} }
CssRule::Keyframes(ref keyframes_rule) => { CssRule::Keyframes(ref keyframes_rule) => {
let keyframes_rule = keyframes_rule.read(); let keyframes_rule = keyframes_rule.read_with(guard);
debug!("Found valid keyframes rule: {:?}", *keyframes_rule); debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
let animation = KeyframesAnimation::from_keyframes(&keyframes_rule.keyframes); let animation = KeyframesAnimation::from_keyframes(
&keyframes_rule.keyframes, guard);
debug!("Found valid keyframe animation: {:?}", animation); debug!("Found valid keyframe animation: {:?}", animation);
self.animations.insert(keyframes_rule.name.clone(), animation); self.animations.insert(keyframes_rule.name.clone(), animation);
} }
@ -294,6 +299,7 @@ impl Stylist {
/// values. The flow constructor uses this flag when constructing anonymous /// values. The flow constructor uses this flag when constructing anonymous
/// flows. /// flows.
pub fn precomputed_values_for_pseudo(&self, pub fn precomputed_values_for_pseudo(&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement, pseudo: &PseudoElement,
parent: Option<&Arc<ComputedValues>>, parent: Option<&Arc<ComputedValues>>,
cascade_flags: CascadeFlags) cascade_flags: CascadeFlags)
@ -327,6 +333,7 @@ impl Stylist {
let computed = let computed =
properties::cascade(&self.device, properties::cascade(&self.device,
&rule_node, &rule_node,
guards,
parent.map(|p| &**p), parent.map(|p| &**p),
parent.map(|p| &**p), parent.map(|p| &**p),
None, None,
@ -338,6 +345,7 @@ impl Stylist {
/// Returns the style for an anonymous box of the given type. /// Returns the style for an anonymous box of the given type.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn style_for_anonymous_box(&self, pub fn style_for_anonymous_box(&self,
guards: &StylesheetGuards,
pseudo: &PseudoElement, pseudo: &PseudoElement,
parent_style: &Arc<ComputedValues>) parent_style: &Arc<ComputedValues>)
-> Arc<ComputedValues> { -> Arc<ComputedValues> {
@ -362,7 +370,7 @@ impl Stylist {
if inherit_all { if inherit_all {
cascade_flags.insert(INHERIT_ALL); cascade_flags.insert(INHERIT_ALL);
} }
self.precomputed_values_for_pseudo(&pseudo, Some(parent_style), cascade_flags) self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags)
.values.unwrap() .values.unwrap()
} }
@ -374,6 +382,7 @@ impl Stylist {
/// Check the documentation on lazy pseudo-elements in /// Check the documentation on lazy pseudo-elements in
/// docs/components/style.md /// docs/components/style.md
pub fn lazily_compute_pseudo_element_style<E>(&self, pub fn lazily_compute_pseudo_element_style<E>(&self,
guards: &StylesheetGuards,
element: &E, element: &E,
pseudo: &PseudoElement, pseudo: &PseudoElement,
parent: &Arc<ComputedValues>) parent: &Arc<ComputedValues>)
@ -395,6 +404,7 @@ impl Stylist {
None, None,
AnimationRules(None, None), AnimationRules(None, None),
Some(pseudo), Some(pseudo),
guards,
&mut declarations, &mut declarations,
&mut flags); &mut flags);
@ -409,6 +419,7 @@ impl Stylist {
let computed = let computed =
properties::cascade(&self.device, properties::cascade(&self.device,
&rule_node, &rule_node,
guards,
Some(&**parent), Some(&**parent),
Some(&**parent), Some(&**parent),
None, None,
@ -461,9 +472,10 @@ impl Stylist {
/// FIXME(emilio): The semantics of the device for Servo and Gecko are /// FIXME(emilio): The semantics of the device for Servo and Gecko are
/// different enough we may want to unify them. /// different enough we may want to unify them.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc<Stylesheet>]) { pub fn set_device(&mut self, mut device: Device, guard: &SharedRwLockReadGuard,
stylesheets: &[Arc<Stylesheet>]) {
let cascaded_rule = ViewportRule { let cascaded_rule = ViewportRule {
declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(), declarations: viewport::Cascade::from_stylesheets(stylesheets, guard, &device).finish(),
}; };
self.viewport_constraints = self.viewport_constraints =
@ -473,15 +485,16 @@ impl Stylist {
device.account_for_viewport_rule(constraints); device.account_for_viewport_rule(constraints);
} }
fn mq_eval_changed(rules: &[CssRule], before: &Device, after: &Device) -> bool { fn mq_eval_changed(guard: &SharedRwLockReadGuard, rules: &[CssRule],
before: &Device, after: &Device) -> bool {
for rule in rules { for rule in rules {
let changed = rule.with_nested_rules_and_mq(|rules, mq| { let changed = rule.with_nested_rules_and_mq(guard, |rules, mq| {
if let Some(mq) = mq { if let Some(mq) = mq {
if mq.evaluate(before) != mq.evaluate(after) { if mq.evaluate(before) != mq.evaluate(after) {
return true return true
} }
} }
mq_eval_changed(rules, before, after) mq_eval_changed(guard, rules, before, after)
}); });
if changed { if changed {
return true return true
@ -490,12 +503,12 @@ impl Stylist {
false false
} }
self.is_device_dirty |= stylesheets.iter().any(|stylesheet| { self.is_device_dirty |= stylesheets.iter().any(|stylesheet| {
let mq = stylesheet.media.read(); let mq = stylesheet.media.read_with(guard);
if mq.evaluate(&self.device) != mq.evaluate(&device) { if mq.evaluate(&self.device) != mq.evaluate(&device) {
return true return true
} }
mq_eval_changed(&stylesheet.rules.read().0, &self.device, &device) mq_eval_changed(guard, &stylesheet.rules.read_with(guard).0, &self.device, &device)
}); });
self.device = Arc::new(device); self.device = Arc::new(device);
@ -528,9 +541,10 @@ impl Stylist {
&self, &self,
element: &E, element: &E,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
style_attribute: Option<&Arc<RwLock<PropertyDeclarationBlock>>>, style_attribute: Option<&Arc<Locked<PropertyDeclarationBlock>>>,
animation_rules: AnimationRules, animation_rules: AnimationRules,
pseudo_element: Option<&PseudoElement>, pseudo_element: Option<&PseudoElement>,
guards: &StylesheetGuards,
applicable_declarations: &mut V, applicable_declarations: &mut V,
flags: &mut ElementSelectorFlags) -> StyleRelations flags: &mut ElementSelectorFlags) -> StyleRelations
where E: TElement + where E: TElement +
@ -556,6 +570,7 @@ impl Stylist {
// Step 1: Normal user-agent rules. // Step 1: Normal user-agent rules.
map.user_agent.get_all_matching_rules(element, map.user_agent.get_all_matching_rules(element,
parent_bf, parent_bf,
guards.ua_or_user,
applicable_declarations, applicable_declarations,
&mut relations, &mut relations,
flags, flags,
@ -580,6 +595,7 @@ impl Stylist {
// Step 3: User and author normal rules. // Step 3: User and author normal rules.
map.user.get_all_matching_rules(element, map.user.get_all_matching_rules(element,
parent_bf, parent_bf,
guards.ua_or_user,
applicable_declarations, applicable_declarations,
&mut relations, &mut relations,
flags, flags,
@ -587,6 +603,7 @@ impl Stylist {
debug!("user normal: {:?}", relations); debug!("user normal: {:?}", relations);
map.author.get_all_matching_rules(element, map.author.get_all_matching_rules(element,
parent_bf, parent_bf,
guards.author,
applicable_declarations, applicable_declarations,
&mut relations, &mut relations,
flags, flags,
@ -595,7 +612,7 @@ impl Stylist {
// Step 4: Normal style attributes. // Step 4: Normal style attributes.
if let Some(sa) = style_attribute { if let Some(sa) = style_attribute {
if sa.read().any_normal() { if sa.read_with(guards.author).any_normal() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE; relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push( Push::push(
applicable_declarations, applicable_declarations,
@ -621,6 +638,7 @@ impl Stylist {
// Step 6: Author-supplied `!important` rules. // Step 6: Author-supplied `!important` rules.
map.author.get_all_matching_rules(element, map.author.get_all_matching_rules(element,
parent_bf, parent_bf,
guards.author,
applicable_declarations, applicable_declarations,
&mut relations, &mut relations,
flags, flags,
@ -630,7 +648,7 @@ impl Stylist {
// Step 7: `!important` style attributes. // Step 7: `!important` style attributes.
if let Some(sa) = style_attribute { if let Some(sa) = style_attribute {
if sa.read().any_important() { if sa.read_with(guards.author).any_important() {
relations |= AFFECTED_BY_STYLE_ATTRIBUTE; relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
Push::push( Push::push(
applicable_declarations, applicable_declarations,
@ -644,6 +662,7 @@ impl Stylist {
// Step 8: User `!important` rules. // Step 8: User `!important` rules.
map.user.get_all_matching_rules(element, map.user.get_all_matching_rules(element,
parent_bf, parent_bf,
guards.ua_or_user,
applicable_declarations, applicable_declarations,
&mut relations, &mut relations,
flags, flags,
@ -657,6 +676,7 @@ impl Stylist {
// Step 9: UA `!important` rules. // Step 9: UA `!important` rules.
map.user_agent.get_all_matching_rules(element, map.user_agent.get_all_matching_rules(element,
parent_bf, parent_bf,
guards.ua_or_user,
applicable_declarations, applicable_declarations,
&mut relations, &mut relations,
flags, flags,
@ -895,6 +915,7 @@ impl SelectorMap {
pub fn get_all_matching_rules<E, V>(&self, pub fn get_all_matching_rules<E, V>(&self,
element: &E, element: &E,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
guard: &SharedRwLockReadGuard,
matching_rules_list: &mut V, matching_rules_list: &mut V,
relations: &mut StyleRelations, relations: &mut StyleRelations,
flags: &mut ElementSelectorFlags, flags: &mut ElementSelectorFlags,
@ -913,6 +934,7 @@ impl SelectorMap {
parent_bf, parent_bf,
&self.id_hash, &self.id_hash,
&id, &id,
guard,
matching_rules_list, matching_rules_list,
relations, relations,
flags, flags,
@ -924,6 +946,7 @@ impl SelectorMap {
parent_bf, parent_bf,
&self.class_hash, &self.class_hash,
class, class,
guard,
matching_rules_list, matching_rules_list,
relations, relations,
flags, flags,
@ -939,6 +962,7 @@ impl SelectorMap {
parent_bf, parent_bf,
local_name_hash, local_name_hash,
element.get_local_name(), element.get_local_name(),
guard,
matching_rules_list, matching_rules_list,
relations, relations,
flags, flags,
@ -947,6 +971,7 @@ impl SelectorMap {
SelectorMap::get_matching_rules(element, SelectorMap::get_matching_rules(element,
parent_bf, parent_bf,
&self.other_rules, &self.other_rules,
guard,
matching_rules_list, matching_rules_list,
relations, relations,
flags, flags,
@ -960,6 +985,7 @@ impl SelectorMap {
/// Append to `rule_list` all universal Rules (rules with selector `*|*`) in /// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
/// `self` sorted by specificity and source order. /// `self` sorted by specificity and source order.
pub fn get_universal_rules(&self, pub fn get_universal_rules(&self,
guard: &SharedRwLockReadGuard,
cascade_level: CascadeLevel, cascade_level: CascadeLevel,
important_cascade_level: CascadeLevel) important_cascade_level: CascadeLevel)
-> Vec<ApplicableDeclarationBlock> { -> Vec<ApplicableDeclarationBlock> {
@ -977,8 +1003,8 @@ impl SelectorMap {
for rule in self.other_rules.iter() { for rule in self.other_rules.iter() {
if rule.selector.compound_selector.is_empty() && if rule.selector.compound_selector.is_empty() &&
rule.selector.next.is_none() { rule.selector.next.is_none() {
let guard = rule.style_rule.read(); let style_rule = rule.style_rule.read_with(guard);
let block = guard.block.read(); let block = style_rule.block.read_with(guard);
if block.any_normal() { if block.any_normal() {
matching_rules_list.push( matching_rules_list.push(
rule.to_applicable_declaration_block(cascade_level)); rule.to_applicable_declaration_block(cascade_level));
@ -1006,6 +1032,7 @@ impl SelectorMap {
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
hash: &FnvHashMap<Str, Vec<Rule>>, hash: &FnvHashMap<Str, Vec<Rule>>,
key: &BorrowedStr, key: &BorrowedStr,
guard: &SharedRwLockReadGuard,
matching_rules: &mut Vector, matching_rules: &mut Vector,
relations: &mut StyleRelations, relations: &mut StyleRelations,
flags: &mut ElementSelectorFlags, flags: &mut ElementSelectorFlags,
@ -1019,6 +1046,7 @@ impl SelectorMap {
SelectorMap::get_matching_rules(element, SelectorMap::get_matching_rules(element,
parent_bf, parent_bf,
rules, rules,
guard,
matching_rules, matching_rules,
relations, relations,
flags, flags,
@ -1030,6 +1058,7 @@ impl SelectorMap {
fn get_matching_rules<E, V>(element: &E, fn get_matching_rules<E, V>(element: &E,
parent_bf: Option<&BloomFilter>, parent_bf: Option<&BloomFilter>,
rules: &[Rule], rules: &[Rule],
guard: &SharedRwLockReadGuard,
matching_rules: &mut V, matching_rules: &mut V,
relations: &mut StyleRelations, relations: &mut StyleRelations,
flags: &mut ElementSelectorFlags, flags: &mut ElementSelectorFlags,
@ -1038,8 +1067,8 @@ impl SelectorMap {
V: VecLike<ApplicableDeclarationBlock> V: VecLike<ApplicableDeclarationBlock>
{ {
for rule in rules.iter() { for rule in rules.iter() {
let guard = rule.style_rule.read(); let style_rule = rule.style_rule.read_with(guard);
let block = guard.block.read(); let block = style_rule.block.read_with(guard);
let any_declaration_for_importance = if cascade_level.is_important() { let any_declaration_for_importance = if cascade_level.is_important() {
block.any_important() block.any_important()
} else { } else {
@ -1137,7 +1166,7 @@ pub struct Rule {
pub selector: Arc<ComplexSelector<SelectorImpl>>, pub selector: Arc<ComplexSelector<SelectorImpl>>,
/// The actual style rule. /// The actual style rule.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
pub style_rule: Arc<RwLock<StyleRule>>, pub style_rule: Arc<Locked<StyleRule>>,
/// The source order this style rule appears in. /// The source order this style rule appears in.
pub source_order: usize, pub source_order: usize,
/// The specificity of the rule this selector represents. /// The specificity of the rule this selector represents.
@ -1178,7 +1207,7 @@ impl ApplicableDeclarationBlock {
/// Constructs an applicable declaration block from a given property /// Constructs an applicable declaration block from a given property
/// declaration block and importance. /// declaration block and importance.
#[inline] #[inline]
pub fn from_declarations(declarations: Arc<RwLock<PropertyDeclarationBlock>>, pub fn from_declarations(declarations: Arc<Locked<PropertyDeclarationBlock>>,
level: CascadeLevel) level: CascadeLevel)
-> Self { -> Self {
ApplicableDeclarationBlock { ApplicableDeclarationBlock {

View file

@ -312,7 +312,8 @@ pub trait DomTraversal<E: TElement> : Sync {
} }
/// Helper for the function below. /// Helper for the function below.
fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, element: E, ensure_data: &F) fn resolve_style_internal<E, F>(context: &mut StyleContext<E>,
element: E, ensure_data: &F)
-> Option<E> -> Option<E>
where E: TElement, where E: TElement,
F: Fn(E), F: Fn(E),

View file

@ -15,6 +15,7 @@ use cssparser::ToCss as ParserToCss;
use euclid::size::TypedSize2D; use euclid::size::TypedSize2D;
use media_queries::Device; use media_queries::Device;
use parser::{ParserContext, log_css_error}; use parser::{ParserContext, log_css_error};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
@ -504,9 +505,10 @@ impl ViewportRule {
} }
} }
impl ToCss for ViewportRule { impl ToCssWithGuard for ViewportRule {
// Serialization of ViewportRule is not specced. // Serialization of ViewportRule is not specced.
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
where W: fmt::Write {
try!(dest.write_str("@viewport { ")); try!(dest.write_str("@viewport { "));
let mut iter = self.declarations.iter(); let mut iter = self.declarations.iter();
try!(iter.next().unwrap().to_css(dest)); try!(iter.next().unwrap().to_css(dest));
@ -555,13 +557,14 @@ impl Cascade {
} }
} }
pub fn from_stylesheets<'a, I>(stylesheets: I, device: &Device) -> Self pub fn from_stylesheets<'a, I>(stylesheets: I, guard: &SharedRwLockReadGuard,
device: &Device) -> Self
where I: IntoIterator, where I: IntoIterator,
I::Item: AsRef<Stylesheet>, I::Item: AsRef<Stylesheet>,
{ {
let mut cascade = Self::new(); let mut cascade = Self::new();
for stylesheet in stylesheets { for stylesheet in stylesheets {
stylesheet.as_ref().effective_viewport_rules(device, |rule| { stylesheet.as_ref().effective_viewport_rules(device, guard, |rule| {
for declaration in &rule.declarations { for declaration in &rule.declarations {
cascade.add(Cow::Borrowed(declaration)) cascade.add(Cow::Borrowed(declaration))
} }

View file

@ -20,9 +20,7 @@ env_logger = {version = "0.4", default-features = false} # disable `regex` to re
lazy_static = "0.2" lazy_static = "0.2"
libc = "0.2" libc = "0.2"
log = {version = "0.3.5", features = ["release_max_level_info"]} log = {version = "0.3.5", features = ["release_max_level_info"]}
num_cpus = "1.1.0"
parking_lot = "0.3" parking_lot = "0.3"
rayon = "0.6"
selectors = {path = "../../components/selectors"} selectors = {path = "../../components/selectors"}
servo_url = {path = "../../components/url"} servo_url = {path = "../../components/url"}
style = {path = "../../components/style", features = ["gecko"]} style = {path = "../../components/style", features = ["gecko"]}

View file

@ -6,13 +6,10 @@ use atomic_refcell::AtomicRefMut;
use cssparser::Parser; use cssparser::Parser;
use cssparser::ToCss as ParserToCss; use cssparser::ToCss as ParserToCss;
use env_logger::LogBuilder; use env_logger::LogBuilder;
use num_cpus;
use parking_lot::RwLock; use parking_lot::RwLock;
use rayon;
use selectors::Element; use selectors::Element;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp;
use std::env; use std::env;
use std::fmt::Write; use std::fmt::Write;
use std::ptr; use std::ptr;
@ -24,6 +21,7 @@ use style::data::{ElementData, ElementStyles, RestyleData};
use style::dom::{ShowSubtreeData, TElement, TNode}; use style::dom::{ShowSubtreeData, TElement, TNode};
use style::error_reporting::StdoutErrorReporter; use style::error_reporting::StdoutErrorReporter;
use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl}; use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl};
use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
use style::gecko::restyle_damage::GeckoRestyleDamage; use style::gecko::restyle_damage::GeckoRestyleDamage;
use style::gecko::selector_parser::{SelectorImpl, PseudoElement}; use style::gecko::selector_parser::{SelectorImpl, PseudoElement};
use style::gecko::traversal::RecalcStyleOnly; use style::gecko::traversal::RecalcStyleOnly;
@ -76,6 +74,7 @@ use style::properties::parse_one_declaration;
use style::restyle_hints::{self, RestyleHint}; use style::restyle_hints::{self, RestyleHint};
use style::selector_parser::PseudoElementCascadeType; use style::selector_parser::PseudoElementCascadeType;
use style::sequential; use style::sequential;
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
use style::string_cache::Atom; use style::string_cache::Atom;
use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule};
use style::stylesheets::{Origin, Stylesheet, StyleRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule};
@ -85,7 +84,7 @@ use style::thread_state;
use style::timer::Timer; use style::timer::Timer;
use style::traversal::{resolve_style, DomTraversal, TraversalDriver}; use style::traversal::{resolve_style, DomTraversal, TraversalDriver};
use style_traits::ToCss; use style_traits::ToCss;
use stylesheet_loader::StylesheetLoader; use super::stylesheet_loader::StylesheetLoader;
/* /*
* For Gecko->Servo function calls, we need to redeclare the same signature that was declared in * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
@ -95,44 +94,7 @@ use stylesheet_loader::StylesheetLoader;
* depend on but good enough for our purposes. * depend on but good enough for our purposes.
*/ */
struct GlobalStyleData {
// How many threads parallel styling can use.
pub num_threads: usize,
// The parallel styling thread pool.
pub style_thread_pool: Option<rayon::ThreadPool>,
}
impl GlobalStyleData {
pub fn new() -> Self {
let stylo_threads = env::var("STYLO_THREADS")
.map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
let num_threads = match stylo_threads {
Ok(num) => num,
_ => cmp::max(num_cpus::get() * 3 / 4, 1),
};
let pool = if num_threads <= 1 {
None
} else {
let configuration =
rayon::Configuration::new().set_num_threads(num_threads);
let pool = rayon::ThreadPool::new(configuration).ok();
pool
};
GlobalStyleData {
num_threads: num_threads,
style_thread_pool: pool,
}
}
}
lazy_static! {
static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
GlobalStyleData::new()
};
}
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_Initialize() { pub extern "C" fn Servo_Initialize() {
@ -160,12 +122,14 @@ pub extern "C" fn Servo_Shutdown() {
gecko_properties::shutdown(); gecko_properties::shutdown();
} }
fn create_shared_context(per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext { fn create_shared_context<'a>(guard: &'a SharedRwLockReadGuard,
per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext<'a> {
let local_context_data = let local_context_data =
ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone()); ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone());
SharedStyleContext { SharedStyleContext {
stylist: per_doc_data.stylist.clone(), stylist: per_doc_data.stylist.clone(),
guards: StylesheetGuards::same(guard),
running_animations: per_doc_data.running_animations.clone(), running_animations: per_doc_data.running_animations.clone(),
expired_animations: per_doc_data.expired_animations.clone(), expired_animations: per_doc_data.expired_animations.clone(),
// FIXME(emilio): Stop boxing here. // FIXME(emilio): Stop boxing here.
@ -198,8 +162,9 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed,
debug!("Traversing subtree:"); debug!("Traversing subtree:");
debug!("{:?}", ShowSubtreeData(element.as_node())); debug!("{:?}", ShowSubtreeData(element.as_node()));
let shared_style_context = create_shared_context(&per_doc_data); let global_style_data = &*GLOBAL_STYLE_DATA;
let ref global_style_data = *GLOBAL_STYLE_DATA; let guard = global_style_data.shared_lock.read();
let shared_style_context = create_shared_context(&guard, &per_doc_data);
let traversal_driver = if global_style_data.style_thread_pool.is_none() { let traversal_driver = if global_style_data.style_thread_pool.is_none() {
TraversalDriver::Sequential TraversalDriver::Sequential
@ -328,6 +293,7 @@ pub extern "C" fn Servo_Element_ClearData(element: RawGeckoElementBorrowed) {
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetStrong { pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let url = ServoUrl::parse("about:blank").unwrap(); let url = ServoUrl::parse("about:blank").unwrap();
let extra_data = ParserContextExtraData::default(); let extra_data = ParserContextExtraData::default();
let origin = match mode { let origin = match mode {
@ -335,8 +301,9 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl
SheetParsingMode::eUserSheetFeatures => Origin::User, SheetParsingMode::eUserSheetFeatures => Origin::User,
SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
}; };
let shared_lock = global_style_data.shared_lock.clone();
Arc::new(Stylesheet::from_str( Arc::new(Stylesheet::from_str(
"", url, origin, Default::default(), None, "", url, origin, Default::default(), shared_lock, None,
&StdoutErrorReporter, extra_data) &StdoutErrorReporter, extra_data)
).into_strong() ).into_strong()
} }
@ -351,6 +318,7 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
referrer: *mut ThreadSafeURIHolder, referrer: *mut ThreadSafeURIHolder,
principal: *mut ThreadSafePrincipalHolder) principal: *mut ThreadSafePrincipalHolder)
-> RawServoStyleSheetStrong { -> RawServoStyleSheetStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let input = unsafe { data.as_ref().unwrap().as_str_unchecked() }; let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
let origin = match mode { let origin = match mode {
@ -378,8 +346,9 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
Some(ref s) => Some(s), Some(ref s) => Some(s),
}; };
let shared_lock = global_style_data.shared_lock.clone();
Arc::new(Stylesheet::from_str( Arc::new(Stylesheet::from_str(
input, url, origin, Default::default(), loader, input, url, origin, Default::default(), shared_lock, loader,
&StdoutErrorReporter, extra_data) &StdoutErrorReporter, extra_data)
).into_strong() ).into_strong()
} }
@ -413,23 +382,22 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
}; };
let sheet = Stylesheet::as_arc(&stylesheet); let sheet = Stylesheet::as_arc(&stylesheet);
sheet.rules.write().0.clear(); Stylesheet::update_from_str(&sheet, input, loader, &StdoutErrorReporter, extra_data);
Stylesheet::update_from_str(&sheet, input, loader,
&StdoutErrorReporter, extra_data);
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed, pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed,
raw_sheet: RawServoStyleSheetBorrowed, raw_sheet: RawServoStyleSheetBorrowed,
flush: bool) { flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet); let sheet = HasArcFFI::as_arc(&raw_sheet);
data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
data.stylesheets.push(sheet.clone()); data.stylesheets.push(sheet.clone());
data.stylesheets_changed = true; data.stylesheets_changed = true;
if flush { if flush {
data.flush_stylesheets(); data.flush_stylesheets(&guard);
} }
} }
@ -437,13 +405,15 @@ pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorr
pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed, pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed,
raw_sheet: RawServoStyleSheetBorrowed, raw_sheet: RawServoStyleSheetBorrowed,
flush: bool) { flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet); let sheet = HasArcFFI::as_arc(&raw_sheet);
data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
data.stylesheets.insert(0, sheet.clone()); data.stylesheets.insert(0, sheet.clone());
data.stylesheets_changed = true; data.stylesheets_changed = true;
if flush { if flush {
data.flush_stylesheets(); data.flush_stylesheets(&guard);
} }
} }
@ -452,6 +422,8 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS
raw_sheet: RawServoStyleSheetBorrowed, raw_sheet: RawServoStyleSheetBorrowed,
raw_reference: RawServoStyleSheetBorrowed, raw_reference: RawServoStyleSheetBorrowed,
flush: bool) { flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet); let sheet = HasArcFFI::as_arc(&raw_sheet);
let reference = HasArcFFI::as_arc(&raw_reference); let reference = HasArcFFI::as_arc(&raw_reference);
@ -460,7 +432,7 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS
data.stylesheets.insert(index, sheet.clone()); data.stylesheets.insert(index, sheet.clone());
data.stylesheets_changed = true; data.stylesheets_changed = true;
if flush { if flush {
data.flush_stylesheets(); data.flush_stylesheets(&guard);
} }
} }
@ -468,19 +440,23 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS
pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorrowed, pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorrowed,
raw_sheet: RawServoStyleSheetBorrowed, raw_sheet: RawServoStyleSheetBorrowed,
flush: bool) { flush: bool) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let sheet = HasArcFFI::as_arc(&raw_sheet); let sheet = HasArcFFI::as_arc(&raw_sheet);
data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
data.stylesheets_changed = true; data.stylesheets_changed = true;
if flush { if flush {
data.flush_stylesheets(); data.flush_stylesheets(&guard);
} }
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_FlushStyleSheets(raw_data: RawServoStyleSetBorrowed) { pub extern "C" fn Servo_StyleSet_FlushStyleSheets(raw_data: RawServoStyleSetBorrowed) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
data.flush_stylesheets(); data.flush_stylesheets(&guard);
} }
#[no_mangle] #[no_mangle]
@ -491,7 +467,9 @@ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(raw_data: RawServoStyleS
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool { pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool {
!Stylesheet::as_arc(&raw_sheet).rules.read().0.is_empty() let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
!Stylesheet::as_arc(&raw_sheet).rules.read_with(&guard).0.is_empty()
} }
#[no_mangle] #[no_mangle]
@ -502,7 +480,9 @@ pub extern "C" fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed) -
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed, pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
result: nsTArrayBorrowed_uintptr_t) { result: nsTArrayBorrowed_uintptr_t) {
let rules = RwLock::<CssRules>::as_arc(&rules).read(); let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
let iter = rules.0.iter().map(|rule| rule.rule_type() as usize); let iter = rules.0.iter().map(|rule| rule.rule_type() as usize);
let (size, upper) = iter.size_hint(); let (size, upper) = iter.size_hint();
debug_assert_eq!(size, upper.unwrap()); debug_assert_eq!(size, upper.unwrap());
@ -514,10 +494,12 @@ pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet: RawServoStyleSheetBorrowed, pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet: RawServoStyleSheetBorrowed,
rule: *const nsACString, index: u32, nested: bool, rule: *const nsACString, index: u32, nested: bool,
rule_type: *mut u16) -> nsresult { rule_type: *mut u16) -> nsresult {
let rules = RwLock::<CssRules>::as_arc(&rules); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let rules = Locked::<CssRules>::as_arc(&rules);
let sheet = Stylesheet::as_arc(&sheet); let sheet = Stylesheet::as_arc(&sheet);
let rule = unsafe { rule.as_ref().unwrap().as_str_unchecked() }; let rule = unsafe { rule.as_ref().unwrap().as_str_unchecked() };
match rules.write().insert_rule(rule, sheet, index as usize, nested) { match rules.write_with(&mut guard).insert_rule(rule, sheet, index as usize, nested) {
Ok(new_rule) => { Ok(new_rule) => {
*unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16; *unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16;
nsresult::NS_OK nsresult::NS_OK
@ -528,8 +510,10 @@ pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet:
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: u32) -> nsresult { pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: u32) -> nsresult {
let rules = RwLock::<CssRules>::as_arc(&rules); let global_style_data = &*GLOBAL_STYLE_DATA;
match rules.write().remove_rule(index as usize) { let mut guard = global_style_data.shared_lock.write();
let rules = Locked::<CssRules>::as_arc(&rules);
match rules.write_with(&mut guard).remove_rule(index as usize) {
Ok(_) => nsresult::NS_OK, Ok(_) => nsresult::NS_OK,
Err(err) => err.into() Err(err) => err.into()
} }
@ -543,7 +527,9 @@ macro_rules! impl_basic_rule_funcs {
} => { } => {
#[no_mangle] #[no_mangle]
pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32) -> Strong<$raw_type> { pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32) -> Strong<$raw_type> {
let rules = RwLock::<CssRules>::as_arc(&rules).read(); let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
match rules.0[index as usize] { match rules.0[index as usize] {
CssRule::$name(ref rule) => rule.clone().into_strong(), CssRule::$name(ref rule) => rule.clone().into_strong(),
_ => { _ => {
@ -555,15 +541,19 @@ macro_rules! impl_basic_rule_funcs {
#[no_mangle] #[no_mangle]
pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) { pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) {
let rule = RwLock::<$rule_type>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<$rule_type>::as_arc(&rule);
let result = unsafe { result.as_mut().unwrap() }; let result = unsafe { result.as_mut().unwrap() };
write!(result, "{:?}", *rule.read()).unwrap(); write!(result, "{:?}", *rule.read_with(&guard)).unwrap();
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) { pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) {
let rule = RwLock::<$rule_type>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
rule.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); let guard = global_style_data.shared_lock.read();
let rule = Locked::<$rule_type>::as_arc(&rule);
rule.read_with(&guard).to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap();
} }
} }
} }
@ -588,46 +578,60 @@ impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule),
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong { pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong {
let rule = RwLock::<StyleRule>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
rule.read().block.clone().into_strong() let guard = global_style_data.shared_lock.read();
let rule = Locked::<StyleRule>::as_arc(&rule);
rule.read_with(&guard).block.clone().into_strong()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed, pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
declarations: RawServoDeclarationBlockBorrowed) { declarations: RawServoDeclarationBlockBorrowed) {
let rule = RwLock::<StyleRule>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let mut guard = global_style_data.shared_lock.write();
rule.write().block = declarations.clone(); let rule = Locked::<StyleRule>::as_arc(&rule);
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
rule.write_with(&mut guard).block = declarations.clone();
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) { pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) {
let rule = RwLock::<StyleRule>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); let guard = global_style_data.shared_lock.read();
let rule = Locked::<StyleRule>::as_arc(&rule);
rule.read_with(&guard).selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong { pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong {
let rule = RwLock::<MediaRule>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
rule.read().media_queries.clone().into_strong() let guard = global_style_data.shared_lock.read();
let rule = Locked::<MediaRule>::as_arc(&rule);
rule.read_with(&guard).media_queries.clone().into_strong()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaRule_GetRules(rule: RawServoMediaRuleBorrowed) -> ServoCssRulesStrong { pub extern "C" fn Servo_MediaRule_GetRules(rule: RawServoMediaRuleBorrowed) -> ServoCssRulesStrong {
let rule = RwLock::<MediaRule>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
rule.read().rules.clone().into_strong() let guard = global_style_data.shared_lock.read();
let rule = Locked::<MediaRule>::as_arc(&rule);
rule.read_with(&guard).rules.clone().into_strong()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom { pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom {
let rule = RwLock::<NamespaceRule>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
rule.read().prefix.as_ref().unwrap_or(&atom!("")).as_ptr() let guard = global_style_data.shared_lock.read();
let rule = Locked::<NamespaceRule>::as_arc(&rule);
rule.read_with(&guard).prefix.as_ref().unwrap_or(&atom!("")).as_ptr()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_NamespaceRule_GetURI(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom { pub extern "C" fn Servo_NamespaceRule_GetURI(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom {
let rule = RwLock::<NamespaceRule>::as_arc(&rule); let global_style_data = &*GLOBAL_STYLE_DATA;
rule.read().url.0.as_ptr() let guard = global_style_data.shared_lock.read();
let rule = Locked::<NamespaceRule>::as_arc(&rule);
rule.read_with(&guard).url.0.as_ptr()
} }
#[no_mangle] #[no_mangle]
@ -636,6 +640,9 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
skip_display_fixup: bool, skip_display_fixup: bool,
raw_data: RawServoStyleSetBorrowed) raw_data: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong { -> ServoComputedValuesStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let guards = StylesheetGuards::same(&guard);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let atom = Atom::from(pseudo_tag); let atom = Atom::from(pseudo_tag);
let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true); let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true);
@ -646,7 +653,7 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null:
if skip_display_fixup { if skip_display_fixup {
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP); cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
} }
data.stylist.precomputed_values_for_pseudo(&pseudo, maybe_parent, data.stylist.precomputed_values_for_pseudo(&guards, &pseudo, maybe_parent,
cascade_flags) cascade_flags)
.values.unwrap() .values.unwrap()
.into_strong() .into_strong()
@ -672,14 +679,16 @@ pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
}; };
} }
match get_pseudo_style(element, pseudo_tag, data.styles(), doc_data) { let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
match get_pseudo_style(&guard, element, pseudo_tag, data.styles(), doc_data) {
Some(values) => values.into_strong(), Some(values) => values.into_strong(),
None if !is_probe => data.styles().primary.values().clone().into_strong(), None if !is_probe => data.styles().primary.values().clone().into_strong(),
None => Strong::null(), None => Strong::null(),
} }
} }
fn get_pseudo_style(element: GeckoElement, pseudo_tag: *mut nsIAtom, fn get_pseudo_style(guard: &SharedRwLockReadGuard, element: GeckoElement, pseudo_tag: *mut nsIAtom,
styles: &ElementStyles, doc_data: &PerDocumentStyleData) styles: &ElementStyles, doc_data: &PerDocumentStyleData)
-> Option<Arc<ComputedValues>> -> Option<Arc<ComputedValues>>
{ {
@ -690,7 +699,9 @@ fn get_pseudo_style(element: GeckoElement, pseudo_tag: *mut nsIAtom,
PseudoElementCascadeType::Lazy => { PseudoElementCascadeType::Lazy => {
let d = doc_data.borrow_mut(); let d = doc_data.borrow_mut();
let base = styles.primary.values(); let base = styles.primary.values();
d.stylist.lazily_compute_pseudo_element_style(&element, let guards = StylesheetGuards::same(guard);
d.stylist.lazily_compute_pseudo_element_style(&guards,
&element,
&pseudo, &pseudo,
base) base)
.map(|s| s.values().clone()) .map(|s| s.values().clone())
@ -725,8 +736,10 @@ pub extern "C" fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned)
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_StyleSet_RebuildData(raw_data: RawServoStyleSetBorrowed) { pub extern "C" fn Servo_StyleSet_RebuildData(raw_data: RawServoStyleSetBorrowed) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
data.reset_device(); data.reset_device(&guard);
} }
#[no_mangle] #[no_mangle]
@ -768,9 +781,10 @@ pub extern "C" fn Servo_ParseProperty(property: *const nsACString, value: *const
match ParsedDeclaration::parse(id, &context, &mut Parser::new(value), false) { match ParsedDeclaration::parse(id, &context, &mut Parser::new(value), false) {
Ok(parsed) => { Ok(parsed) => {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut block = PropertyDeclarationBlock::new(); let mut block = PropertyDeclarationBlock::new();
parsed.expand(|d| block.push(d, Importance::Normal)); parsed.expand(|d| block.push(d, Importance::Normal));
Arc::new(RwLock::new(block)).into_strong() Arc::new(global_style_data.shared_lock.wrap(block)).into_strong()
} }
Err(_) => RawServoDeclarationBlockStrong::null() Err(_) => RawServoDeclarationBlockStrong::null()
} }
@ -781,36 +795,47 @@ pub extern "C" fn Servo_ParseStyleAttribute(data: *const nsACString,
base: *const nsACString, base: *const nsACString,
raw_extra_data: *const structs::GeckoParserExtraData) raw_extra_data: *const structs::GeckoParserExtraData)
-> RawServoDeclarationBlockStrong { -> RawServoDeclarationBlockStrong {
let global_style_data = &*GLOBAL_STYLE_DATA;
let value = unsafe { data.as_ref().unwrap().as_str_unchecked() }; let value = unsafe { data.as_ref().unwrap().as_str_unchecked() };
make_context!((base, raw_extra_data) => (base_url, extra_data)); make_context!((base, raw_extra_data) => (base_url, extra_data));
Arc::new(RwLock::new(GeckoElement::parse_style_attribute(value, &base_url, extra_data))).into_strong() Arc::new(global_style_data.shared_lock.wrap(
GeckoElement::parse_style_attribute(value, &base_url, extra_data))).into_strong()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> RawServoDeclarationBlockStrong { pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> RawServoDeclarationBlockStrong {
Arc::new(RwLock::new(PropertyDeclarationBlock::new())).into_strong() let global_style_data = &*GLOBAL_STYLE_DATA;
Arc::new(global_style_data.shared_lock.wrap(PropertyDeclarationBlock::new())).into_strong()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Clone(declarations: RawServoDeclarationBlockBorrowed) pub extern "C" fn Servo_DeclarationBlock_Clone(declarations: RawServoDeclarationBlockBorrowed)
-> RawServoDeclarationBlockStrong { -> RawServoDeclarationBlockStrong {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
Arc::new(RwLock::new(declarations.read().clone())).into_strong() let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
Arc::new(global_style_data.shared_lock.wrap(
declarations.read_with(&guard).clone()
)).into_strong()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed, pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed,
b: RawServoDeclarationBlockBorrowed) b: RawServoDeclarationBlockBorrowed)
-> bool { -> bool {
*RwLock::<PropertyDeclarationBlock>::as_arc(&a).read().declarations() == let global_style_data = &*GLOBAL_STYLE_DATA;
*RwLock::<PropertyDeclarationBlock>::as_arc(&b).read().declarations() let guard = global_style_data.shared_lock.read();
*Locked::<PropertyDeclarationBlock>::as_arc(&a).read_with(&guard).declarations() ==
*Locked::<PropertyDeclarationBlock>::as_arc(&b).read_with(&guard).declarations()
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed, pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed,
result: *mut nsAString) { result: *mut nsAString) {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
declarations.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap();
} }
#[no_mangle] #[no_mangle]
@ -819,9 +844,11 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
property_id: nsCSSPropertyID, buffer: *mut nsAString) property_id: nsCSSPropertyID, buffer: *mut nsAString)
{ {
let property_id = get_property_id_from_nscsspropertyid!(property_id, ()); let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let mut string = String::new(); let mut string = String::new();
let rv = declarations.read().single_value_to_css(&property_id, &mut string); let rv = declarations.read_with(&guard).single_value_to_css(&property_id, &mut string);
debug_assert!(rv.is_ok()); debug_assert!(rv.is_ok());
write!(unsafe { &mut *buffer }, "{}", string).expect("Failed to copy string"); write!(unsafe { &mut *buffer }, "{}", string).expect("Failed to copy string");
@ -829,15 +856,19 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 { pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
declarations.read().declarations().len() as u32 let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard).declarations().len() as u32
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDeclarationBlockBorrowed, pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDeclarationBlockBorrowed,
index: u32, result: *mut nsAString) -> bool { index: u32, result: *mut nsAString) -> bool {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
if let Some(&(ref decl, _)) = declarations.read().declarations().get(index as usize) { let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
if let Some(&(ref decl, _)) = declarations.read_with(&guard).declarations().get(index as usize) {
let result = unsafe { result.as_mut().unwrap() }; let result = unsafe { result.as_mut().unwrap() };
decl.id().to_css(result).unwrap(); decl.id().to_css(result).unwrap();
true true
@ -858,8 +889,12 @@ macro_rules! get_property_id_from_property {
fn get_property_value(declarations: RawServoDeclarationBlockBorrowed, fn get_property_value(declarations: RawServoDeclarationBlockBorrowed,
property_id: PropertyId, value: *mut nsAString) { property_id: PropertyId, value: *mut nsAString) {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
declarations.read().property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() }).unwrap(); let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard)
.property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() })
.unwrap();
} }
#[no_mangle] #[no_mangle]
@ -878,8 +913,10 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(declarations: RawS
pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed, pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed,
property: *const nsACString) -> bool { property: *const nsACString) -> bool {
let property_id = get_property_id_from_property!(property, false); let property_id = get_property_id_from_property!(property, false);
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
declarations.read().property_priority(&property_id).important() let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.read_with(&guard).property_priority(&property_id).important()
} }
fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId, fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId,
@ -890,7 +927,10 @@ fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: Pro
make_context!((base, data) => (base_url, extra_data)); make_context!((base, data) => (base_url, extra_data));
if let Ok(parsed) = parse_one_declaration(property_id, value, &base_url, if let Ok(parsed) = parse_one_declaration(property_id, value, &base_url,
&StdoutErrorReporter, extra_data) { &StdoutErrorReporter, extra_data) {
let mut declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations).write(); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations)
.write_with(&mut guard);
let importance = if is_important { Importance::Important } else { Importance::Normal }; let importance = if is_important { Importance::Important } else { Importance::Normal };
let mut changed = false; let mut changed = false;
parsed.expand(|decl| { parsed.expand(|decl| {
@ -923,8 +963,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetPropertyById(declarations: RawServoD
} }
fn remove_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId) { fn remove_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId) {
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
declarations.write().remove_property(&property_id); let mut guard = global_style_data.shared_lock.write();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
declarations.write_with(&mut guard).remove_property(&property_id);
} }
#[no_mangle] #[no_mangle]
@ -941,29 +983,37 @@ pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(declarations: RawSer
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) { pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) {
let list = RwLock::<MediaList>::as_arc(&list); let global_style_data = &*GLOBAL_STYLE_DATA;
list.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); let guard = global_style_data.shared_lock.read();
let list = Locked::<MediaList>::as_arc(&list);
list.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap();
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaList_SetText(list: RawServoMediaListBorrowed, text: *const nsACString) { pub extern "C" fn Servo_MediaList_SetText(list: RawServoMediaListBorrowed, text: *const nsACString) {
let list = RwLock::<MediaList>::as_arc(&list); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let list = Locked::<MediaList>::as_arc(&list);
let text = unsafe { text.as_ref().unwrap().as_str_unchecked() }; let text = unsafe { text.as_ref().unwrap().as_str_unchecked() };
let mut parser = Parser::new(&text); let mut parser = Parser::new(&text);
*list.write() = parse_media_query_list(&mut parser); *list.write_with(&mut guard) = parse_media_query_list(&mut parser);
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 { pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 {
let list = RwLock::<MediaList>::as_arc(&list); let global_style_data = &*GLOBAL_STYLE_DATA;
list.read().media_queries.len() as u32 let guard = global_style_data.shared_lock.read();
let list = Locked::<MediaList>::as_arc(&list);
list.read_with(&guard).media_queries.len() as u32
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, index: u32, pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, index: u32,
result: *mut nsAString) -> bool { result: *mut nsAString) -> bool {
let list = RwLock::<MediaList>::as_arc(&list); let global_style_data = &*GLOBAL_STYLE_DATA;
if let Some(media_query) = list.read().media_queries.get(index as usize) { let guard = global_style_data.shared_lock.read();
let list = Locked::<MediaList>::as_arc(&list);
if let Some(media_query) = list.read_with(&guard).media_queries.get(index as usize) {
media_query.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); media_query.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
true true
} else { } else {
@ -974,17 +1024,21 @@ pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, i
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed, pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed,
new_medium: *const nsACString) { new_medium: *const nsACString) {
let list = RwLock::<MediaList>::as_arc(&list); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let list = Locked::<MediaList>::as_arc(&list);
let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() }; let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() };
list.write().append_medium(new_medium); list.write_with(&mut guard).append_medium(new_medium);
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Servo_MediaList_DeleteMedium(list: RawServoMediaListBorrowed, pub extern "C" fn Servo_MediaList_DeleteMedium(list: RawServoMediaListBorrowed,
old_medium: *const nsACString) -> bool { old_medium: *const nsACString) -> bool {
let list = RwLock::<MediaList>::as_arc(&list); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let list = Locked::<MediaList>::as_arc(&list);
let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() }; let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() };
list.write().delete_medium(old_medium) list.write_with(&mut guard).delete_medium(old_medium)
} }
macro_rules! get_longhand_from_id { macro_rules! get_longhand_from_id {
@ -1022,9 +1076,11 @@ pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(declarations:
property: nsCSSPropertyID) property: nsCSSPropertyID)
-> bool { -> bool {
use style::properties::PropertyDeclarationId; use style::properties::PropertyDeclarationId;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property, false); let long = get_longhand_from_id!(property, false);
declarations.read().get(PropertyDeclarationId::Longhand(long)).is_some() let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
declarations.read_with(&guard).get(PropertyDeclarationId::Longhand(long)).is_some()
} }
#[no_mangle] #[no_mangle]
@ -1037,12 +1093,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(declarations:
use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::{PropertyDeclaration, LonghandId};
use style::properties::longhands::_x_lang::computed_value::T as Lang; use style::properties::longhands::_x_lang::computed_value::T as Lang;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let prop = match_wrap_declared! { long, let prop = match_wrap_declared! { long,
XLang => Lang(Atom::from(value)), XLang => Lang(Atom::from(value)),
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1055,7 +1113,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations:
use style::properties::longhands; use style::properties::longhands;
use style::values::specified::{BorderStyle, NoCalcLength}; use style::values::specified::{BorderStyle, NoCalcLength};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let value = value as u32; let value = value as u32;
@ -1079,7 +1137,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations:
BorderBottomStyle => BorderStyle::from_gecko_keyword(value), BorderBottomStyle => BorderStyle::from_gecko_keyword(value),
BorderLeftStyle => BorderStyle::from_gecko_keyword(value), BorderLeftStyle => BorderStyle::from_gecko_keyword(value),
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1089,12 +1149,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIntValue(declarations: RawServoDecla
use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::{PropertyDeclaration, LonghandId};
use style::properties::longhands::_x_span::computed_value::T as Span; use style::properties::longhands::_x_span::computed_value::T as Span;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let prop = match_wrap_declared! { long, let prop = match_wrap_declared! { long,
XSpan => Span(value), XSpan => Span(value),
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1107,7 +1169,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
use style::values::specified::BorderWidth; use style::values::specified::BorderWidth;
use style::values::specified::length::NoCalcLength; use style::values::specified::length::NoCalcLength;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let nocalc = NoCalcLength::from_px(value); let nocalc = NoCalcLength::from_px(value);
@ -1133,7 +1195,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
} }
), ),
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1144,7 +1208,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations:
use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::{PropertyDeclaration, LonghandId};
use style::values::specified::length::Percentage; use style::values::specified::length::Percentage;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let pc = Percentage(value); let pc = Percentage(value);
@ -1156,7 +1220,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations:
MarginBottom => pc.into(), MarginBottom => pc.into(),
MarginLeft => pc.into(), MarginLeft => pc.into(),
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1166,7 +1232,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations:
use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::{PropertyDeclaration, LonghandId};
use style::values::specified::LengthOrPercentageOrAuto; use style::values::specified::LengthOrPercentageOrAuto;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let auto = LengthOrPercentageOrAuto::Auto; let auto = LengthOrPercentageOrAuto::Auto;
@ -1178,7 +1244,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations:
MarginBottom => auto, MarginBottom => auto,
MarginLeft => auto, MarginLeft => auto,
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1188,7 +1256,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::{PropertyDeclaration, LonghandId};
use style::values::specified::{Color, CSSColor}; use style::values::specified::{Color, CSSColor};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let cc = CSSColor { parsed: Color::CurrentColor, authored: None }; let cc = CSSColor { parsed: Color::CurrentColor, authored: None };
@ -1198,7 +1266,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
BorderBottomColor => cc, BorderBottomColor => cc,
BorderLeftColor => cc, BorderLeftColor => cc,
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1211,7 +1281,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
use style::properties::longhands; use style::properties::longhands;
use style::values::specified::{Color, CSSColor}; use style::values::specified::{Color, CSSColor};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property); let long = get_longhand_from_id!(property);
let rgba = convert_nscolor_to_rgba(value); let rgba = convert_nscolor_to_rgba(value);
let color = CSSColor { parsed: Color::RGBA(rgba), authored: None }; let color = CSSColor { parsed: Color::RGBA(rgba), authored: None };
@ -1224,7 +1294,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
Color => longhands::color::SpecifiedValue(color), Color => longhands::color::SpecifiedValue(color),
BackgroundColor => color, BackgroundColor => color,
}; };
declarations.write().push(prop, Importance::Normal); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
declarations.write_with(&mut guard).push(prop, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1235,13 +1307,15 @@ pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations:
use style::properties::PropertyDeclaration; use style::properties::PropertyDeclaration;
use style::properties::longhands::font_family::SpecifiedValue as FontFamily; use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let string = unsafe { (*value).to_string() }; let string = unsafe { (*value).to_string() };
let mut parser = Parser::new(&string); let mut parser = Parser::new(&string);
if let Ok(family) = FontFamily::parse(&mut parser) { if let Ok(family) = FontFamily::parse(&mut parser) {
if parser.is_exhausted() { if parser.is_exhausted() {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let decl = PropertyDeclaration::FontFamily(family); let decl = PropertyDeclaration::FontFamily(family);
declarations.write().push(decl, Importance::Normal); declarations.write_with(&mut guard).push(decl, Importance::Normal);
} }
} }
} }
@ -1252,11 +1326,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarat
use style::properties::PropertyDeclaration; use style::properties::PropertyDeclaration;
use style::properties::longhands::text_decoration_line; use style::properties::longhands::text_decoration_line;
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let mut decoration = text_decoration_line::computed_value::none; let mut decoration = text_decoration_line::computed_value::none;
decoration |= text_decoration_line::COLOR_OVERRIDE; decoration |= text_decoration_line::COLOR_OVERRIDE;
let decl = PropertyDeclaration::TextDecorationLine(decoration); let decl = PropertyDeclaration::TextDecorationLine(decoration);
declarations.write().push(decl, Importance::Normal); declarations.write_with(&mut guard).push(decl, Importance::Normal);
} }
#[no_mangle] #[no_mangle]
@ -1357,8 +1434,10 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
pub extern "C" fn Servo_ImportRule_GetSheet(import_rule: pub extern "C" fn Servo_ImportRule_GetSheet(import_rule:
RawServoImportRuleBorrowed) RawServoImportRuleBorrowed)
-> RawServoStyleSheetStrong { -> RawServoStyleSheetStrong {
let import_rule = RwLock::<ImportRule>::as_arc(&import_rule); let global_style_data = &*GLOBAL_STYLE_DATA;
import_rule.read().stylesheet.clone().into_strong() let guard = global_style_data.shared_lock.read();
let import_rule = Locked::<ImportRule>::as_arc(&import_rule);
import_rule.read_with(&guard).stylesheet.clone().into_strong()
} }
#[no_mangle] #[no_mangle]
@ -1402,11 +1481,13 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
raw_data: RawServoStyleSetBorrowed) raw_data: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong -> ServoComputedValuesStrong
{ {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let element = GeckoElement(element); let element = GeckoElement(element);
let doc_data = PerDocumentStyleData::from_ffi(raw_data); let doc_data = PerDocumentStyleData::from_ffi(raw_data);
let finish = |styles: &ElementStyles| -> Arc<ComputedValues> { let finish = |styles: &ElementStyles| -> Arc<ComputedValues> {
let maybe_pseudo = if !pseudo_tag.is_null() { let maybe_pseudo = if !pseudo_tag.is_null() {
get_pseudo_style(element, pseudo_tag, styles, doc_data) get_pseudo_style(&guard, element, pseudo_tag, styles, doc_data)
} else { } else {
None None
}; };
@ -1422,7 +1503,7 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
} }
// We don't have the style ready. Go ahead and compute it as necessary. // We don't have the style ready. Go ahead and compute it as necessary.
let shared = create_shared_context(&mut doc_data.borrow_mut()); let shared = create_shared_context(&guard, &mut doc_data.borrow_mut());
let mut tlc = ThreadLocalStyleContext::new(&shared); let mut tlc = ThreadLocalStyleContext::new(&shared);
let mut context = StyleContext { let mut context = StyleContext {
shared: &shared, shared: &shared,
@ -1446,6 +1527,11 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
use style::properties::LonghandIdSet; use style::properties::LonghandIdSet;
use style::properties::declaration_block::Importance; use style::properties::declaration_block::Importance;
use style::values::computed::Context; use style::values::computed::Context;
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let style = ComputedValues::as_arc(&style); let style = ComputedValues::as_arc(&style);
@ -1472,8 +1558,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
.filter(|&property| !property.mServoDeclarationBlock.mRawPtr.is_null()); .filter(|&property| !property.mServoDeclarationBlock.mRawPtr.is_null());
for property in iter { for property in iter {
let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() }; let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations); let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let guard = declarations.read(); let guard = declarations.read_with(&guard);
let anim_iter = guard.declarations() let anim_iter = guard.declarations()
.iter() .iter()
@ -1537,15 +1623,18 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
use style::gecko_bindings::structs::Keyframe; use style::gecko_bindings::structs::Keyframe;
use style::properties::LonghandIdSet; use style::properties::LonghandIdSet;
let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) }; let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) };
let style_timing_function = unsafe { timing_function.as_ref().unwrap() }; let style_timing_function = unsafe { timing_function.as_ref().unwrap() };
let style = ComputedValues::as_arc(&style); let style = ComputedValues::as_arc(&style);
if let Some(ref animation) = data.stylist.animations().get(&name) { if let Some(ref animation) = data.stylist.animations().get(&name) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
for step in &animation.steps { for step in &animation.steps {
// Override timing_function if the keyframe has animation-timing-function. // Override timing_function if the keyframe has animation-timing-function.
let timing_function = if let Some(val) = step.get_animation_timing_function() { let timing_function = if let Some(val) = step.get_animation_timing_function(&guard) {
val.into() val.into()
} else { } else {
*style_timing_function *style_timing_function
@ -1560,7 +1649,8 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
fn add_computed_property_value(keyframe: *mut Keyframe, fn add_computed_property_value(keyframe: *mut Keyframe,
index: usize, index: usize,
style: &ComputedValues, style: &ComputedValues,
property: &TransitionProperty) { property: &TransitionProperty,
shared_lock: &SharedRwLock) {
let block = style.to_declaration_block(property.clone().into()); let block = style.to_declaration_block(property.clone().into());
unsafe { unsafe {
(*keyframe).mPropertyValues.set_len((index + 1) as u32); (*keyframe).mPropertyValues.set_len((index + 1) as u32);
@ -1568,18 +1658,19 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
// FIXME. Do not set computed values once we handles missing keyframes // FIXME. Do not set computed values once we handles missing keyframes
// with additive composition. // with additive composition.
(*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky(
Arc::new(RwLock::new(block))); Arc::new(shared_lock.wrap(block)));
} }
} }
match step.value { match step.value {
KeyframesStepValue::ComputedValues => { KeyframesStepValue::ComputedValues => {
for (index, property) in animation.properties_changed.iter().enumerate() { for (index, property) in animation.properties_changed.iter().enumerate() {
add_computed_property_value(keyframe, index, style, property); add_computed_property_value(
keyframe, index, style, property, &global_style_data.shared_lock);
} }
}, },
KeyframesStepValue::Declarations { ref block } => { KeyframesStepValue::Declarations { ref block } => {
let guard = block.read(); let guard = block.read_with(&guard);
// Filter out non-animatable properties. // Filter out non-animatable properties.
let animatable = let animatable =
guard.declarations() guard.declarations()
@ -1596,8 +1687,9 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
(*keyframe).mPropertyValues.set_len((index + 1) as u32); (*keyframe).mPropertyValues.set_len((index + 1) as u32);
(*keyframe).mPropertyValues[index].mProperty = property.into(); (*keyframe).mPropertyValues[index].mProperty = property.into();
(*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky(
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( Arc::new(global_style_data.shared_lock.wrap(
declaration.clone(), Importance::Normal PropertyDeclarationBlock::with_one(
declaration.clone(), Importance::Normal
)))); ))));
if step.start_percentage.0 == 0. || if step.start_percentage.0 == 0. ||
step.start_percentage.0 == 1. { step.start_percentage.0 == 1. {
@ -1612,7 +1704,8 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet
let mut index = unsafe { (*keyframe).mPropertyValues.len() }; let mut index = unsafe { (*keyframe).mPropertyValues.len() };
for property in animation.properties_changed.iter() { for property in animation.properties_changed.iter() {
if !seen.has_transition_property_bit(&property) { if !seen.has_transition_property_bit(&property) {
add_computed_property_value(keyframe, index, style, property); add_computed_property_value(
keyframe, index, style, property, &global_style_data.shared_lock);
index += 1; index += 1;
} }
} }

View file

@ -10,9 +10,7 @@ extern crate env_logger;
#[macro_use] extern crate lazy_static; #[macro_use] extern crate lazy_static;
extern crate libc; extern crate libc;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate num_cpus;
extern crate parking_lot; extern crate parking_lot;
extern crate rayon;
extern crate selectors; extern crate selectors;
extern crate servo_url; extern crate servo_url;
#[macro_use] extern crate style; #[macro_use] extern crate style;

View file

@ -2,11 +2,12 @@
* 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 parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
use style::gecko_bindings::structs::{Loader, ServoStyleSheet}; use style::gecko_bindings::structs::{Loader, ServoStyleSheet};
use style::gecko_bindings::sugar::ownership::HasArcFFI; use style::gecko_bindings::sugar::ownership::HasArcFFI;
use style::media_queries::MediaList;
use style::shared_lock::Locked;
use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader}; use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader};
use style_traits::ToCss; use style_traits::ToCss;
@ -19,11 +20,12 @@ impl StylesheetLoader {
} }
impl StyleStylesheetLoader for StylesheetLoader { impl StyleStylesheetLoader for StylesheetLoader {
fn request_stylesheet(&self, import_rule: &Arc<RwLock<ImportRule>>) { fn request_stylesheet(
let import = import_rule.read(); &self,
let (spec_bytes, spec_len) = import.url.as_slice_components() media: MediaList,
.expect("Import only loads valid URLs"); make_import: &mut FnMut(MediaList) -> ImportRule,
make_arc: &mut FnMut(ImportRule) -> Arc<Locked<ImportRule>>,
) -> Arc<Locked<ImportRule>> {
// TODO(emilio): We probably want to share media representation with // TODO(emilio): We probably want to share media representation with
// Gecko in Stylo. // Gecko in Stylo.
// //
@ -32,16 +34,27 @@ impl StyleStylesheetLoader for StylesheetLoader {
// evaluate them on the main thread. // evaluate them on the main thread.
// //
// Meanwhile, this works. // Meanwhile, this works.
let media = import.stylesheet.media.read().to_css_string(); let media_string = media.to_css_string();
let import = make_import(media);
// After we get this raw pointer ImportRule will be moved into a lock and Arc
// and so the Arc<Url> pointer inside will also move,
// but the Url it points to or the allocating backing the String inside that Url wont,
// so this raw pointer will still be valid.
let (spec_bytes, spec_len): (*const u8, usize) = import.url.as_slice_components()
.expect("Import only loads valid URLs");
let arc = make_arc(import);
unsafe { unsafe {
Gecko_LoadStyleSheet(self.0, Gecko_LoadStyleSheet(self.0,
self.1, self.1,
HasArcFFI::arc_as_borrowed(import_rule), HasArcFFI::arc_as_borrowed(&arc),
spec_bytes, spec_bytes,
spec_len as u32, spec_len as u32,
media.as_bytes().as_ptr(), media_string.as_bytes().as_ptr(),
media.len() as u32); media_string.len() as u32);
} }
arc
} }
} }

View file

@ -17,7 +17,6 @@ app_units = "0.4"
cssparser = "0.12" cssparser = "0.12"
euclid = "0.11" euclid = "0.11"
html5ever-atoms = "0.2" html5ever-atoms = "0.2"
owning_ref = "0.2.2"
parking_lot = "0.3" parking_lot = "0.3"
rayon = "0.6" rayon = "0.6"
rustc-serialize = "0.3" rustc-serialize = "0.3"

View file

@ -2,18 +2,19 @@
* 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 parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage, KeyframeSelector}; use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage, KeyframeSelector};
use style::keyframes::{KeyframesStep, KeyframesStepValue}; use style::keyframes::{KeyframesStep, KeyframesStepValue};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, Importance}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, Importance};
use style::properties::animated_properties::TransitionProperty; use style::properties::animated_properties::TransitionProperty;
use style::shared_lock::SharedRwLock;
use style::values::specified::{LengthOrPercentageOrAuto, NoCalcLength}; use style::values::specified::{LengthOrPercentageOrAuto, NoCalcLength};
#[test] #[test]
fn test_empty_keyframe() { fn test_empty_keyframe() {
let shared_lock = SharedRwLock::new();
let keyframes = vec![]; let keyframes = vec![];
let animation = KeyframesAnimation::from_keyframes(&keyframes); let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation { let expected = KeyframesAnimation {
steps: vec![], steps: vec![],
properties_changed: vec![], properties_changed: vec![],
@ -24,13 +25,14 @@ fn test_empty_keyframe() {
#[test] #[test]
fn test_no_property_in_keyframe() { fn test_no_property_in_keyframe() {
let shared_lock = SharedRwLock::new();
let keyframes = vec![ let keyframes = vec![
Arc::new(RwLock::new(Keyframe { Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]), selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
block: Arc::new(RwLock::new(PropertyDeclarationBlock::new())) block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new()))
})), })),
]; ];
let animation = KeyframesAnimation::from_keyframes(&keyframes); let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation { let expected = KeyframesAnimation {
steps: vec![], steps: vec![],
properties_changed: vec![], properties_changed: vec![],
@ -41,15 +43,16 @@ fn test_no_property_in_keyframe() {
#[test] #[test]
fn test_missing_property_in_initial_keyframe() { fn test_missing_property_in_initial_keyframe() {
let shared_lock = SharedRwLock::new();
let declarations_on_initial_keyframe = let declarations_on_initial_keyframe =
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Width( PropertyDeclaration::Width(
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))), LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
Importance::Normal Importance::Normal
))); )));
let declarations_on_final_keyframe = let declarations_on_final_keyframe =
Arc::new(RwLock::new({ Arc::new(shared_lock.wrap({
let mut block = PropertyDeclarationBlock::new(); let mut block = PropertyDeclarationBlock::new();
block.push( block.push(
PropertyDeclaration::Width( PropertyDeclaration::Width(
@ -65,17 +68,17 @@ fn test_missing_property_in_initial_keyframe() {
})); }));
let keyframes = vec![ let keyframes = vec![
Arc::new(RwLock::new(Keyframe { Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
block: declarations_on_initial_keyframe.clone(), block: declarations_on_initial_keyframe.clone(),
})), })),
Arc::new(RwLock::new(Keyframe { Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]), selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
block: declarations_on_final_keyframe.clone(), block: declarations_on_final_keyframe.clone(),
})), })),
]; ];
let animation = KeyframesAnimation::from_keyframes(&keyframes); let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation { let expected = KeyframesAnimation {
steps: vec![ steps: vec![
KeyframesStep { KeyframesStep {
@ -97,8 +100,9 @@ fn test_missing_property_in_initial_keyframe() {
#[test] #[test]
fn test_missing_property_in_final_keyframe() { fn test_missing_property_in_final_keyframe() {
let shared_lock = SharedRwLock::new();
let declarations_on_initial_keyframe = let declarations_on_initial_keyframe =
Arc::new(RwLock::new({ Arc::new(shared_lock.wrap({
let mut block = PropertyDeclarationBlock::new(); let mut block = PropertyDeclarationBlock::new();
block.push( block.push(
PropertyDeclaration::Width( PropertyDeclaration::Width(
@ -114,24 +118,24 @@ fn test_missing_property_in_final_keyframe() {
})); }));
let declarations_on_final_keyframe = let declarations_on_final_keyframe =
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Height( PropertyDeclaration::Height(
LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))), LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))),
Importance::Normal, Importance::Normal,
))); )));
let keyframes = vec![ let keyframes = vec![
Arc::new(RwLock::new(Keyframe { Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
block: declarations_on_initial_keyframe.clone(), block: declarations_on_initial_keyframe.clone(),
})), })),
Arc::new(RwLock::new(Keyframe { Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]), selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(1.)]),
block: declarations_on_final_keyframe.clone(), block: declarations_on_final_keyframe.clone(),
})), })),
]; ];
let animation = KeyframesAnimation::from_keyframes(&keyframes); let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation { let expected = KeyframesAnimation {
steps: vec![ steps: vec![
KeyframesStep { KeyframesStep {
@ -153,8 +157,9 @@ fn test_missing_property_in_final_keyframe() {
#[test] #[test]
fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() {
let shared_lock = SharedRwLock::new();
let declarations = let declarations =
Arc::new(RwLock::new({ Arc::new(shared_lock.wrap({
let mut block = PropertyDeclarationBlock::new(); let mut block = PropertyDeclarationBlock::new();
block.push( block.push(
PropertyDeclaration::Width( PropertyDeclaration::Width(
@ -170,22 +175,22 @@ fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() {
})); }));
let keyframes = vec![ let keyframes = vec![
Arc::new(RwLock::new(Keyframe { Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]),
block: Arc::new(RwLock::new(PropertyDeclarationBlock::new())) block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::new()))
})), })),
Arc::new(RwLock::new(Keyframe { Arc::new(shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.5)]), selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.5)]),
block: declarations.clone(), block: declarations.clone(),
})), })),
]; ];
let animation = KeyframesAnimation::from_keyframes(&keyframes); let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read());
let expected = KeyframesAnimation { let expected = KeyframesAnimation {
steps: vec![ steps: vec![
KeyframesStep { KeyframesStep {
start_percentage: KeyframePercentage(0.), start_percentage: KeyframePercentage(0.),
value: KeyframesStepValue::Declarations { value: KeyframesStepValue::Declarations {
block: Arc::new(RwLock::new( block: Arc::new(shared_lock.wrap(
// XXX: Should we use ComputedValues in this case? // XXX: Should we use ComputedValues in this case?
PropertyDeclarationBlock::new() PropertyDeclarationBlock::new()
)) ))

View file

@ -9,7 +9,6 @@ extern crate app_units;
extern crate cssparser; extern crate cssparser;
extern crate euclid; extern crate euclid;
#[macro_use] extern crate html5ever_atoms; #[macro_use] extern crate html5ever_atoms;
extern crate owning_ref;
extern crate parking_lot; extern crate parking_lot;
extern crate rayon; extern crate rayon;
extern crate rustc_serialize; extern crate rustc_serialize;
@ -26,7 +25,6 @@ mod attr;
mod keyframes; mod keyframes;
mod logical_geometry; mod logical_geometry;
mod media_queries; mod media_queries;
mod owning_handle;
mod parsing; mod parsing;
mod properties; mod properties;
mod rule_tree; mod rule_tree;

View file

@ -11,6 +11,7 @@ use style::error_reporting::ParseErrorReporter;
use style::media_queries::*; use style::media_queries::*;
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::servo::media_queries::*; use style::servo::media_queries::*;
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
use style::stylesheets::{Stylesheet, Origin, CssRule}; use style::stylesheets::{Stylesheet, Origin, CssRule};
use style::values::specified; use style::values::specified;
use style_traits::ToCss; use style_traits::ToCss;
@ -29,26 +30,27 @@ fn test_media_rule<F>(css: &str, callback: F)
let url = ServoUrl::parse("http://localhost").unwrap(); let url = ServoUrl::parse("http://localhost").unwrap();
let css_str = css.to_owned(); let css_str = css.to_owned();
let stylesheet = Stylesheet::from_str( let stylesheet = Stylesheet::from_str(
css, url, Origin::Author, Default::default(), css, url, Origin::Author, Default::default(), SharedRwLock::new(),
None, &CSSErrorReporterTest, None, &CSSErrorReporterTest,
ParserContextExtraData::default()); ParserContextExtraData::default());
let mut rule_count = 0; let mut rule_count = 0;
media_queries(&stylesheet.rules.read().0, &mut |mq| { let guard = stylesheet.shared_lock.read();
media_queries(&guard, &stylesheet.rules.read_with(&guard).0, &mut |mq| {
rule_count += 1; rule_count += 1;
callback(mq, css); callback(mq, css);
}); });
assert!(rule_count > 0, css_str); assert!(rule_count > 0, css_str);
} }
fn media_queries<F>(rules: &[CssRule], f: &mut F) fn media_queries<F>(guard: &SharedRwLockReadGuard, rules: &[CssRule], f: &mut F)
where F: FnMut(&MediaList), where F: FnMut(&MediaList),
{ {
for rule in rules { for rule in rules {
rule.with_nested_rules_and_mq(|rules, mq| { rule.with_nested_rules_and_mq(guard, |rules, mq| {
if let Some(mq) = mq { if let Some(mq) = mq {
f(mq) f(mq)
} }
media_queries(rules, f) media_queries(guard, rules, f)
}) })
} }
} }
@ -56,11 +58,11 @@ fn media_queries<F>(rules: &[CssRule], f: &mut F)
fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) { fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) {
let url = ServoUrl::parse("http://localhost").unwrap(); let url = ServoUrl::parse("http://localhost").unwrap();
let ss = Stylesheet::from_str( let ss = Stylesheet::from_str(
css, url, Origin::Author, Default::default(), css, url, Origin::Author, Default::default(), SharedRwLock::new(),
None, &CSSErrorReporterTest, None, &CSSErrorReporterTest,
ParserContextExtraData::default()); ParserContextExtraData::default());
let mut rule_count = 0; let mut rule_count = 0;
ss.effective_style_rules(device, |_| rule_count += 1); ss.effective_style_rules(device, &ss.shared_lock.read(), |_| rule_count += 1);
assert!(rule_count == expected_rule_count, css.to_owned()); assert!(rule_count == expected_rule_count, css.to_owned());
} }

View file

@ -1,34 +0,0 @@
/* 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 owning_ref::RcRef;
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
use style::owning_handle::OwningHandle;
#[test]
fn owning_handle() {
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
let mut handle = OwningHandle::new(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
assert_eq!(*handle, 2);
*handle = 3;
assert_eq!(*handle, 3);
}
#[test]
fn nested() {
let result = {
let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
let curr = RcRef::new(complex);
let curr = OwningHandle::new(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
let mut curr = OwningHandle::new(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
assert_eq!(*curr, "someString");
*curr = "someOtherString";
curr
};
assert_eq!(*result, "someOtherString");
}

View file

@ -3,7 +3,6 @@
* 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 cssparser::{Parser, SourcePosition}; use cssparser::{Parser, SourcePosition};
use parking_lot::RwLock;
use rayon; use rayon;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::sync::Arc; use std::sync::Arc;
@ -12,6 +11,7 @@ use style::media_queries::MediaList;
use style::parser::ParserContextExtraData; use style::parser::ParserContextExtraData;
use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock}; use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock};
use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use style::shared_lock::SharedRwLock;
use style::stylesheets::{Origin, Stylesheet, CssRule}; use style::stylesheets::{Origin, Stylesheet, CssRule};
use test::{self, Bencher}; use test::{self, Bencher};
@ -44,10 +44,12 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
MediaList { MediaList {
media_queries: vec![], media_queries: vec![],
}, },
SharedRwLock::new(),
None, None,
&ErrorringErrorReporter, &ErrorringErrorReporter,
ParserContextExtraData {}); ParserContextExtraData {});
let rules = s.rules.read(); let guard = s.shared_lock.read();
let rules = s.rules.read_with(&guard);
rules.0.iter().filter_map(|rule| { rules.0.iter().filter_map(|rule| {
match *rule { match *rule {
CssRule::Style(ref style_rule) => Some(style_rule), CssRule::Style(ref style_rule) => Some(style_rule),
@ -62,9 +64,11 @@ fn test_insertion(rule_tree: &RuleTree, rules: Vec<(StyleSource, CascadeLevel)>)
rule_tree.insert_ordered_rules(rules.into_iter()) rule_tree.insert_ordered_rules(rules.into_iter())
} }
fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)]) -> StrongRuleNode { fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)],
shared_lock: &SharedRwLock)
-> StrongRuleNode {
let mut rules = rules.to_vec(); let mut rules = rules.to_vec();
rules.push((StyleSource::Declarations(Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( rules.push((StyleSource::Declarations(Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Display( PropertyDeclaration::Display(
longhands::display::SpecifiedValue::block), longhands::display::SpecifiedValue::block),
Importance::Normal Importance::Normal
@ -118,11 +122,12 @@ fn bench_expensive_insertion(b: &mut Bencher) {
.bar { height: 500px; } \ .bar { height: 500px; } \
.baz { display: block; }"); .baz { display: block; }");
let shared_lock = SharedRwLock::new();
b.iter(|| { b.iter(|| {
let _gc = AutoGCRuleTree::new(&r); let _gc = AutoGCRuleTree::new(&r);
for _ in 0..(4000 + 400) { for _ in 0..(4000 + 400) {
test::black_box(test_insertion_style_attribute(&r, &rules_matched)); test::black_box(test_insertion_style_attribute(&r, &rules_matched, &shared_lock));
} }
}); });
} }
@ -167,6 +172,7 @@ fn bench_expensive_insersion_parallel(b: &mut Bencher) {
.bar { height: 500px; } \ .bar { height: 500px; } \
.baz { display: block; }"); .baz { display: block; }");
let shared_lock = SharedRwLock::new();
b.iter(|| { b.iter(|| {
let _gc = AutoGCRuleTree::new(&r); let _gc = AutoGCRuleTree::new(&r);
@ -175,12 +181,14 @@ fn bench_expensive_insersion_parallel(b: &mut Bencher) {
s.spawn(|s| { s.spawn(|s| {
for _ in 0..1000 { for _ in 0..1000 {
test::black_box(test_insertion_style_attribute(&r, test::black_box(test_insertion_style_attribute(&r,
&rules_matched)); &rules_matched,
&shared_lock));
} }
s.spawn(|_| { s.spawn(|_| {
for _ in 0..100 { for _ in 0..100 {
test::black_box(test_insertion_style_attribute(&r, test::black_box(test_insertion_style_attribute(&r,
&rules_matched)); &rules_matched,
&shared_lock));
} }
}) })
}) })

View file

@ -20,6 +20,7 @@ use style::properties::Importance;
use style::properties::{CSSWideKeyword, DeclaredValueOwned, PropertyDeclaration, PropertyDeclarationBlock}; use style::properties::{CSSWideKeyword, DeclaredValueOwned, PropertyDeclaration, PropertyDeclarationBlock};
use style::properties::longhands; use style::properties::longhands;
use style::properties::longhands::animation_play_state; use style::properties::longhands::animation_play_state;
use style::shared_lock::SharedRwLock;
use style::stylesheets::{Origin, Namespaces}; use style::stylesheets::{Origin, Namespaces};
use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule}; use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule};
use style::values::specified::{LengthOrPercentageOrAuto, Percentage}; use style::values::specified::{LengthOrPercentageOrAuto, Percentage};
@ -62,24 +63,25 @@ fn test_parse_stylesheet() {
}"; }";
let url = ServoUrl::parse("about::test").unwrap(); let url = ServoUrl::parse("about::test").unwrap();
let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(), let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(),
None, SharedRwLock::new(), None,
&CSSErrorReporterTest, &CSSErrorReporterTest,
ParserContextExtraData::default()); ParserContextExtraData::default());
let mut namespaces = Namespaces::default(); let mut namespaces = Namespaces::default();
namespaces.default = Some(ns!(html)); namespaces.default = Some(ns!(html));
let expected = Stylesheet { let expected = Stylesheet {
origin: Origin::UserAgent, origin: Origin::UserAgent,
media: Default::default(), media: Arc::new(stylesheet.shared_lock.wrap(Default::default())),
shared_lock: stylesheet.shared_lock.clone(),
namespaces: RwLock::new(namespaces), namespaces: RwLock::new(namespaces),
base_url: url, base_url: url,
dirty_on_viewport_size_change: AtomicBool::new(false), dirty_on_viewport_size_change: AtomicBool::new(false),
disabled: AtomicBool::new(false), disabled: AtomicBool::new(false),
rules: CssRules::new(vec![ rules: CssRules::new(vec![
CssRule::Namespace(Arc::new(RwLock::new(NamespaceRule { CssRule::Namespace(Arc::new(stylesheet.shared_lock.wrap(NamespaceRule {
prefix: None, prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml") url: NsAtom::from("http://www.w3.org/1999/xhtml")
}))), }))),
CssRule::Style(Arc::new(RwLock::new(StyleRule { CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![ selectors: SelectorList(vec![
Selector { Selector {
complex_selector: Arc::new(ComplexSelector { complex_selector: Arc::new(ComplexSelector {
@ -107,7 +109,7 @@ fn test_parse_stylesheet() {
specificity: (0 << 20) + (1 << 10) + (1 << 0), specificity: (0 << 20) + (1 << 10) + (1 << 0),
}, },
]), ]),
block: Arc::new(RwLock::new(block_from(vec![ block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Display(longhands::display::SpecifiedValue::none), (PropertyDeclaration::Display(longhands::display::SpecifiedValue::none),
Importance::Important), Importance::Important),
(PropertyDeclaration::Custom(Atom::from("a"), (PropertyDeclaration::Custom(Atom::from("a"),
@ -115,7 +117,7 @@ fn test_parse_stylesheet() {
Importance::Important), Importance::Important),
]))), ]))),
}))), }))),
CssRule::Style(Arc::new(RwLock::new(StyleRule { CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![ selectors: SelectorList(vec![
Selector { Selector {
complex_selector: Arc::new(ComplexSelector { complex_selector: Arc::new(ComplexSelector {
@ -152,12 +154,12 @@ fn test_parse_stylesheet() {
specificity: (0 << 20) + (0 << 10) + (1 << 0), specificity: (0 << 20) + (0 << 10) + (1 << 0),
}, },
]), ]),
block: Arc::new(RwLock::new(block_from(vec![ block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Display(longhands::display::SpecifiedValue::block), (PropertyDeclaration::Display(longhands::display::SpecifiedValue::block),
Importance::Normal), Importance::Normal),
]))), ]))),
}))), }))),
CssRule::Style(Arc::new(RwLock::new(StyleRule { CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![ selectors: SelectorList(vec![
Selector { Selector {
complex_selector: Arc::new(ComplexSelector { complex_selector: Arc::new(ComplexSelector {
@ -183,7 +185,7 @@ fn test_parse_stylesheet() {
specificity: (1 << 20) + (1 << 10) + (0 << 0), specificity: (1 << 20) + (1 << 10) + (0 << 0),
}, },
]), ]),
block: Arc::new(RwLock::new(block_from(vec![ block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::BackgroundColor( (PropertyDeclaration::BackgroundColor(
longhands::background_color::SpecifiedValue { longhands::background_color::SpecifiedValue {
authored: Some("blue".to_owned().into_boxed_str()), authored: Some("blue".to_owned().into_boxed_str()),
@ -233,22 +235,22 @@ fn test_parse_stylesheet() {
Importance::Normal), Importance::Normal),
]))), ]))),
}))), }))),
CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule { CssRule::Keyframes(Arc::new(stylesheet.shared_lock.wrap(KeyframesRule {
name: "foo".into(), name: "foo".into(),
keyframes: vec![ keyframes: vec![
Arc::new(RwLock::new(Keyframe { Arc::new(stylesheet.shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing( selector: KeyframeSelector::new_for_unit_testing(
vec![KeyframePercentage::new(0.)]), vec![KeyframePercentage::new(0.)]),
block: Arc::new(RwLock::new(block_from(vec![ block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Width( (PropertyDeclaration::Width(
LengthOrPercentageOrAuto::Percentage(Percentage(0.))), LengthOrPercentageOrAuto::Percentage(Percentage(0.))),
Importance::Normal), Importance::Normal),
]))) ])))
})), })),
Arc::new(RwLock::new(Keyframe { Arc::new(stylesheet.shared_lock.wrap(Keyframe {
selector: KeyframeSelector::new_for_unit_testing( selector: KeyframeSelector::new_for_unit_testing(
vec![KeyframePercentage::new(1.)]), vec![KeyframePercentage::new(1.)]),
block: Arc::new(RwLock::new(block_from(vec![ block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::Width( (PropertyDeclaration::Width(
LengthOrPercentageOrAuto::Percentage(Percentage(1.))), LengthOrPercentageOrAuto::Percentage(Percentage(1.))),
Importance::Normal), Importance::Normal),
@ -261,7 +263,7 @@ fn test_parse_stylesheet() {
] ]
}))) })))
]), ], &stylesheet.shared_lock),
}; };
assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected)); assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected));
@ -324,7 +326,7 @@ fn test_report_error_stylesheet() {
let errors = error_reporter.errors.clone(); let errors = error_reporter.errors.clone();
Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(), Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(),
None, SharedRwLock::new(), None,
&error_reporter, &error_reporter,
ParserContextExtraData::default()); ParserContextExtraData::default());

View file

@ -3,7 +3,6 @@
* 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 html5ever_atoms::LocalName; use html5ever_atoms::LocalName;
use parking_lot::RwLock;
use selectors::parser::LocalName as LocalNameSelector; use selectors::parser::LocalName as LocalNameSelector;
use servo_atoms::Atom; use servo_atoms::Atom;
use std::sync::Arc; use std::sync::Arc;
@ -11,40 +10,43 @@ use style::properties::{PropertyDeclarationBlock, PropertyDeclaration};
use style::properties::{longhands, Importance}; use style::properties::{longhands, Importance};
use style::rule_tree::CascadeLevel; use style::rule_tree::CascadeLevel;
use style::selector_parser::SelectorParser; use style::selector_parser::SelectorParser;
use style::shared_lock::SharedRwLock;
use style::stylesheets::StyleRule; use style::stylesheets::StyleRule;
use style::stylist::{Rule, SelectorMap}; use style::stylist::{Rule, SelectorMap};
use style::thread_state; use style::thread_state;
/// Helper method to get some Rules from selector strings. /// Helper method to get some Rules from selector strings.
/// Each sublist of the result contains the Rules for one StyleRule. /// Each sublist of the result contains the Rules for one StyleRule.
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> { fn get_mock_rules(css_selectors: &[&str]) -> (Vec<Vec<Rule>>, SharedRwLock) {
css_selectors.iter().enumerate().map(|(i, selectors)| { let shared_lock = SharedRwLock::new();
(css_selectors.iter().enumerate().map(|(i, selectors)| {
let selectors = SelectorParser::parse_author_origin_no_namespace(selectors).unwrap(); let selectors = SelectorParser::parse_author_origin_no_namespace(selectors).unwrap();
let rule = Arc::new(RwLock::new(StyleRule { let locked = Arc::new(shared_lock.wrap(StyleRule {
selectors: selectors, selectors: selectors,
block: Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one(
PropertyDeclaration::Display( PropertyDeclaration::Display(
longhands::display::SpecifiedValue::block), longhands::display::SpecifiedValue::block),
Importance::Normal Importance::Normal
))), ))),
})); }));
let guard = rule.read(); let guard = shared_lock.read();
guard.selectors.0.iter().map(|s| { let rule = locked.read_with(&guard);
rule.selectors.0.iter().map(|s| {
Rule { Rule {
selector: s.complex_selector.clone(), selector: s.complex_selector.clone(),
style_rule: rule.clone(), style_rule: locked.clone(),
specificity: s.specificity, specificity: s.specificity,
source_order: i, source_order: i,
} }
}).collect() }).collect()
}).collect() }).collect(), shared_lock)
} }
fn get_mock_map(selectors: &[&str]) -> SelectorMap { fn get_mock_map(selectors: &[&str]) -> (SelectorMap, SharedRwLock) {
let mut map = SelectorMap::new(); let mut map = SelectorMap::new();
let selector_rules = get_mock_rules(selectors); let (selector_rules, shared_lock) = get_mock_rules(selectors);
for rules in selector_rules.into_iter() { for rules in selector_rules.into_iter() {
for rule in rules.into_iter() { for rule in rules.into_iter() {
@ -52,12 +54,12 @@ fn get_mock_map(selectors: &[&str]) -> SelectorMap {
} }
} }
map (map, shared_lock)
} }
#[test] #[test]
fn test_rule_ordering_same_specificity() { fn test_rule_ordering_same_specificity() {
let rules_list = get_mock_rules(&["a.intro", "img.sidebar"]); let (rules_list, _) = get_mock_rules(&["a.intro", "img.sidebar"]);
let a = &rules_list[0][0]; let a = &rules_list[0][0];
let b = &rules_list[1][0]; let b = &rules_list[1][0];
assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)), assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)),
@ -67,21 +69,21 @@ fn test_rule_ordering_same_specificity() {
#[test] #[test]
fn test_get_id_name() { fn test_get_id_name() {
let rules_list = get_mock_rules(&[".intro", "#top"]); let (rules_list, _) = get_mock_rules(&[".intro", "#top"]);
assert_eq!(SelectorMap::get_id_name(&rules_list[0][0]), None); assert_eq!(SelectorMap::get_id_name(&rules_list[0][0]), None);
assert_eq!(SelectorMap::get_id_name(&rules_list[1][0]), Some(Atom::from("top"))); assert_eq!(SelectorMap::get_id_name(&rules_list[1][0]), Some(Atom::from("top")));
} }
#[test] #[test]
fn test_get_class_name() { fn test_get_class_name() {
let rules_list = get_mock_rules(&[".intro.foo", "#top"]); let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro"))); assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro")));
assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None); assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None);
} }
#[test] #[test]
fn test_get_local_name() { fn test_get_local_name() {
let rules_list = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]); let (rules_list, _) = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]);
let check = |i: usize, names: Option<(&str, &str)>| { let check = |i: usize, names: Option<(&str, &str)>| {
assert!(SelectorMap::get_local_name(&rules_list[i][0]) assert!(SelectorMap::get_local_name(&rules_list[i][0])
== names.map(|(name, lower_name)| LocalNameSelector { == names.map(|(name, lower_name)| LocalNameSelector {
@ -96,7 +98,7 @@ fn test_get_local_name() {
#[test] #[test]
fn test_insert() { fn test_insert() {
let rules_list = get_mock_rules(&[".intro.foo", "#top"]); let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
let mut selector_map = SelectorMap::new(); let mut selector_map = SelectorMap::new();
selector_map.insert(rules_list[1][0].clone()); selector_map.insert(rules_list[1][0].clone());
assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order); assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order);
@ -108,10 +110,11 @@ fn test_insert() {
#[test] #[test]
fn test_get_universal_rules() { fn test_get_universal_rules() {
thread_state::initialize(thread_state::LAYOUT); thread_state::initialize(thread_state::LAYOUT);
let map = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]); let (map, shared_lock) = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]);
let decls = map.get_universal_rules(CascadeLevel::UserNormal, let guard = shared_lock.read();
CascadeLevel::UserImportant); let decls = map.get_universal_rules(
&guard, CascadeLevel::UserNormal, CascadeLevel::UserImportant);
assert_eq!(decls.len(), 1); assert_eq!(decls.len(), 1);
} }

View file

@ -9,6 +9,7 @@ use servo_config::prefs::{PREFS, PrefValue};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use style::media_queries::{Device, MediaType}; use style::media_queries::{Device, MediaType};
use style::parser::{ParserContext, ParserContextExtraData}; use style::parser::{ParserContext, ParserContextExtraData};
use style::shared_lock::SharedRwLock;
use style::stylesheets::{Stylesheet, Origin}; use style::stylesheets::{Stylesheet, Origin};
use style::values::specified::LengthOrPercentageOrAuto::{self, Auto}; use style::values::specified::LengthOrPercentageOrAuto::{self, Auto};
use style::values::specified::NoCalcLength::{self, ViewportPercentage}; use style::values::specified::NoCalcLength::{self, ViewportPercentage};
@ -19,11 +20,15 @@ use style_traits::viewport::*;
macro_rules! stylesheet { macro_rules! stylesheet {
($css:expr, $origin:ident, $error_reporter:expr) => { ($css:expr, $origin:ident, $error_reporter:expr) => {
stylesheet!($css, $origin, $error_reporter, SharedRwLock::new())
};
($css:expr, $origin:ident, $error_reporter:expr, $shared_lock:expr) => {
Box::new(Stylesheet::from_str( Box::new(Stylesheet::from_str(
$css, $css,
ServoUrl::parse("http://localhost").unwrap(), ServoUrl::parse("http://localhost").unwrap(),
Origin::$origin, Origin::$origin,
Default::default(), Default::default(),
$shared_lock,
None, None,
&$error_reporter, &$error_reporter,
ParserContextExtraData::default() ParserContextExtraData::default()
@ -39,7 +44,7 @@ fn test_viewport_rule<F>(css: &str,
PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
let stylesheet = stylesheet!(css, Author, CSSErrorReporterTest); let stylesheet = stylesheet!(css, Author, CSSErrorReporterTest);
let mut rule_count = 0; let mut rule_count = 0;
stylesheet.effective_viewport_rules(&device, |rule| { stylesheet.effective_viewport_rules(&device, &stylesheet.shared_lock.read(), |rule| {
rule_count += 1; rule_count += 1;
callback(&rule.declarations, css); callback(&rule.declarations, css);
}); });
@ -251,24 +256,31 @@ fn multiple_stylesheets_cascading() {
PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.)); let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.));
let error_reporter = CSSErrorReporterTest; let error_reporter = CSSErrorReporterTest;
let shared_lock = SharedRwLock::new();
let stylesheets = vec![ let stylesheets = vec![
stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", UserAgent, error_reporter), stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }",
stylesheet!("@viewport { min-width: 200px; min-height: 200px; }", User, error_reporter), UserAgent, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 300px; }", Author, error_reporter)]; stylesheet!("@viewport { min-width: 200px; min-height: 200px; }",
User, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 300px; }",
Author, error_reporter, shared_lock.clone())
];
let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish(); let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish();
assert_decl_len!(declarations == 3); assert_decl_len!(declarations == 3);
assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.)); assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.));
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px)); assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px));
assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px)); assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px));
let stylesheets = vec![ let stylesheets = vec![
stylesheet!("@viewport { min-width: 100px !important; }", UserAgent, error_reporter), stylesheet!("@viewport { min-width: 100px !important; }",
UserAgent, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 200px !important; min-height: 200px !important; }", stylesheet!("@viewport { min-width: 200px !important; min-height: 200px !important; }",
User, error_reporter), User, error_reporter, shared_lock.clone()),
stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }", stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }",
Author, error_reporter)]; Author, error_reporter, shared_lock.clone())
let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish(); ];
let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish();
assert_decl_len!(declarations == 3); assert_decl_len!(declarations == 3);
assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important); assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important);
assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important); assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important);

View file

@ -21,8 +21,5 @@ extern crate style_traits;
mod sanity_checks; mod sanity_checks;
mod size_of; mod size_of;
#[path = "../../../ports/geckolib/stylesheet_loader.rs"]
mod stylesheet_loader;
mod servo_function_signatures; mod servo_function_signatures;

View file

@ -10,6 +10,9 @@ use style::gecko_properties::*;
include!(concat!(env!("OUT_DIR"), "/check_bindings.rs")); include!(concat!(env!("OUT_DIR"), "/check_bindings.rs"));
#[path = "../../../ports/geckolib/stylesheet_loader.rs"]
mod stylesheet_loader;
#[allow(non_snake_case, unused_unsafe, private_no_mangle_fns)] #[allow(non_snake_case, unused_unsafe, private_no_mangle_fns)]
mod glue { mod glue {
// this module pretends to be glue.rs, with the safe functions swapped for unsafe ones. This is // this module pretends to be glue.rs, with the safe functions swapped for unsafe ones. This is