diff --git a/Cargo.lock b/Cargo.lock index d8bf220c648..72065507be0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -928,9 +928,7 @@ dependencies = [ "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)", "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)", - "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.18.0", "servo_url 0.0.1", "style 0.0.1", @@ -2756,8 +2754,8 @@ dependencies = [ "nsstring_vendor 0.1.0", "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_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)", - "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)", "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)", @@ -2783,7 +2781,6 @@ dependencies = [ "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)", "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)", "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)", diff --git a/components/layout/block.rs b/components/layout/block.rs index 4bfef78cb3d..31f44f0ec0e 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -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 /// 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> { #[inline] diff --git a/components/layout/construct.rs b/components/layout/construct.rs index a6571d0e093..00cd46a079a 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -311,7 +311,7 @@ impl InlineFragmentsAccumulator { /// An object that knows how to create flows. pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> { /// 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 /// the ensuing impl {} by removing the need to parameterize all the methods individually. phantom2: PhantomData, @@ -320,7 +320,7 @@ pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> { impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> FlowConstructor<'a, ConcreteThreadSafeLayoutNode> { /// Creates a new flow constructor. - pub fn new(layout_context: &'a LayoutContext) -> Self { + pub fn new(layout_context: &'a LayoutContext<'a>) -> Self { FlowConstructor { layout_context: layout_context, phantom2: PhantomData, @@ -660,10 +660,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> let mut style = node.style(self.style_context()); if node_is_input_or_text_area { - style = self.style_context() - .stylist - .style_for_anonymous_box(&PseudoElement::ServoInputText, - &style) + let context = self.style_context(); + style = context.stylist.style_for_anonymous_box( + &context.guards, &PseudoElement::ServoInputText, &style) } self.create_fragments_for_node_text_content(&mut initial_fragments, node, &style) @@ -1096,11 +1095,14 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> -> ConstructionResult { let mut legalizer = Legalizer::new(); - let table_style = node.style(self.style_context()); - let wrapper_style = self.style_context() - .stylist - .style_for_anonymous_box(&PseudoElement::ServoTableWrapper, - &table_style); + let table_style; + let wrapper_style; + { + let context = self.style_context(); + table_style = node.style(context); + wrapper_style = context.stylist.style_for_anonymous_box( + &context.guards, &PseudoElement::ServoTableWrapper, &table_style); + } let wrapper_fragment = Fragment::from_opaque_node_and_style(node.opaque(), PseudoElementType::Normal, @@ -2080,8 +2082,7 @@ impl Legalizer { let reference_block = reference.as_block(); let mut new_style = reference_block.fragment.style.clone(); for pseudo in pseudos { - new_style = context.stylist.style_for_anonymous_box(pseudo, - &new_style) + new_style = context.stylist.style_for_anonymous_box(&context.guards, pseudo, &new_style) } let fragment = reference_block.fragment .create_similar_anonymous_fragment(new_style, diff --git a/components/layout/context.rs b/components/layout/context.rs index 1dff9f6ea5e..e2ffeb1cbd9 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -75,9 +75,9 @@ pub fn heap_size_of_persistent_local_context() -> usize { } /// 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. - pub style_context: SharedStyleContext, + pub style_context: SharedStyleContext<'a>, /// The shared image cache thread. pub image_cache_thread: Mutex, @@ -95,7 +95,7 @@ pub struct LayoutContext { pub pending_images: Option>> } -impl Drop for LayoutContext { +impl<'a> Drop for LayoutContext<'a> { fn drop(&mut self) { if !thread::panicking() { 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)] pub fn shared_context(&self) -> &SharedStyleContext { &self.style_context diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index ab3636fdbc5..2ee9985cf0e 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -121,7 +121,7 @@ fn get_cyclic(arr: &[T], index: usize) -> &T { } pub struct DisplayListBuildState<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, pub root_stacking_context: StackingContext, pub items: HashMap>, pub stacking_context_children: HashMap>, diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index ef2e270c064..887562e89fb 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -97,7 +97,7 @@ static KATAKANA_IROHA: [char; 47] = [ /// The generated content resolution traversal. pub struct ResolveGeneratedContent<'a> { /// The layout context. - layout_context: &'a LayoutContext, + layout_context: &'a LayoutContext<'a>, /// The counter representing an ordered list item. list_item: Counter, /// Named CSS counters. diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 0088ef208f3..3c0c1763d0c 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -22,20 +22,20 @@ use style::traversal::PerLevelTraversalData; use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData}; use wrapper::ThreadSafeLayoutNodeHelpers; -pub struct RecalcStyleAndConstructFlows { - context: LayoutContext, +pub struct RecalcStyleAndConstructFlows<'a> { + context: LayoutContext<'a>, driver: TraversalDriver, } -impl RecalcStyleAndConstructFlows { - pub fn layout_context(&self) -> &LayoutContext { +impl<'a> RecalcStyleAndConstructFlows<'a> { + pub fn layout_context(&self) -> &LayoutContext<'a> { &self.context } } -impl RecalcStyleAndConstructFlows { +impl<'a> RecalcStyleAndConstructFlows<'a> { /// 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 { context: context, driver: driver, @@ -44,13 +44,13 @@ impl RecalcStyleAndConstructFlows { /// Consumes this traversal context, returning ownership of the shared layout /// context to the caller. - pub fn destroy(self) -> LayoutContext { + pub fn destroy(self) -> LayoutContext<'a> { self.context } } #[allow(unsafe_code)] -impl DomTraversal for RecalcStyleAndConstructFlows +impl<'a, E> DomTraversal for RecalcStyleAndConstructFlows<'a> where E: TElement, E::ConcreteNode: LayoutNode, { @@ -152,7 +152,7 @@ fn construct_flows_at(context: &LayoutContext, /// The bubble-inline-sizes traversal, the first part of layout computation. This computes /// preferred and intrinsic inline-sizes and bubbles them up the tree. pub struct BubbleISizes<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'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`. #[derive(Copy, Clone)] pub struct AssignISizes<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PreorderFlowTraversal for AssignISizes<'a> { @@ -191,7 +191,7 @@ impl<'a> PreorderFlowTraversal for AssignISizes<'a> { /// positions. In Gecko this corresponds to `Reflow`. #[derive(Copy, Clone)] pub struct AssignBSizes<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PostorderFlowTraversal for AssignBSizes<'a> { @@ -220,7 +220,7 @@ impl<'a> PostorderFlowTraversal for AssignBSizes<'a> { #[derive(Copy, Clone)] pub struct ComputeAbsolutePositions<'a> { - pub layout_context: &'a LayoutContext, + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> { diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 566d6e437cd..1ebee7b5ead 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -114,7 +114,9 @@ use style::error_reporting::StdoutErrorReporter; use style::logical_geometry::LogicalPoint; use style::media_queries::{Device, MediaType}; 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::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards}; use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets}; use style::stylist::Stylist; use style::thread_state; @@ -214,7 +216,7 @@ pub struct LayoutThread { WebRenderImageInfo, BuildHasherDefault>>>, - // Webrender interface. + /// Webrender interface. webrender_api: webrender_traits::RenderApi, /// 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, + guard: &SharedRwLockReadGuard, device: &Device, font_cache_thread: &FontCacheThread, font_cache_sender: &IpcSender<()>, outstanding_web_fonts_counter: &Arc) { if opts::get().load_webfonts_synchronously { 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(); font_cache_thread.add_web_font(font_face.family.clone(), effective_sources, @@ -358,7 +361,7 @@ fn add_font_face_rules(stylesheet: &Stylesheet, receiver.recv().unwrap(); }) } 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(); outstanding_web_fonts_counter.fetch_add(1, Ordering::SeqCst); font_cache_thread.add_web_font(font_face.family.clone(), @@ -406,8 +409,11 @@ impl LayoutThread { let stylist = Arc::new(Stylist::new(device)); 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, + &guard, &stylist.device, &font_cache_thread, &ipc_font_cache_sender, @@ -493,16 +499,18 @@ impl LayoutThread { } // Create a layout context for use in building display lists, hit testing, &c. - fn build_layout_context(&self, - rw_data: &LayoutThreadData, - request_images: bool) - -> LayoutContext { + fn build_layout_context<'a>(&self, + guards: StylesheetGuards<'a>, + rw_data: &LayoutThreadData, + request_images: bool) + -> LayoutContext<'a> { let thread_local_style_context_creation_data = ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone()); LayoutContext { style_context: SharedStyleContext { stylist: rw_data.stylist.clone(), + guards: guards, running_animations: self.running_animations.clone(), expired_animations: self.expired_animations.clone(), error_reporter: Box::new(self.error_reporter.clone()), @@ -730,8 +738,10 @@ impl LayoutThread { // GWTODO: Need to handle unloading web fonts. 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, + &guard, &rw_data.stylist.device, &self.font_cache_thread, &self.font_cache_sender, @@ -1009,8 +1019,11 @@ impl LayoutThread { Au::from_f32_px(initial_viewport.height)); // 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); - 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 = 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. - let needs_dirtying = Arc::get_mut(&mut rw_data.stylist).unwrap().update(&data.document_stylesheets, - Some(&*UA_STYLESHEETS), - data.stylesheets_changed); + let ua_stylesheets = &*UA_STYLESHEETS; + let ua_or_user_guard = ua_stylesheets.shared_lock.read(); + 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; if needs_dirtying { if let Some(mut d) = element.mutate_data() { @@ -1102,7 +1123,7 @@ impl LayoutThread { } // 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. :-( let traversal_driver = if self.parallel_flag && self.parallel_traversal.is_some() { @@ -1161,7 +1182,7 @@ impl LayoutThread { } 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. @@ -1330,7 +1351,13 @@ impl LayoutThread { 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() { // 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 { - fn parse_ua_stylesheet(filename: &'static str) -> Result { + fn parse_ua_stylesheet(shared_lock: &SharedRwLock, filename: &'static str) + -> Result { let res = try!(read_resource_file(filename).map_err(|_| filename)); Ok(Stylesheet::from_bytes( &res, @@ -1537,26 +1565,29 @@ fn get_ua_stylesheets() -> Result { None, Origin::UserAgent, Default::default(), + shared_lock.clone(), None, &StdoutErrorReporter, ParserContextExtraData::default())) } + let shared_lock = SharedRwLock::new(); let mut user_or_user_agent_stylesheets = vec!(); // FIXME: presentational-hints.css should be at author origin with zero specificity. // (Does it make a difference?) 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 { user_or_user_agent_stylesheets.push(Stylesheet::from_bytes( &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 { + shared_lock: shared_lock, user_or_user_agent_stylesheets: user_or_user_agent_stylesheets, quirks_mode_stylesheet: quirks_mode_stylesheet, }) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 4d38b39d333..ee90766b1e2 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -99,6 +99,7 @@ use style::keyframes::Keyframe; use style::media_queries::MediaList; use style::properties::PropertyDeclarationBlock; 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::SupportsRule; use style::values::specified::Length; @@ -360,6 +361,7 @@ unsafe_no_jsmanaged_fields!(HttpsState); unsafe_no_jsmanaged_fields!(Request); unsafe_no_jsmanaged_fields!(RequestInit); unsafe_no_jsmanaged_fields!(SharedRt); +unsafe_no_jsmanaged_fields!(StyleSharedRwLock); unsafe_no_jsmanaged_fields!(TouchpadPressurePhase); unsafe_no_jsmanaged_fields!(USVString); unsafe_no_jsmanaged_fields!(ReferrerPolicy); @@ -500,67 +502,67 @@ unsafe impl JSTraceable for Mutex> { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } @@ -572,7 +574,7 @@ unsafe impl JSTraceable for RwLock { } } -unsafe impl JSTraceable for RwLock { +unsafe impl JSTraceable for StyleLocked { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. } diff --git a/components/script/dom/cssconditionrule.rs b/components/script/dom/cssconditionrule.rs index 02c52bcf28f..8bf5dad6c93 100644 --- a/components/script/dom/cssconditionrule.rs +++ b/components/script/dom/cssconditionrule.rs @@ -10,8 +10,8 @@ use dom::cssmediarule::CSSMediaRule; use dom::cssstylesheet::CSSStyleSheet; use dom::csssupportsrule::CSSSupportsRule; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::{SharedRwLock, Locked}; use style::stylesheets::CssRules as StyleCssRules; #[dom_struct] @@ -21,12 +21,19 @@ pub struct CSSConditionRule { impl CSSConditionRule { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, - rules: Arc>) -> CSSConditionRule { + rules: Arc>) -> CSSConditionRule { CSSConditionRule { 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 { diff --git a/components/script/dom/cssfontfacerule.rs b/components/script/dom/cssfontfacerule.rs index b9ef949c1b7..184f6784afa 100644 --- a/components/script/dom/cssfontfacerule.rs +++ b/components/script/dom/cssfontfacerule.rs @@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::font_face::FontFaceRule; -use style_traits::ToCss; +use style::shared_lock::{Locked, ToCssWithGuard}; #[dom_struct] pub struct CSSFontFaceRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - fontfacerule: Arc>, + fontfacerule: Arc>, } impl CSSFontFaceRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, fontfacerule: Arc>) -> CSSFontFaceRule { CSSFontFaceRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -33,7 +32,7 @@ impl CSSFontFaceRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - fontfacerule: Arc>) -> Root { + fontfacerule: Arc>) -> Root { reflect_dom_object(box CSSFontFaceRule::new_inherited(parent_stylesheet, fontfacerule), window, CSSFontFaceRuleBinding::Wrap) @@ -47,6 +46,7 @@ impl SpecificCSSRule for CSSFontFaceRule { } 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() } } diff --git a/components/script/dom/cssgroupingrule.rs b/components/script/dom/cssgroupingrule.rs index ec608b2bc77..249aaccd42e 100644 --- a/components/script/dom/cssgroupingrule.rs +++ b/components/script/dom/cssgroupingrule.rs @@ -12,21 +12,21 @@ use dom::cssrule::CSSRule; use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::cssstylesheet::CSSStyleSheet; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::{SharedRwLock, Locked}; use style::stylesheets::CssRules as StyleCssRules; #[dom_struct] pub struct CSSGroupingRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - rules: Arc>, + rules: Arc>, rulelist: MutNullableJS, } impl CSSGroupingRule { pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, - rules: Arc>) -> CSSGroupingRule { + rules: Arc>) -> CSSGroupingRule { CSSGroupingRule { cssrule: CSSRule::new_inherited(parent_stylesheet), rules: rules, @@ -40,6 +40,14 @@ impl CSSGroupingRule { parent_stylesheet, 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 { diff --git a/components/script/dom/cssimportrule.rs b/components/script/dom/cssimportrule.rs index 6ef354ec43e..3c0eb7eb4aa 100644 --- a/components/script/dom/cssimportrule.rs +++ b/components/script/dom/cssimportrule.rs @@ -10,21 +10,20 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::ImportRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSImportRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - import_rule: Arc>, + import_rule: Arc>, } impl CSSImportRule { fn new_inherited(parent_stylesheet: &CSSStyleSheet, - import_rule: Arc>) + import_rule: Arc>) -> Self { CSSImportRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -35,7 +34,7 @@ impl CSSImportRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - import_rule: Arc>) -> Root { + import_rule: Arc>) -> Root { reflect_dom_object(box Self::new_inherited(parent_stylesheet, import_rule), window, CSSImportRuleBinding::Wrap) @@ -49,6 +48,7 @@ impl SpecificCSSRule for CSSImportRule { } 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() } } diff --git a/components/script/dom/csskeyframerule.rs b/components/script/dom/csskeyframerule.rs index 0f620bdc764..d36e8988e04 100644 --- a/components/script/dom/csskeyframerule.rs +++ b/components/script/dom/csskeyframerule.rs @@ -12,21 +12,20 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::keyframes::Keyframe; -use style_traits::ToCss; +use style::shared_lock::{Locked, ToCssWithGuard}; #[dom_struct] pub struct CSSKeyframeRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - keyframerule: Arc>, + keyframerule: Arc>, style_decl: MutNullableJS, } impl CSSKeyframeRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframerule: Arc>) -> CSSKeyframeRule { CSSKeyframeRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -37,7 +36,7 @@ impl CSSKeyframeRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - keyframerule: Arc>) -> Root { + keyframerule: Arc>) -> Root { reflect_dom_object(box CSSKeyframeRule::new_inherited(parent_stylesheet, keyframerule), window, CSSKeyframeRuleBinding::Wrap) @@ -48,11 +47,16 @@ impl CSSKeyframeRuleMethods for CSSKeyframeRule { // https://drafts.csswg.org/css-animations/#dom-csskeyframerule-style fn Style(&self) -> Root { self.style_decl.or_init(|| { - CSSStyleDeclaration::new(self.global().as_window(), - CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()), - self.keyframerule.read().block.clone()), - None, - CSSModificationAccess::ReadWrite) + let guard = self.cssrule.shared_lock().read(); + CSSStyleDeclaration::new( + self.global().as_window(), + CSSStyleOwner::CSSRule( + 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 { - self.keyframerule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.keyframerule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs index db0240bf9a2..288ae486d1d 100644 --- a/components/script/dom/csskeyframesrule.rs +++ b/components/script/dom/csskeyframesrule.rs @@ -16,24 +16,23 @@ use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use servo_atoms::Atom; use std::sync::Arc; use style::keyframes::{Keyframe, KeyframeSelector}; use style::parser::ParserContextExtraData; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::KeyframesRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSKeyframesRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - keyframesrule: Arc>, + keyframesrule: Arc>, rulelist: MutNullableJS, } impl CSSKeyframesRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, keyframesrule: Arc>) -> CSSKeyframesRule { CSSKeyframesRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -44,7 +43,7 @@ impl CSSKeyframesRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - keyframesrule: Arc>) -> Root { + keyframesrule: Arc>) -> Root { reflect_dom_object(box CSSKeyframesRule::new_inherited(parent_stylesheet, keyframesrule), window, CSSKeyframesRuleBinding::Wrap) @@ -63,11 +62,12 @@ impl CSSKeyframesRule { fn find_rule(&self, selector: &str) -> Option { let mut input = Parser::new(selector); if let Ok(sel) = KeyframeSelector::parse(&mut input) { + let guard = self.cssrule.shared_lock().read(); // This finds the *last* element matching a selector // because that's the rule that applies. Thus, rposition - self.keyframesrule.read() + self.keyframesrule.read_with(&guard) .keyframes.iter().rposition(|frame| { - frame.read().selector == sel + frame.read_with(&guard).selector == sel }) } else { None @@ -86,7 +86,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule { let rule = Keyframe::parse(&rule, self.cssrule.parent_stylesheet().style_stylesheet(), ParserContextExtraData::default()); 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(); } } @@ -107,7 +108,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule { // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-name 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 @@ -122,7 +124,8 @@ impl CSSKeyframesRuleMethods for CSSKeyframesRule { "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(()) } } @@ -134,7 +137,8 @@ impl SpecificCSSRule for CSSKeyframesRule { } 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) { diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index 31923cb29dd..2a07471679e 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -14,26 +14,27 @@ use dom::cssstylesheet::CSSStyleSheet; use dom::medialist::MediaList; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::media_queries::parse_media_query_list; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::MediaRule; use style_traits::ToCss; #[dom_struct] pub struct CSSMediaRule { - cssrule: CSSConditionRule, + cssconditionrule: CSSConditionRule, #[ignore_heap_size_of = "Arc"] - mediarule: Arc>, + mediarule: Arc>, medialist: MutNullableJS, } impl CSSMediaRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, mediarule: Arc>) -> CSSMediaRule { - let list = mediarule.read().rules.clone(); + let guard = parent_stylesheet.shared_lock().read(); + let list = mediarule.read_with(&guard).rules.clone(); CSSMediaRule { - cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), + cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list), mediarule: mediarule, medialist: MutNullableJS::new(None), } @@ -41,21 +42,26 @@ impl CSSMediaRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - mediarule: Arc>) -> Root { + mediarule: Arc>) -> Root { reflect_dom_object(box CSSMediaRule::new_inherited(parent_stylesheet, mediarule), window, CSSMediaRuleBinding::Wrap) } fn medialist(&self) -> Root { - self.medialist.or_init(|| MediaList::new(self.global().as_window(), - self.mediarule.read().media_queries.clone())) + self.medialist.or_init(|| { + 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 pub fn get_condition_text(&self) -> DOMString { - let rule = self.mediarule.read(); - let list = rule.media_queries.read(); + let guard = self.cssconditionrule.shared_lock().read(); + let rule = self.mediarule.read_with(&guard); + let list = rule.media_queries.read_with(&guard); list.to_css_string().into() } @@ -63,9 +69,16 @@ impl CSSMediaRule { pub fn set_condition_text(&self, text: DOMString) { let mut input = Parser::new(&text); let new_medialist = parse_media_query_list(&mut input); - let rule = self.mediarule.read(); - let mut list = rule.media_queries.write(); - *list = new_medialist; + let mut guard = self.cssconditionrule.shared_lock().write(); + + // Clone an Arc because we can’t 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 { - self.mediarule.read().to_css_string().into() + let guard = self.cssconditionrule.shared_lock().read(); + self.mediarule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/cssnamespacerule.rs b/components/script/dom/cssnamespacerule.rs index 51f60fafd08..744a8020667 100644 --- a/components/script/dom/cssnamespacerule.rs +++ b/components/script/dom/cssnamespacerule.rs @@ -11,20 +11,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::NamespaceRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSNamespaceRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - namespacerule: Arc>, + namespacerule: Arc>, } impl CSSNamespaceRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, namespacerule: Arc>) -> CSSNamespaceRule { CSSNamespaceRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -34,7 +33,7 @@ impl CSSNamespaceRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - namespacerule: Arc>) -> Root { + namespacerule: Arc>) -> Root { reflect_dom_object(box CSSNamespaceRule::new_inherited(parent_stylesheet, namespacerule), window, CSSNamespaceRuleBinding::Wrap) @@ -44,14 +43,16 @@ impl CSSNamespaceRule { impl CSSNamespaceRuleMethods for CSSNamespaceRule { // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix 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()) .unwrap_or(DOMString::new()) } // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-namespaceuri 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 { - self.namespacerule.read().to_css_string().into() + let guard = self.cssrule.shared_lock().read(); + self.namespacerule.read_with(&guard).to_css_string(&guard).into() } } diff --git a/components/script/dom/cssrule.rs b/components/script/dom/cssrule.rs index 277d7323a21..54bb8c175a5 100644 --- a/components/script/dom/cssrule.rs +++ b/components/script/dom/cssrule.rs @@ -20,6 +20,7 @@ use dom::cssviewportrule::CSSViewportRule; use dom::window::Window; use dom_struct::dom_struct; use std::cell::Cell; +use style::shared_lock::SharedRwLock; use style::stylesheets::CssRule as StyleCssRule; @@ -103,6 +104,10 @@ impl CSSRule { pub fn parent_stylesheet(&self) -> &CSSStyleSheet { &self.parent_stylesheet } + + pub fn shared_lock(&self) -> &SharedRwLock { + &self.parent_stylesheet.style_stylesheet().shared_lock + } } impl CSSRuleMethods for CSSRule { diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index 0b6351d237c..1f1573a05d5 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -13,8 +13,8 @@ use dom::cssrule::CSSRule; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::Locked; use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError}; #[allow(unsafe_code)] @@ -43,19 +43,20 @@ pub struct CSSRuleList { } pub enum RulesSource { - Rules(Arc>), - Keyframes(Arc>), + Rules(Arc>), + Keyframes(Arc>), } impl CSSRuleList { #[allow(unrooted_must_root)] pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, rules: RulesSource) -> CSSRuleList { + let guard = parent_stylesheet.shared_lock().read(); let dom_rules = match 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) => { - 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 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 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. pub fn remove_rule(&self, index: u32) -> ErrorResult { let index = index as usize; + let mut guard = self.parent_stylesheet.shared_lock().write(); match self.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(); dom_rules[index].get().map(|r| r.detach()); dom_rules.remove(index); @@ -114,7 +121,7 @@ impl CSSRuleList { let mut dom_rules = self.dom_rules.borrow_mut(); dom_rules[index].get().map(|r| r.detach()); dom_rules.remove(index); - kf.write().keyframes.remove(index); + kf.write_with(&mut guard).keyframes.remove(index); Ok(()) } } @@ -131,16 +138,17 @@ impl CSSRuleList { self.dom_rules.borrow().get(idx as usize).map(|rule| { rule.or_init(|| { let parent_stylesheet = &self.parent_stylesheet; + let guard = parent_stylesheet.shared_lock().read(); match self.rules { RulesSource::Rules(ref rules) => { CSSRule::new_specific(self.global().as_window(), parent_stylesheet, - rules.read().0[idx as usize].clone()) + rules.read_with(&guard).0[idx as usize].clone()) } RulesSource::Keyframes(ref rules) => { Root::upcast(CSSKeyframeRule::new(self.global().as_window(), parent_stylesheet, - rules.read() + rules.read_with(&guard) .keyframes[idx as usize] .clone())) } diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 8af3b3975d2..d5d248f7880 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -11,10 +11,9 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::cssrule::CSSRule; 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_struct::dom_struct; -use parking_lot::RwLock; use servo_url::ServoUrl; use std::ascii::AsciiExt; use std::sync::Arc; @@ -23,6 +22,7 @@ use style::parser::ParserContextExtraData; use style::properties::{Importance, PropertyDeclarationBlock, PropertyId, LonghandId, ShorthandId}; use style::properties::{parse_one_declaration, parse_style_attribute}; use style::selector_parser::PseudoElement; +use style::shared_lock::Locked; use style_traits::ToCss; // http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface @@ -40,7 +40,7 @@ pub enum CSSStyleOwner { Element(JS), CSSRule(JS, #[ignore_heap_size_of = "Arc"] - Arc>), + Arc>), } impl CSSStyleOwner { @@ -55,10 +55,13 @@ impl CSSStyleOwner { let mut changed = true; match *self { 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 result = if attr.is_some() { 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); result } else { @@ -69,7 +72,7 @@ impl CSSStyleOwner { // exact conditions under it changes. changed = !pdb.declarations().is_empty(); if changed { - attr = Some(Arc::new(RwLock::new(pdb))); + attr = Some(Arc::new(shared_lock.wrap(pdb))); } result @@ -83,7 +86,8 @@ impl CSSStyleOwner { // // [1]: https://github.com/whatwg/html/issues/2306 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"), AttrValue::Declaration(serialization, pdb)); @@ -96,7 +100,10 @@ impl CSSStyleOwner { result } 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 { rule.global().as_window().Document().invalidate_stylesheets(); } @@ -111,15 +118,20 @@ impl CSSStyleOwner { match *self { CSSStyleOwner::Element(ref el) => { 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 => { let pdb = PropertyDeclarationBlock::new(); f(&pdb) } } } - CSSStyleOwner::CSSRule(_, ref pdb) => { - f(&pdb.read()) + CSSStyleOwner::CSSRule(ref rule, ref pdb) => { + let guard = rule.shared_lock().read(); + f(pdb.read_with(&guard)) } } } diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index 3c4c8c815d1..fed2b947f90 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -12,21 +12,20 @@ use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSSt use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::StyleRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSStyleRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - stylerule: Arc>, + stylerule: Arc>, style_decl: MutNullableJS, } impl CSSStyleRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, stylerule: Arc>) -> CSSStyleRule { CSSStyleRule { cssrule: CSSRule::new_inherited(parent_stylesheet), @@ -37,7 +36,7 @@ impl CSSStyleRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - stylerule: Arc>) -> Root { + stylerule: Arc>) -> Root { reflect_dom_object(box CSSStyleRule::new_inherited(parent_stylesheet, stylerule), window, CSSStyleRuleBinding::Wrap) @@ -51,7 +50,8 @@ impl SpecificCSSRule for CSSStyleRule { } 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 fn Style(&self) -> Root { self.style_decl.or_init(|| { - CSSStyleDeclaration::new(self.global().as_window(), - CSSStyleOwner::CSSRule(JS::from_ref(self.upcast()), - self.stylerule.read().block.clone()), - None, - CSSModificationAccess::ReadWrite) + let guard = self.cssrule.shared_lock().read(); + CSSStyleDeclaration::new( + self.global().as_window(), + CSSStyleOwner::CSSRule( + JS::from_ref(self.upcast()), + self.stylerule.read_with(&guard).block.clone() + ), + None, + CSSModificationAccess::ReadWrite + ) }) } } diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index f8397a732c2..ee097313c2e 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -16,6 +16,7 @@ use dom::window::Window; use dom_struct::dom_struct; use std::cell::Cell; use std::sync::Arc; +use style::shared_lock::SharedRwLock; use style::stylesheets::Stylesheet as StyleStyleSheet; #[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 { &self.style_stylesheet } diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs index 0cc113bef1c..7ba3a24d038 100644 --- a/components/script/dom/csssupportsrule.rs +++ b/components/script/dom/csssupportsrule.rs @@ -13,33 +13,34 @@ use dom::cssrule::SpecificCSSRule; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::parser::ParserContext; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::stylesheets::SupportsRule; use style::supports::SupportsCondition; use style_traits::ToCss; #[dom_struct] pub struct CSSSupportsRule { - cssrule: CSSConditionRule, + cssconditionrule: CSSConditionRule, #[ignore_heap_size_of = "Arc"] - supportsrule: Arc>, + supportsrule: Arc>, } impl CSSSupportsRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc>) + fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc>) -> CSSSupportsRule { - let list = supportsrule.read().rules.clone(); + let guard = parent_stylesheet.shared_lock().read(); + let list = supportsrule.read_with(&guard).rules.clone(); CSSSupportsRule { - cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), + cssconditionrule: CSSConditionRule::new_inherited(parent_stylesheet, list), supportsrule: supportsrule, } } #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - supportsrule: Arc>) -> Root { + supportsrule: Arc>) -> Root { reflect_dom_object(box CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule), window, CSSSupportsRuleBinding::Wrap) @@ -47,7 +48,8 @@ impl CSSSupportsRule { /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface 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() } @@ -61,7 +63,8 @@ impl CSSSupportsRule { let url = win.Document().url(); let context = ParserContext::new_for_cssom(&url, win.css_error_reporter()); 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.enabled = enabled; } @@ -75,6 +78,7 @@ impl SpecificCSSRule for CSSSupportsRule { } 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() } } diff --git a/components/script/dom/cssviewportrule.rs b/components/script/dom/cssviewportrule.rs index c784a26f442..38abf909ff0 100644 --- a/components/script/dom/cssviewportrule.rs +++ b/components/script/dom/cssviewportrule.rs @@ -10,20 +10,19 @@ use dom::cssrule::{CSSRule, SpecificCSSRule}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; +use style::shared_lock::{Locked, ToCssWithGuard}; use style::viewport::ViewportRule; -use style_traits::ToCss; #[dom_struct] pub struct CSSViewportRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] - viewportrule: Arc>, + viewportrule: Arc>, } impl CSSViewportRule { - fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc>) -> CSSViewportRule { + fn new_inherited(parent_stylesheet: &CSSStyleSheet, viewportrule: Arc>) -> CSSViewportRule { CSSViewportRule { cssrule: CSSRule::new_inherited(parent_stylesheet), viewportrule: viewportrule, @@ -32,7 +31,7 @@ impl CSSViewportRule { #[allow(unrooted_must_root)] pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, - viewportrule: Arc>) -> Root { + viewportrule: Arc>) -> Root { reflect_dom_object(box CSSViewportRule::new_inherited(parent_stylesheet, viewportrule), window, CSSViewportRuleBinding::Wrap) @@ -46,6 +45,7 @@ impl SpecificCSSRule for CSSViewportRule { } 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() } } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index b85366a27d2..b875c75d837 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -134,6 +134,8 @@ use style::attr::AttrValue; use style::context::{QuirksMode, ReflowGoal}; use style::restyle_hints::{RestyleHint, RESTYLE_STYLE_ATTRIBUTE}; 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::stylesheets::Stylesheet; use task_source::TaskSource; @@ -220,6 +222,9 @@ pub struct Document { scripts: MutNullableJS, anchors: MutNullableJS, applets: MutNullableJS, + /// 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. stylesheets: DOMRefCell>>, /// 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 will_paint(&self); unsafe fn quirks_mode(&self) -> QuirksMode; + unsafe fn style_shared_lock(&self) -> &StyleSharedRwLock; } #[allow(unsafe_code)] @@ -2000,6 +2006,11 @@ impl LayoutDocumentHelpers for LayoutJS { unsafe fn quirks_mode(&self) -> QuirksMode { (*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 @@ -2121,6 +2132,7 @@ impl Document { scripts: Default::default(), anchors: Default::default(), applets: Default::default(), + style_shared_lock: AUTHOR_SHARED_LOCK.clone(), stylesheets: DOMRefCell::new(None), stylesheets_changed_since_reflow: Cell::new(false), 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. pub fn stylesheets(&self) -> Vec> { self.ensure_stylesheets(); diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 8e13716fa9d..3a73bbce97e 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -82,7 +82,6 @@ use html5ever::serialize::TraversalScope::{ChildrenOnly, IncludeNode}; use html5ever_atoms::{Prefix, LocalName, Namespace, QualName}; use js::jsapi::{HandleValue, JSAutoCompartment}; use net_traits::request::CorsSettings; -use parking_lot::RwLock; use ref_filter_map::ref_filter_map; use script_layout_interface::message::ReflowQueryType; 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::rule_tree::CascadeLevel; use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser}; +use style::shared_lock::{SharedRwLock, Locked}; use style::sink::Push; use style::stylist::ApplicableDeclarationBlock; use style::thread_state; @@ -129,7 +129,7 @@ pub struct Element { attrs: DOMRefCell>>, id_attribute: DOMRefCell>, #[ignore_heap_size_of = "Arc"] - style_attribute: DOMRefCell>>>, + style_attribute: DOMRefCell>>>, attr_list: MutNullableJS, class_list: MutNullableJS, state: Cell, @@ -352,7 +352,7 @@ pub trait LayoutElementHelpers { #[allow(unsafe_code)] unsafe fn html_element_in_html_document_for_layout(&self) -> bool; fn id_attribute(&self) -> *const Option; - fn style_attribute(&self) -> *const Option>>; + fn style_attribute(&self) -> *const Option>>; fn local_name(&self) -> &LocalName; fn namespace(&self) -> &Namespace; fn get_lang_for_layout(&self) -> String; @@ -384,14 +384,18 @@ impl LayoutElementHelpers for LayoutJS { where V: Push { #[inline] - fn from_declaration(declaration: PropertyDeclaration) -> ApplicableDeclarationBlock { + fn from_declaration(shared_lock: &SharedRwLock, declaration: PropertyDeclaration) + -> ApplicableDeclarationBlock { ApplicableDeclarationBlock::from_declarations( - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( declaration, Importance::Normal ))), CascadeLevel::PresHints) } + let document = self.upcast::().owner_doc_for_layout(); + let shared_lock = document.style_shared_lock(); + let bgcolor = if let Some(this) = self.downcast::() { this.get_background_color() } else if let Some(this) = self.downcast::() { @@ -408,6 +412,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(color) = bgcolor { hints.push(from_declaration( + shared_lock, PropertyDeclaration::BackgroundColor( CSSColor { parsed: Color::RGBA(color), authored: None }))); } @@ -420,6 +425,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(url) = background { hints.push(from_declaration( + shared_lock, PropertyDeclaration::BackgroundImage( background_image::SpecifiedValue(vec![ background_image::single_value::SpecifiedValue(Some( @@ -442,6 +448,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(color) = color { hints.push(from_declaration( + shared_lock, PropertyDeclaration::Color( longhands::color::SpecifiedValue(CSSColor { parsed: Color::RGBA(color), @@ -459,6 +466,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(font_family) = font_family { hints.push(from_declaration( + shared_lock, PropertyDeclaration::FontFamily( font_family::computed_value::T(vec![ font_family::computed_value::FontFamily::from_atom( @@ -469,6 +477,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(font_size) = font_size { hints.push(from_declaration( + shared_lock, PropertyDeclaration::FontSize(font_size::SpecifiedValue(font_size.into())))) } @@ -481,6 +490,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(cellspacing) = cellspacing { let width_value = specified::Length::from_px(cellspacing as f32); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderSpacing( Box::new(border_spacing::SpecifiedValue { horizontal: width_value.clone(), @@ -514,6 +524,7 @@ impl LayoutElementHelpers for LayoutJS { if let Some(size) = size { let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(size)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width( specified::LengthOrPercentageOrAuto::Length(value)))); } @@ -539,12 +550,14 @@ impl LayoutElementHelpers for LayoutJS { let width_value = specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width(width_value))); } LengthOrPercentageOrAuto::Length(length) => { let width_value = specified::LengthOrPercentageOrAuto::Length( specified::NoCalcLength::Absolute(length)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width(width_value))); } } @@ -564,12 +577,14 @@ impl LayoutElementHelpers for LayoutJS { let height_value = specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Height(height_value))); } LengthOrPercentageOrAuto::Length(length) => { let height_value = specified::LengthOrPercentageOrAuto::Length( specified::NoCalcLength::Absolute(length)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Height(height_value))); } } @@ -592,6 +607,7 @@ impl LayoutElementHelpers for LayoutJS { // https://html.spec.whatwg.org/multipage/#textarea-effective-width let value = specified::NoCalcLength::ServoCharacterWidth(specified::CharacterWidth(cols)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Width(specified::LengthOrPercentageOrAuto::Length(value)))); } @@ -610,6 +626,7 @@ impl LayoutElementHelpers for LayoutJS { // https://html.spec.whatwg.org/multipage/#textarea-effective-height let value = specified::NoCalcLength::FontRelative(specified::FontRelativeLength::Em(rows as CSSFloat)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::Height(specified::LengthOrPercentageOrAuto::Length(value)))); } @@ -623,12 +640,16 @@ impl LayoutElementHelpers for LayoutJS { if let Some(border) = border { let width_value = specified::BorderWidth::from_length(specified::Length::from_px(border as f32)); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderTopWidth(Box::new(width_value.clone())))); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderLeftWidth(Box::new(width_value.clone())))); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderBottomWidth(Box::new(width_value.clone())))); hints.push(from_declaration( + shared_lock, PropertyDeclaration::BorderRightWidth(Box::new(width_value)))); } } @@ -672,7 +693,7 @@ impl LayoutElementHelpers for LayoutJS { } #[allow(unsafe_code)] - fn style_attribute(&self) -> *const Option>> { + fn style_attribute(&self) -> *const Option>> { unsafe { (*self.unsafe_get()).style_attribute.borrow_for_layout() } @@ -835,7 +856,7 @@ impl Element { ns!() } - pub fn style_attribute(&self) -> &DOMRefCell>>> { + pub fn style_attribute(&self) -> &DOMRefCell>>> { &self.style_attribute } @@ -2170,7 +2191,7 @@ impl VirtualMethods for Element { block } else { 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(), &doc.base_url(), win.css_error_reporter(), diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index b4f90b89b85..d29a94a11f0 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -291,9 +291,8 @@ impl HTMLLinkElement { // doesn't match. let loader = StylesheetLoader::for_element(self.upcast()); loader.load(StylesheetContextSource::LinkElement { - url: url, 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) { diff --git a/components/script/dom/htmlmetaelement.rs b/components/script/dom/htmlmetaelement.rs index a751486de7d..bc6f37561d8 100644 --- a/components/script/dom/htmlmetaelement.rs +++ b/components/script/dom/htmlmetaelement.rs @@ -19,7 +19,6 @@ use dom::node::{Node, UnbindContext, document_from_node, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use html5ever_atoms::LocalName; -use parking_lot::RwLock; use servo_config::prefs::PREFS; use std::ascii::AsciiExt; use std::sync::Arc; @@ -99,12 +98,16 @@ impl HTMLMetaElement { let content = content.value(); if !content.is_empty() { if let Some(translated_rule) = ViewportRule::from_meta(&**content) { + let document = self.upcast::().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 { - rules: CssRules::new(vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))]), + rules: CssRules::new(vec![rule], shared_lock), origin: Origin::Author, + shared_lock: shared_lock.clone(), base_url: window_from_node(self).get_url(), 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 // force all styles to be recomputed. dirty_on_viewport_size_change: AtomicBool::new(false), diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index f9c6412f854..13721feba58 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -84,9 +84,10 @@ impl HTMLStyleElement { let data = node.GetTextContent().expect("Element.textContent must be a string"); 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 sheet = Stylesheet::from_str(&data, url, Origin::Author, mq, - Some(&loader), + shared_lock, Some(&loader), win.css_error_reporter(), ParserContextExtraData::default()); diff --git a/components/script/dom/medialist.rs b/components/script/dom/medialist.rs index 806946f6356..b403200983e 100644 --- a/components/script/dom/medialist.rs +++ b/components/script/dom/medialist.rs @@ -6,52 +6,62 @@ use core::default::Default; use cssparser::Parser; use dom::bindings::codegen::Bindings::MediaListBinding; 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::str::DOMString; +use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use dom_struct::dom_struct; -use parking_lot::RwLock; use std::sync::Arc; use style::media_queries::{MediaQuery, parse_media_query_list}; use style::media_queries::MediaList as StyleMediaList; +use style::shared_lock::{SharedRwLock, Locked}; use style_traits::ToCss; #[dom_struct] pub struct MediaList { reflector_: Reflector, + parent_stylesheet: JS, #[ignore_heap_size_of = "Arc"] - media_queries: Arc>, + media_queries: Arc>, } impl MediaList { #[allow(unrooted_must_root)] - pub fn new_inherited(media_queries: Arc>) -> MediaList { + pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, + media_queries: Arc>) -> MediaList { MediaList { + parent_stylesheet: JS::from_ref(parent_stylesheet), reflector_: Reflector::new(), media_queries: media_queries, } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, media_queries: Arc>) + pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, + media_queries: Arc>) -> Root { - reflect_dom_object(box MediaList::new_inherited(media_queries), + reflect_dom_object(box MediaList::new_inherited(parent_stylesheet, media_queries), window, MediaListBinding::Wrap) } + fn shared_lock(&self) -> &SharedRwLock { + &self.parent_stylesheet.style_stylesheet().shared_lock + } } impl MediaListMethods for MediaList { // https://drafts.csswg.org/cssom/#dom-medialist-mediatext 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 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 if value.is_empty() { // Step 1 @@ -65,13 +75,15 @@ impl MediaListMethods for MediaList { // https://drafts.csswg.org/cssom/#dom-medialist-length 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 fn Item(&self, index: u32) -> Option { - self.media_queries.read().media_queries.get(index as usize) - .and_then(|query| { + let guard = self.shared_lock().read(); + self.media_queries.read_with(&guard).media_queries + .get(index as usize).and_then(|query| { let mut s = String::new(); query.to_css(&mut s).unwrap(); Some(DOMString::from_string(s)) @@ -94,13 +106,14 @@ impl MediaListMethods for MediaList { } // Step 3 let m_serialized = m.clone().unwrap().to_css_string(); - let any = self.media_queries.read().media_queries.iter() - .any(|q| m_serialized == q.to_css_string()); + let mut guard = self.shared_lock().write(); + 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 { return; } // 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 @@ -114,7 +127,8 @@ impl MediaListMethods for MediaList { } // Step 3 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(..) .filter(|q| m_serialized != q.to_css_string()) .collect(); diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 98ce86745f2..36aa7601d0b 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -44,7 +44,6 @@ use dom::text::Text; use gfx_traits::ByteIndex; use html5ever_atoms::{LocalName, Namespace}; use msg::constellation_msg::PipelineId; -use parking_lot::RwLock; use range::Range; use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; @@ -69,6 +68,7 @@ use style::dom::UnsafeNode; use style::element_state::*; use style::properties::{ComputedValues, PropertyDeclarationBlock}; use style::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl}; +use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked}; use style::sink::Push; use style::str::is_whitespace; use style::stylist::ApplicableDeclarationBlock; @@ -330,6 +330,10 @@ impl<'ld> ServoLayoutDocument<'ld> { 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) -> ServoLayoutDocument<'ld> { ServoLayoutDocument { document: doc, @@ -372,7 +376,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { ServoLayoutNode::from_layout_js(self.element.upcast()) } - fn style_attribute(&self) -> Option<&Arc>> { + fn style_attribute(&self) -> Option<&Arc>> { unsafe { (*self.element.style_attribute()).as_ref() } diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index cdc93c9808b..4c2f06322a4 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -22,13 +22,13 @@ use ipc_channel::router::ROUTER; use net_traits::{FetchResponseListener, FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy}; use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode, Type as RequestType}; use network_listener::{NetworkListener, PreInvoke}; -use parking_lot::RwLock; use script_layout_interface::message::Msg; use servo_url::ServoUrl; use std::mem; use std::sync::{Arc, Mutex}; use style::media_queries::MediaList; use style::parser::ParserContextExtraData; +use style::shared_lock::Locked as StyleLocked; use style::stylesheets::{ImportRule, Stylesheet, Origin}; use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; @@ -54,24 +54,8 @@ pub trait StylesheetOwner { pub enum StylesheetContextSource { // NB: `media` is just an option so we avoid cloning it. - LinkElement { media: Option, url: ServoUrl }, - Import(Arc>), -} - -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() - } - } - } + LinkElement { media: Option, }, + Import(Arc), } /// The context required for asynchronously loading an external stylesheet. @@ -79,6 +63,7 @@ pub struct StylesheetContext { /// The element that initiated the request. elem: Trusted, source: StylesheetContextSource, + url: ServoUrl, metadata: Option, /// The response body received to date. data: Vec, @@ -145,19 +130,21 @@ impl FetchResponseListener for StylesheetContext { let loader = StylesheetLoader::for_element(&elem); match self.source { - StylesheetContextSource::LinkElement { ref mut media, .. } => { + StylesheetContextSource::LinkElement { ref mut media } => { let link = elem.downcast::().unwrap(); // 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. let is_stylesheet_load_applicable = self.request_generation_id.map_or(true, |gen| gen == link.get_request_generation_id()); if is_stylesheet_load_applicable { + let shared_lock = document.style_shared_lock().clone(); let sheet = Arc::new(Stylesheet::from_bytes(&data, final_url, protocol_encoding_label, Some(environment_encoding), Origin::Author, media.take().unwrap(), + shared_lock, Some(&loader), win.css_error_reporter(), ParserContextExtraData::default())); @@ -171,9 +158,8 @@ impl FetchResponseListener for StylesheetContext { win.layout_chan().send(Msg::AddStylesheet(sheet)).unwrap(); } } - StylesheetContextSource::Import(ref import) => { - let import = import.read(); - Stylesheet::update_from_bytes(&import.stylesheet, + StylesheetContextSource::Import(ref stylesheet) => { + Stylesheet::update_from_bytes(&stylesheet, &data, protocol_encoding_label, Some(environment_encoding), @@ -197,8 +183,7 @@ impl FetchResponseListener for StylesheetContext { document.decrement_script_blocking_stylesheet_count(); } - let url = self.source.url(); - document.finish_load(LoadType::Stylesheet(url)); + document.finish_load(LoadType::Stylesheet(self.url.clone())); if let Some(any_failed) = owner.load_finished(successful) { let event = if any_failed { atom!("error") } else { atom!("load") }; @@ -220,15 +205,16 @@ impl<'a> StylesheetLoader<'a> { } impl<'a> StylesheetLoader<'a> { - pub fn load(&self, source: StylesheetContextSource, cors_setting: Option, + pub fn load(&self, source: StylesheetContextSource, url: ServoUrl, + cors_setting: Option, integrity_metadata: String) { - let url = source.url(); let document = document_from_node(self.elem); let gen = self.elem.downcast::() .map(HTMLLinkElement::get_request_generation_id); let context = Arc::new(Mutex::new(StylesheetContext { elem: Trusted::new(&*self.elem), source: source, + url: url.clone(), metadata: None, data: vec![], document: Trusted::new(&*document), @@ -285,9 +271,20 @@ impl<'a> StylesheetLoader<'a> { } impl<'a> StyleStylesheetLoader for StylesheetLoader<'a> { - fn request_stylesheet(&self, import: &Arc>) { + fn request_stylesheet( + &self, + media: MediaList, + make_import: &mut FnMut(MediaList) -> ImportRule, + make_arc: &mut FnMut(ImportRule) -> Arc>, + ) -> Arc> { + 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? //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) } } diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 0e7cb160334..86e293d4a05 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -405,6 +405,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + let mut data = self.get_style_data().unwrap().borrow_mut(); let new_style = context.stylist.precomputed_values_for_pseudo( + &context.guards, &style_pseudo, Some(data.styles().primary.values()), CascadeFlags::empty()); @@ -421,6 +422,7 @@ pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + let new_style = context.stylist .lazily_compute_pseudo_element_style( + &context.guards, unsafe { &self.unsafe_get() }, &style_pseudo, data.styles().primary.values()); diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index a4a6e5ac823..6532efc4e9d 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -13,7 +13,7 @@ path = "lib.rs" doctest = false [features] -gecko = ["nsstring_vendor", "rayon/unstable"] +gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus"] use_bindgen = ["bindgen", "regex"] servo = ["serde/unstable", "serde", "serde_derive", "heapsize_derive", "style_traits/servo", "servo_atoms", "html5ever-atoms", @@ -37,10 +37,10 @@ lazy_static = "0.2" log = "0.3" matches = "0.1" nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true} +num_cpus = {version = "1.1.0", optional = true} num-integer = "0.1.32" num-traits = "0.1.32" ordered-float = "0.4" -owning_ref = "0.2.2" parking_lot = "0.3.3" pdqsort = "0.1.0" rayon = "0.6" diff --git a/components/style/animation.rs b/components/style/animation.rs index ddf1498d983..9734b67c1fd 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -415,7 +415,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext, match step.value { KeyframesStepValue::ComputedValues => style_from_cascade.clone(), KeyframesStepValue::Declarations { block: ref declarations } => { - let guard = declarations.read(); + let guard = declarations.read_with(context.guards.author); // No !important in keyframes. debug_assert!(guard.declarations().iter() diff --git a/components/style/attr.rs b/components/style/attr.rs index 0d07a35e828..b4cd434635e 100644 --- a/components/style/attr.rs +++ b/components/style/attr.rs @@ -11,9 +11,9 @@ use app_units::Au; use cssparser::{self, Color, RGBA}; use euclid::num::Zero; use num_traits::ToPrimitive; -use parking_lot::RwLock; use properties::PropertyDeclarationBlock; use servo_url::ServoUrl; +use shared_lock::Locked; use std::ascii::AsciiExt; use std::str::FromStr; use std::sync::Arc; @@ -61,7 +61,7 @@ pub enum AttrValue { /// declarationblock for longer than needed. Declaration(String, #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] - Arc>) + Arc>) } /// Shared implementation to parse an integer according to diff --git a/components/style/context.rs b/components/style/context.rs index 44485915c2c..3a2926672ac 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -17,6 +17,7 @@ use parking_lot::RwLock; use selector_parser::PseudoElement; use selectors::matching::ElementSelectorFlags; use servo_config::opts; +use shared_lock::StylesheetGuards; use std::collections::HashMap; use std::env; use std::fmt; @@ -61,10 +62,13 @@ pub enum QuirksMode { /// /// There's exactly one of these during a given restyle traversal, and it's /// shared among the worker threads. -pub struct SharedStyleContext { +pub struct SharedStyleContext<'a> { /// The CSS selector stylist. pub stylist: Arc, + /// Guards for pre-acquired locks + pub guards: StylesheetGuards<'a>, + /// The animations that are currently running. pub running_animations: Arc>>>, @@ -85,7 +89,7 @@ pub struct SharedStyleContext { pub quirks_mode: QuirksMode, } -impl SharedStyleContext { +impl<'a> SharedStyleContext<'a> { /// Return a suitable viewport size in order to be used for viewport units. pub fn viewport_size(&self) -> Size2D { self.stylist.device.au_viewport_size() @@ -306,7 +310,7 @@ impl Drop for ThreadLocalStyleContext { /// shared style context, and a mutable reference to a local one. pub struct StyleContext<'a, E: TElement + 'a> { /// The shared style context reference. - pub shared: &'a SharedStyleContext, + pub shared: &'a SharedStyleContext<'a>, /// The thread-local style context (mutable) reference. pub thread_local: &'a mut ThreadLocalStyleContext, } diff --git a/components/style/dom.rs b/components/style/dom.rs index 612105c20e9..ac8ad3bd109 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -11,10 +11,10 @@ use {Atom, Namespace, LocalName}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use data::ElementData; use element_state::ElementState; -use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement}; use selectors::matching::ElementSelectorFlags; +use shared_lock::Locked; use sink::Push; use std::fmt; 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 /// Transition cascade level. -pub struct AnimationRules(pub Option>>, - pub Option>>); +pub struct AnimationRules(pub Option>>, + pub Option>>); /// The element trait, the main abstraction the style crate acts over. 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. - fn style_attribute(&self) -> Option<&Arc>>; + fn style_attribute(&self) -> Option<&Arc>>; /// Get this element's animation rules. 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. fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>) - -> Option>> { + -> Option>> { None } /// Get this element's transition rule. fn get_transition_rule(&self, _pseudo: Option<&PseudoElement>) - -> Option>> { + -> Option>> { None } diff --git a/components/style/encoding_support.rs b/components/style/encoding_support.rs index 62323ec2314..141291c896e 100644 --- a/components/style/encoding_support.rs +++ b/components/style/encoding_support.rs @@ -12,6 +12,7 @@ use media_queries::MediaList; use parser::ParserContextExtraData; use self::encoding::{EncodingRef, DecoderTrap}; use servo_url::ServoUrl; +use shared_lock::SharedRwLock; use std::str; use stylesheets::{Stylesheet, StylesheetLoader, Origin}; @@ -54,6 +55,7 @@ impl Stylesheet { environment_encoding: Option, origin: Origin, media: MediaList, + shared_lock: SharedRwLock, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) @@ -64,6 +66,7 @@ impl Stylesheet { base_url, origin, media, + shared_lock, stylesheet_loader, error_reporter, extra_data) diff --git a/components/style/font_face.rs b/components/style/font_face.rs index 0d4bc4f8a09..8bad3a93aee 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -14,6 +14,7 @@ use computed_values::font_family::FamilyName; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; #[cfg(feature = "gecko")] use cssparser::UnicodeRange; use parser::{ParserContext, log_css_error, Parse}; +use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt; use std::iter; 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. - fn to_css(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write, - { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { dest.write_str("@font-face {\n")?; $( dest.write_str(concat!(" ", $m_name, ": "))?; diff --git a/components/style/gecko/arc_types.rs b/components/style/gecko/arc_types.rs index d822857a9e6..349fca1bbcb 100644 --- a/components/style/gecko/arc_types.rs +++ b/components/style/gecko/arc_types.rs @@ -17,6 +17,7 @@ use media_queries::MediaList; use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; use properties::animated_properties::{AnimationValue, AnimationValueMap}; +use shared_lock::Locked; use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, MediaRule, NamespaceRule}; macro_rules! impl_arc_ffi { @@ -38,7 +39,7 @@ macro_rules! impl_arc_ffi { } } -impl_arc_ffi!(RwLock => ServoCssRules +impl_arc_ffi!(Locked => ServoCssRules [Servo_CssRules_AddRef, Servo_CssRules_Release]); impl_arc_ffi!(Stylesheet => RawServoStyleSheet @@ -47,13 +48,13 @@ impl_arc_ffi!(Stylesheet => RawServoStyleSheet impl_arc_ffi!(ComputedValues => ServoComputedValues [Servo_ComputedValues_AddRef, Servo_ComputedValues_Release]); -impl_arc_ffi!(RwLock => RawServoDeclarationBlock +impl_arc_ffi!(Locked => RawServoDeclarationBlock [Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]); -impl_arc_ffi!(RwLock => RawServoStyleRule +impl_arc_ffi!(Locked => RawServoStyleRule [Servo_StyleRule_AddRef, Servo_StyleRule_Release]); -impl_arc_ffi!(RwLock => RawServoImportRule +impl_arc_ffi!(Locked => RawServoImportRule [Servo_ImportRule_AddRef, Servo_ImportRule_Release]); impl_arc_ffi!(AnimationValue => RawServoAnimationValue @@ -62,11 +63,11 @@ impl_arc_ffi!(AnimationValue => RawServoAnimationValue impl_arc_ffi!(RwLock => RawServoAnimationValueMap [Servo_AnimationValueMap_AddRef, Servo_AnimationValueMap_Release]); -impl_arc_ffi!(RwLock => RawServoMediaList +impl_arc_ffi!(Locked => RawServoMediaList [Servo_MediaList_AddRef, Servo_MediaList_Release]); -impl_arc_ffi!(RwLock => RawServoMediaRule +impl_arc_ffi!(Locked => RawServoMediaRule [Servo_MediaRule_AddRef, Servo_MediaRule_Release]); -impl_arc_ffi!(RwLock => RawServoNamespaceRule +impl_arc_ffi!(Locked => RawServoNamespaceRule [Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release]); diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 627b3845051..a1ef6db3e2e 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -13,6 +13,7 @@ use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use media_queries::Device; use parking_lot::RwLock; use properties::ComputedValues; +use shared_lock::{StylesheetGuards, SharedRwLockReadGuard}; use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; @@ -83,20 +84,20 @@ impl PerDocumentStyleDataImpl { /// Reset the device state because it may have changed. /// /// 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(); Arc::get_mut(&mut stylist.device).unwrap().reset(); } self.stylesheets_changed = true; - self.flush_stylesheets(); + self.flush_stylesheets(guard); } /// 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 { 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; } } diff --git a/components/style/gecko/global_style_data.rs b/components/style/gecko/global_style_data.rs new file mode 100644 index 00000000000..2653ad16b1f --- /dev/null +++ b/components/style/gecko/global_style_data.rs @@ -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, + + /// 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::().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(), + } + }; +} diff --git a/components/style/gecko/mod.rs b/components/style/gecko/mod.rs index 2ee19fc60fc..48d50c5fa80 100644 --- a/components/style/gecko/mod.rs +++ b/components/style/gecko/mod.rs @@ -10,6 +10,7 @@ mod non_ts_pseudo_class_list; pub mod arc_types; pub mod conversions; pub mod data; +pub mod global_style_data; pub mod media_queries; pub mod restyle_damage; pub mod selector_parser; diff --git a/components/style/gecko/traversal.rs b/components/style/gecko/traversal.rs index 3cb7f30cb1b..7a68f66c75f 100644 --- a/components/style/gecko/traversal.rs +++ b/components/style/gecko/traversal.rs @@ -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 /// styling. -pub struct RecalcStyleOnly { - shared: SharedStyleContext, +pub struct RecalcStyleOnly<'a> { + shared: SharedStyleContext<'a>, driver: TraversalDriver, } -impl RecalcStyleOnly { +impl<'a> RecalcStyleOnly<'a> { /// 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 { shared: shared, driver: driver, @@ -28,10 +28,11 @@ impl RecalcStyleOnly { } } -impl<'le> DomTraversal> for RecalcStyleOnly { +impl<'recalc, 'le> DomTraversal> for RecalcStyleOnly<'recalc> { type ThreadLocalContext = ThreadLocalStyleContext>; - fn process_preorder(&self, traversal_data: &mut PerLevelTraversalData, + fn process_preorder(&self, + traversal_data: &mut PerLevelTraversalData, thread_local: &mut Self::ThreadLocalContext, node: GeckoNode<'le>) { diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index fa057a4ae26..b9cab601f2c 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -20,6 +20,7 @@ use dom::{AnimationRules, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode} use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use element_state::ElementState; use error_reporting::StdoutErrorReporter; +use gecko::global_style_data::GLOBAL_STYLE_DATA; use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement}; use gecko::snapshot_helpers; use gecko_bindings::bindings; @@ -53,6 +54,7 @@ use selectors::Element; use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector}; use selectors::parser::{AttrSelector, NamespaceConstraint}; use servo_url::ServoUrl; +use shared_lock::Locked; use sink::Push; use std::fmt; use std::ptr; @@ -407,12 +409,14 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 { fn get_animation_rule(element: &GeckoElement, pseudo: Option<&PseudoElement>, cascade_level: CascadeLevel) - -> Option>> { + -> Option>> { let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo); let animation_values = Arc::new(RwLock::new(AnimationValueMap::new())); if unsafe { Gecko_GetAnimationRule(element.0, atom_ptr, cascade_level, 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 { None } @@ -425,7 +429,7 @@ impl<'le> TElement for GeckoElement<'le> { unsafe { GeckoNode(&*(self.0 as *const _ as *const RawGeckoNode)) } } - fn style_attribute(&self) -> Option<&Arc>> { + fn style_attribute(&self) -> Option<&Arc>> { let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) }; 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>) - -> Option>> { + -> Option>> { get_animation_rule(self, pseudo, CascadeLevel::Animations) } fn get_transition_rule(&self, pseudo: Option<&PseudoElement>) - -> Option>> { + -> Option>> { get_animation_rule(self, pseudo, CascadeLevel::Transitions) } diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs index 69aeb669dcc..67f0c848f8d 100644 --- a/components/style/keyframes.rs +++ b/components/style/keyframes.rs @@ -8,13 +8,13 @@ use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser}; use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule}; -use parking_lot::RwLock; use parser::{ParserContext, ParserContextExtraData, log_css_error}; use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use properties::{PropertyDeclarationId, LonghandId, ParsedDeclaration}; use properties::LonghandIdSet; use properties::animated_properties::TransitionProperty; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; +use shared_lock::{SharedRwLock, SharedRwLockReadGuard, Locked, ToCssWithGuard}; use std::fmt; use std::sync::Arc; use style_traits::ToCss; @@ -101,11 +101,12 @@ pub struct Keyframe { /// /// Note that `!important` rules in keyframes don't apply, but we keep this /// `Arc` just for convenience. - pub block: Arc>, + pub block: Arc>, } -impl ToCss for Keyframe { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl ToCssWithGuard for Keyframe { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { let mut iter = self.selector.percentages().iter(); try!(iter.next().unwrap().to_css(dest)); for percentage in iter { @@ -113,7 +114,7 @@ impl ToCss for Keyframe { try!(percentage.to_css(dest)); } try!(dest.write_str(" { ")); - try!(self.block.read().to_css(dest)); + try!(self.block.read_with(guard).to_css(dest)); try!(dest.write_str(" }")); Ok(()) } @@ -125,7 +126,7 @@ impl Keyframe { pub fn parse(css: &str, parent_stylesheet: &Stylesheet, extra_data: ParserContextExtraData) - -> Result>, ()> { + -> Result>, ()> { let error_reporter = MemoryHoleReporter; let context = ParserContext::new_with_extra_data(parent_stylesheet.origin, &parent_stylesheet.base_url, @@ -135,6 +136,7 @@ impl Keyframe { let mut rule_parser = KeyframeListParser { context: &context, + shared_lock: &parent_stylesheet.shared_lock, }; parse_one_rule(&mut input, &mut rule_parser) } @@ -152,7 +154,7 @@ pub enum KeyframesStepValue { Declarations { /// The declaration block per se. #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] - block: Arc> + block: Arc> }, /// A synthetic step computed from the current computed values at the time /// of the animation. @@ -178,10 +180,11 @@ pub struct KeyframesStep { impl KeyframesStep { #[inline] fn new(percentage: KeyframePercentage, - value: KeyframesStepValue) -> Self { + value: KeyframesStepValue, + guard: &SharedRwLockReadGuard) -> Self { let declared_timing_function = match value { 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 { PropertyDeclaration::AnimationTimingFunction(..) => true, _ => false, @@ -199,13 +202,14 @@ impl KeyframesStep { } /// Return specified TransitionTimingFunction if this KeyframesSteps has 'animation-timing-function'. - pub fn get_animation_timing_function(&self) -> Option { + pub fn get_animation_timing_function(&self, guard: &SharedRwLockReadGuard) + -> Option { if !self.declared_timing_function { return None; } match self.value { KeyframesStepValue::Declarations { ref block } => { - let guard = block.read(); + let guard = block.read_with(guard); let &(ref declaration, _) = guard.get(PropertyDeclarationId::Longhand(LonghandId::AnimationTimingFunction)).unwrap(); match *declaration { @@ -239,14 +243,16 @@ pub struct KeyframesAnimation { } /// Get all the animated properties in a keyframes animation. -fn get_animated_properties(keyframes: &[Arc>]) -> Vec { +fn get_animated_properties(keyframes: &[Arc>], guard: &SharedRwLockReadGuard) + -> Vec { let mut ret = vec![]; let mut seen = LonghandIdSet::new(); // NB: declarations are already deduplicated, so we don't have to check for // it here. for keyframe in keyframes { - let keyframe = keyframe.read(); - for &(ref declaration, importance) in keyframe.block.read().declarations().iter() { + let keyframe = keyframe.read_with(&guard); + let block = keyframe.block.read_with(guard); + for &(ref declaration, importance) in block.declarations().iter() { assert!(!importance.important()); 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, /// and return the animation object. - pub fn from_keyframes(keyframes: &[Arc>]) -> Self { + pub fn from_keyframes(keyframes: &[Arc>], guard: &SharedRwLockReadGuard) + -> Self { let mut result = KeyframesAnimation { steps: vec![], properties_changed: vec![], @@ -280,17 +287,17 @@ impl KeyframesAnimation { return result; } - result.properties_changed = get_animated_properties(keyframes); + result.properties_changed = get_animated_properties(keyframes, guard); if result.properties_changed.is_empty() { return result; } for keyframe in keyframes { - let keyframe = keyframe.read(); + let keyframe = keyframe.read_with(&guard); for percentage in keyframe.selector.0.iter() { result.steps.push(KeyframesStep::new(*percentage, KeyframesStepValue::Declarations { block: keyframe.block.clone(), - })); + }, guard)); } } @@ -300,12 +307,14 @@ impl KeyframesAnimation { // Prepend autogenerated keyframes if appropriate. if result.steps[0].start_percentage.0 != 0. { result.steps.insert(0, KeyframesStep::new(KeyframePercentage::new(0.), - KeyframesStepValue::ComputedValues)); + KeyframesStepValue::ComputedValues, + guard)); } if result.steps.last().unwrap().start_percentage.0 != 1. { result.steps.push(KeyframesStep::new(KeyframePercentage::new(1.), - KeyframesStepValue::ComputedValues)); + KeyframesStepValue::ComputedValues, + guard)); } result @@ -322,24 +331,27 @@ impl KeyframesAnimation { /// } struct KeyframeListParser<'a> { context: &'a ParserContext<'a>, + shared_lock: &'a SharedRwLock, } /// Parses a keyframe list from CSS input. -pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser) -> Vec>> { - RuleListParser::new_for_nested_rule(input, KeyframeListParser { context: context }) - .filter_map(Result::ok) - .collect() +pub fn parse_keyframe_list(context: &ParserContext, input: &mut Parser, shared_lock: &SharedRwLock) + -> Vec>> { + RuleListParser::new_for_nested_rule(input, KeyframeListParser { + context: context, + shared_lock: shared_lock, + }).filter_map(Result::ok).collect() } enum Void {} impl<'a> AtRuleParser for KeyframeListParser<'a> { type Prelude = Void; - type AtRule = Arc>; + type AtRule = Arc>; } impl<'a> QualifiedRuleParser for KeyframeListParser<'a> { type Prelude = KeyframeSelector; - type QualifiedRule = Arc>; + type QualifiedRule = Arc>; fn parse_prelude(&mut self, input: &mut Parser) -> Result { 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. } - Ok(Arc::new(RwLock::new(Keyframe { + Ok(Arc::new(self.shared_lock.wrap(Keyframe { selector: prelude, - block: Arc::new(RwLock::new(block)), + block: Arc::new(self.shared_lock.wrap(block)), }))) } } diff --git a/components/style/lib.rs b/components/style/lib.rs index b5bc9f74440..ab564c59bd8 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -57,10 +57,10 @@ extern crate log; #[macro_use] extern crate matches; #[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring; +#[cfg(feature = "gecko")] extern crate num_cpus; extern crate num_integer; extern crate num_traits; extern crate ordered_float; -extern crate owning_ref; extern crate parking_lot; extern crate pdqsort; extern crate rayon; @@ -99,13 +99,13 @@ pub mod keyframes; pub mod logical_geometry; pub mod matching; pub mod media_queries; -pub mod owning_handle; pub mod parallel; pub mod parser; pub mod restyle_hints; pub mod rule_tree; pub mod scoped_tls; pub mod selector_parser; +pub mod shared_lock; pub mod stylist; #[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo; pub mod sequential; @@ -168,6 +168,8 @@ macro_rules! reexport_computed_values { longhand_properties_idents!(reexport_computed_values); /// 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] pub fn arc_ptr_eq(a: &Arc, b: &Arc) -> bool { let a: &T = &**a; diff --git a/components/style/matching.rs b/components/style/matching.rs index 296862cfe20..38552ff46da 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -541,6 +541,7 @@ trait PrivateMatchMethods: TElement { let values = Arc::new(cascade(&shared_context.stylist.device, rule_node, + &shared_context.guards, inherited_values, layout_parent_style, Some(&mut cascade_info), @@ -784,6 +785,7 @@ pub trait MatchMethods : TElement { style_attribute, animation_rules, None, + &context.shared.guards, &mut applicable_declarations, &mut flags); 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()), None, pseudo_animation_rules, Some(&pseudo), + &context.shared.guards, &mut applicable_declarations, &mut flags); @@ -883,7 +886,8 @@ pub trait MatchMethods : TElement { let new_node = context.shared.stylist.rule_tree .update_rule_at_level(CascadeLevel::StyleAttributeNormal, style_attribute, - primary_rules); + primary_rules, + &context.shared.guards); if let Some(n) = new_node { *primary_rules = n; rule_node_changed = true; @@ -892,7 +896,8 @@ pub trait MatchMethods : TElement { let new_node = context.shared.stylist.rule_tree .update_rule_at_level(CascadeLevel::StyleAttributeImportant, style_attribute, - primary_rules); + primary_rules, + &context.shared.guards); if let Some(n) = new_node { *primary_rules = n; rule_node_changed = true; diff --git a/components/style/owning_handle.rs b/components/style/owning_handle.rs deleted file mode 100644 index 1294bf7e59f..00000000000 --- a/components/style/owning_handle.rs +++ /dev/null @@ -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 - where O: StableAddress, - H: Deref, -{ - handle: H, - _owner: O, -} - -impl Deref for OwningHandle - where O: StableAddress, - H: Deref, -{ - type Target = H::Target; - fn deref(&self) -> &H::Target { - self.handle.deref() - } -} - -unsafe impl StableAddress for OwningHandle - where O: StableAddress, - H: StableAddress, -{} - -impl DerefMut for OwningHandle - where O: StableAddress, - H: DerefMut, -{ - fn deref_mut(&mut self) -> &mut H::Target { - self.handle.deref_mut() - } -} - -impl OwningHandle - 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(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, - } - } -} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 7b81b9ae594..f9c2cac07b6 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -31,6 +31,7 @@ use parser::{Parse, ParserContext, ParserContextExtraData}; use properties::animated_properties::TransitionProperty; #[cfg(feature = "servo")] use servo_config::prefs::PREFS; use servo_url::ServoUrl; +use shared_lock::StylesheetGuards; use style_traits::ToCss; use stylesheets::Origin; #[cfg(feature = "servo")] use values::Either; @@ -1860,6 +1861,7 @@ bitflags! { /// pub fn cascade(device: &Device, rule_node: &StrongRuleNode, + guards: &StylesheetGuards, parent_style: Option<<&ComputedValues>, layout_parent_style: Option<<&ComputedValues>, cascade_info: Option<<&mut CascadeInfo>, @@ -1882,11 +1884,12 @@ pub fn cascade(device: &Device, // Hold locks until after the apply_declarations() call returns. // Use filter_map because the root node has no style source. - let lock_guards = rule_node.self_and_ancestors().filter_map(|node| { - node.style_source().map(|source| (source.read(), node.importance())) + let declaration_blocks = rule_node.self_and_ancestors().filter_map(|node| { + let guard = node.cascade_level().guard(guards); + node.style_source().map(|source| (source.read(guard), node.importance())) }).collect::>(); let iter_declarations = || { - lock_guards.iter().flat_map(|&(ref source, source_importance)| { + declaration_blocks.iter().flat_map(|&(ref source, source_importance)| { source.declarations().iter() // Yield declarations later in source order (with more precedence) first. .rev() diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 9a725a19286..54cf785e458 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -10,9 +10,8 @@ use arc_ptr_eq; #[cfg(feature = "servo")] use heapsize::HeapSizeOf; -use owning_handle::OwningHandle; -use parking_lot::{RwLock, RwLockReadGuard}; use properties::{Importance, PropertyDeclarationBlock}; +use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard}; use std::io::{self, Write}; use std::ptr; use std::sync::Arc; @@ -52,33 +51,9 @@ pub struct RuleTree { #[derive(Debug, Clone)] pub enum StyleSource { /// A style rule stable pointer. - Style(Arc>), + Style(Arc>), /// A declaration block stable pointer. - Declarations(Arc>), -} - -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, - } - } + Declarations(Arc>), } impl StyleSource { @@ -92,28 +67,26 @@ impl StyleSource { } } - fn dump(&self, writer: &mut W) { + fn dump(&self, guard: &SharedRwLockReadGuard, writer: &mut W) { use self::StyleSource::*; 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 /// underlying property declaration block. #[inline] - pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> { - use self::StyleSource::*; - match *self { - Style(ref rule) => { - let owning_ref = OwningHandle::new(rule.read(), |r| unsafe { &*r }.block.read()); - StyleSourceGuard::Style(owning_ref) - } - Declarations(ref block) => StyleSourceGuard::Declarations(block.read()), - } + pub fn read<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a PropertyDeclarationBlock { + let block = match *self { + StyleSource::Style(ref rule) => &rule.read_with(guard).block, + StyleSource::Declarations(ref block) => block, + }; + block.read_with(guard) } } @@ -137,15 +110,15 @@ impl RuleTree { self.root.clone() } - fn dump(&self, writer: &mut W) { + fn dump(&self, guards: &StylesheetGuards, writer: &mut W) { let _ = writeln!(writer, " + RuleTree"); - self.root.get().dump(writer, 0); + self.root.get().dump(guards, writer, 0); } /// Dump the rule tree to stdout. - pub fn dump_stdout(&self) { + pub fn dump_stdout(&self, guards: &StylesheetGuards) { 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 @@ -187,8 +160,9 @@ impl RuleTree { /// the old path is still valid. pub fn update_rule_at_level(&self, level: CascadeLevel, - pdb: Option<&Arc>>, - path: &StrongRuleNode) + pdb: Option<&Arc>>, + path: &StrongRuleNode, + guards: &StylesheetGuards) -> Option { debug_assert!(level.is_unique_per_element()); // TODO(emilio): Being smarter with lifetimes we could avoid a bit of @@ -247,13 +221,13 @@ impl RuleTree { // pretty bad styling cases already. if let Some(pdb) = pdb { 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(), StyleSource::Declarations(pdb.clone()), level); } } else { - if pdb.read().any_normal() { + if pdb.read_with(level.guard(guards)).any_normal() { current = current.ensure_child(self.root.downgrade(), StyleSource::Declarations(pdb.clone()), level); @@ -307,6 +281,17 @@ pub enum 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 /// we can replace the path in the cascade without fear. pub fn is_unique_per_element(&self) -> bool { @@ -450,7 +435,7 @@ impl RuleNode { } } - fn dump(&self, writer: &mut W, indent: usize) { + fn dump(&self, guards: &StylesheetGuards, writer: &mut W, indent: usize) { const INDENT_INCREMENT: usize = 4; for _ in 0..indent { @@ -467,7 +452,7 @@ impl RuleNode { match self.source { Some(ref source) => { - source.dump(writer); + source.dump(self.level.guard(guards), writer); } None => { if indent != 0 { @@ -479,7 +464,7 @@ impl RuleNode { let _ = write!(writer, "\n"); 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() } + /// The cascade level for this node + pub fn cascade_level(&self) -> CascadeLevel { + self.get().level + } + /// Get the importance that this rule node represents. pub fn importance(&self) -> Importance { self.get().level.importance() diff --git a/components/style/servo/mod.rs b/components/style/servo/mod.rs index ad741616eeb..ff6890658d3 100644 --- a/components/style/servo/mod.rs +++ b/components/style/servo/mod.rs @@ -9,3 +9,13 @@ pub mod media_queries; pub mod restyle_damage; 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(); +} diff --git a/components/style/shared_lock.rs b/components/style/shared_lock.rs new file mode 100644 index 00000000000..152e2b6ba82 --- /dev/null +++ b/components/style/shared_lock.rs @@ -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>, +} + +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(&self, data: T) -> Locked { + 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 { + shared_lock: SharedRwLock, + data: UnsafeCell, +} + +// Unsafe: the data inside `UnsafeCell` is only accessed in `read_with` and `write_with`, +// where guards ensure synchronization. +unsafe impl Send for Locked {} +unsafe impl Sync for Locked {} + +impl fmt::Debug for Locked { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let guard = self.shared_lock.read(); + self.read_with(&guard).fmt(f) + } +} + +impl Locked { + 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 we’ve checked that it’s 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 we’ve checked that it’s 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 Marker1 for T {} + impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Clone + impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Clone + + trait Marker2 {} + impl 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(&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, + } + } +} diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 5b5c47e152f..202c31f7416 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -21,6 +21,7 @@ use selector_parser::{SelectorImpl, SelectorParser}; use selectors::parser::SelectorList; use servo_config::prefs::PREFS; use servo_url::ServoUrl; +use shared_lock::{SharedRwLock, Locked, ToCssWithGuard, SharedRwLockReadGuard}; use std::cell::Cell; use std::fmt; use std::sync::Arc; @@ -86,8 +87,8 @@ impl From for RulesMutateError { impl CssRules { #[allow(missing_docs)] - pub fn new(rules: Vec) -> Arc> { - Arc::new(RwLock::new(CssRules(rules))) + pub fn new(rules: Vec, shared_lock: &SharedRwLock) -> Arc> { + Arc::new(shared_lock.wrap(CssRules(rules))) } fn only_ns_or_import(&self) -> bool { @@ -173,13 +174,15 @@ impl CssRules { pub struct Stylesheet { /// List of rules in the order they were found (important for /// cascading order) - pub rules: Arc>, + pub rules: Arc>, /// List of media associated with the Stylesheet. - pub media: Arc>, + pub media: Arc>, /// The origin of this stylesheet. pub origin: Origin, /// The base url this stylesheet should use. pub base_url: ServoUrl, + /// The lock used for objects inside this stylesheet + pub shared_lock: SharedRwLock, /// The namespaces that apply to this stylesheet. pub namespaces: RwLock, /// 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. pub struct UserAgentStylesheets { + /// The lock used for user-agent stylesheets. + pub shared_lock: SharedRwLock, /// The user or user agent stylesheets. pub user_or_user_agent_stylesheets: Vec, /// The quirks mode stylesheet. @@ -207,14 +212,14 @@ pub enum CssRule { // No Charset here, CSSCharsetRule has been removed from CSSOM // https://drafts.csswg.org/cssom/#changes-from-5-december-2013 - Namespace(Arc>), - Import(Arc>), - Style(Arc>), - Media(Arc>), - FontFace(Arc>), - Viewport(Arc>), - Keyframes(Arc>), - Supports(Arc>), + Namespace(Arc>), + Import(Arc>), + Style(Arc>), + Media(Arc>), + FontFace(Arc>), + Viewport(Arc>), + Keyframes(Arc>), + Supports(Arc>), } #[allow(missing_docs)] @@ -291,13 +296,13 @@ impl CssRule { /// used for others. /// /// This will not recurse down unsupported @supports rules - pub fn with_nested_rules_and_mq(&self, mut f: F) -> R + pub fn with_nested_rules_and_mq(&self, guard: &SharedRwLockReadGuard, mut f: F) -> R where F: FnMut(&[CssRule], Option<&MediaList>) -> R { match *self { CssRule::Import(ref lock) => { - let rule = lock.read(); - let media = rule.stylesheet.media.read(); - let rules = rule.stylesheet.rules.read(); + let rule = lock.read_with(guard); + let media = rule.stylesheet.media.read_with(guard); + let rules = rule.stylesheet.rules.read_with(guard); // FIXME(emilio): Include the nested rules if the stylesheet is // loaded. f(&rules.0, Some(&media)) @@ -310,16 +315,16 @@ impl CssRule { f(&[], None) } CssRule::Media(ref lock) => { - let media_rule = lock.read(); - let mq = media_rule.media_queries.read(); - let rules = &media_rule.rules.read().0; + let media_rule = lock.read_with(guard); + let mq = media_rule.media_queries.read_with(guard); + let rules = &media_rule.rules.read_with(guard).0; f(rules, Some(&mq)) } CssRule::Supports(ref lock) => { - let supports_rule = lock.read(); + let supports_rule = lock.read_with(guard); let enabled = supports_rule.enabled; if enabled { - let rules = &supports_rule.rules.read().0; + let rules = &supports_rule.rules.read_with(guard).0; f(rules, None) } else { f(&[], None) @@ -349,6 +354,7 @@ impl CssRule { let mut rule_parser = TopLevelRuleParser { stylesheet_origin: parent_stylesheet.origin, context: context, + shared_lock: &parent_stylesheet.shared_lock, loader: None, state: Cell::new(state), 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 - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { match *self { - CssRule::Namespace(ref lock) => lock.read().to_css(dest), - CssRule::Import(ref lock) => lock.read().to_css(dest), - CssRule::Style(ref lock) => lock.read().to_css(dest), - CssRule::FontFace(ref lock) => lock.read().to_css(dest), - CssRule::Viewport(ref lock) => lock.read().to_css(dest), - CssRule::Keyframes(ref lock) => lock.read().to_css(dest), - CssRule::Media(ref lock) => lock.read().to_css(dest), - CssRule::Supports(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_with(guard).to_css(guard, dest), + CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest), + CssRule::Supports(ref lock) => lock.read_with(guard).to_css(guard, dest), } } } @@ -390,9 +397,10 @@ pub struct NamespaceRule { pub url: Namespace, } -impl ToCss for NamespaceRule { +impl ToCssWithGuard for NamespaceRule { // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSNamespaceRule - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@namespace ")); if let Some(ref prefix) = self.prefix { try!(dest.write_str(&*prefix.to_string())); @@ -420,11 +428,12 @@ pub struct ImportRule { pub stylesheet: Arc, } -impl ToCss for ImportRule { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl ToCssWithGuard for ImportRule { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@import ")); try!(self.url.to_css(dest)); - let media = self.stylesheet.media.read(); + let media = self.stylesheet.media.read_with(guard); if !media.is_empty() { try!(dest.write_str(" ")); try!(media.to_css(dest)); @@ -441,12 +450,13 @@ pub struct KeyframesRule { /// The name of the current animation. pub name: Atom, /// The keyframes specified for this CSS rule. - pub keyframes: Vec>>, + pub keyframes: Vec>>, } -impl ToCss for KeyframesRule { +impl ToCssWithGuard for KeyframesRule { // Serialization of KeyframesRule is not specced. - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@keyframes ")); try!(dest.write_str(&*self.name.to_string())); try!(dest.write_str(" { ")); @@ -457,8 +467,8 @@ impl ToCss for KeyframesRule { try!(dest.write_str(" ")); } first = false; - let keyframe = lock.read(); - try!(keyframe.to_css(dest)); + let keyframe = lock.read_with(&guard); + try!(keyframe.to_css(guard, dest)); } dest.write_str(" }") } @@ -467,20 +477,21 @@ impl ToCss for KeyframesRule { #[allow(missing_docs)] #[derive(Debug)] pub struct MediaRule { - pub media_queries: Arc>, - pub rules: Arc>, + pub media_queries: Arc>, + pub rules: Arc>, } -impl ToCss for MediaRule { +impl ToCssWithGuard for MediaRule { // Serialization of MediaRule is not specced. // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { 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(" {")); - for rule in self.rules.read().0.iter() { + for rule in self.rules.read_with(guard).0.iter() { try!(dest.write_str(" ")); - try!(rule.to_css(dest)); + try!(rule.to_css(guard, dest)); } dest.write_str(" }") } @@ -493,19 +504,20 @@ pub struct SupportsRule { /// The parsed condition pub condition: SupportsCondition, /// Child rules - pub rules: Arc>, + pub rules: Arc>, /// The result of evaluating the condition pub enabled: bool, } -impl ToCss for SupportsRule { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { +impl ToCssWithGuard for SupportsRule { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@supports ")); try!(self.condition.to_css(dest)); 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!(rule.to_css(dest)); + try!(rule.to_css(guard, dest)); } dest.write_str(" }") } @@ -515,18 +527,19 @@ impl ToCss for SupportsRule { #[derive(Debug)] pub struct StyleRule { pub selectors: SelectorList, - pub block: Arc>, + pub block: Arc>, } -impl ToCss for StyleRule { +impl ToCssWithGuard for StyleRule { // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { // Step 1 try!(self.selectors.to_css(dest)); // Step 2 try!(dest.write_str(" { ")); // Step 3 - let declaration_block = self.block.read(); + let declaration_block = self.block.read_with(guard); try!(declaration_block.to_css(dest)); // Step 4 if declaration_block.declarations().len() > 0 { @@ -545,18 +558,39 @@ impl Stylesheet { stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, extra_data: ParserContextExtraData) { - let mut rules = existing.rules.write(); - let mut namespaces = existing.namespaces.write(); + let mut namespaces = Namespaces::default(); + 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, bool) { + let mut rules = Vec::new(); let mut input = Parser::new(css); let rule_parser = TopLevelRuleParser { - stylesheet_origin: existing.origin, - namespaces: &mut namespaces, + stylesheet_origin: origin, + namespaces: namespaces, + shared_lock: shared_lock, loader: stylesheet_loader, - context: ParserContext::new_with_extra_data(existing.origin, - &existing.base_url, + context: ParserContext::new_with_extra_data(origin, + base_url, error_reporter, extra_data), state: Cell::new(State::Start), @@ -568,7 +602,7 @@ impl Stylesheet { let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); while let Some(result) = iter.next() { match result { - Ok(rule) => rules.0.push(rule), + Ok(rule) => rules.push(rule), Err(range) => { let pos = range.start; let message = format!("Invalid rule: '{}'", iter.input.slice(range)); @@ -578,8 +612,7 @@ impl Stylesheet { } } - existing.dirty_on_viewport_size_change - .store(input.seen_viewport_percentages(), Ordering::Release); + (rules, input.seen_viewport_percentages()) } /// Creates an empty stylesheet and parses it with a given base url, origin @@ -591,26 +624,25 @@ impl Stylesheet { base_url: ServoUrl, origin: Origin, media: MediaList, + shared_lock: SharedRwLock, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, 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, base_url: base_url, - namespaces: RwLock::new(Namespaces::default()), - rules: CssRules::new(vec![]), - media: Arc::new(RwLock::new(media)), - dirty_on_viewport_size_change: AtomicBool::new(false), + namespaces: RwLock::new(namespaces), + rules: CssRules::new(rules, &shared_lock), + media: Arc::new(shared_lock.wrap(media)), + shared_lock: shared_lock, + dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change), 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. @@ -637,8 +669,8 @@ impl Stylesheet { /// on the associated MediaList. /// /// Always true if no associated MediaList exists. - pub fn is_effective_for_device(&self, device: &Device) -> bool { - self.media.read().evaluate(device) + pub fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool { + self.media.read_with(guard).evaluate(device) } /// 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 /// examined. #[inline] - pub fn effective_rules(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) { - effective_rules(&self.rules.read().0, device, &mut f); + pub fn effective_rules(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: 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 @@ -670,16 +703,17 @@ impl Stylesheet { } } -fn effective_rules(rules: &[CssRule], device: &Device, f: &mut F) where F: FnMut(&CssRule) { +fn effective_rules(rules: &[CssRule], device: &Device, guard: &SharedRwLockReadGuard, f: &mut F) +where F: FnMut(&CssRule) { for rule in rules { 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 !media_queries.evaluate(device) { return } } - effective_rules(rules, device, f) + effective_rules(rules, device, guard, f) }) } } @@ -689,10 +723,11 @@ macro_rules! rule_filter { impl Stylesheet { $( #[allow(missing_docs)] - pub fn $method(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) { - self.effective_rules(device, |rule| { + pub fn $method(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F) + where F: FnMut(&$rule_type) { + self.effective_rules(device, guard, |rule| { if let CssRule::$variant(ref lock) = *rule { - let rule = lock.read(); + let rule = lock.read_with(guard); f(&rule) } }) @@ -718,12 +753,35 @@ pub trait StylesheetLoader { /// /// The called code is responsible to update the `stylesheet` rules field /// when the sheet is done loading. - fn request_stylesheet(&self, import: &Arc>); + /// + /// The convoluted signature allows impls to look at MediaList and ImportRule + /// before they’re 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>, + ) -> Arc>; } +struct NoOpLoader; + +impl StylesheetLoader for NoOpLoader { + fn request_stylesheet( + &self, + media: MediaList, + make_import: &mut FnMut(MediaList) -> ImportRule, + make_arc: &mut FnMut(ImportRule) -> Arc>, + ) -> Arc> { + make_arc(make_import(media)) + } +} + + struct TopLevelRuleParser<'a> { stylesheet_origin: Origin, namespaces: &'a mut Namespaces, + shared_lock: &'a SharedRwLock, loader: Option<&'a StylesheetLoader>, context: ParserContext<'a>, state: Cell, @@ -733,6 +791,7 @@ impl<'b> TopLevelRuleParser<'b> { fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> { NestedRuleParser { stylesheet_origin: self.stylesheet_origin, + shared_lock: self.shared_lock, context: &self.context, namespaces: self.namespaces, } @@ -754,7 +813,7 @@ enum AtRulePrelude { /// A @font-face rule prelude. FontFace, /// A @media rule prelude, with its media queries. - Media(Arc>), + Media(Arc>), /// An @supports rule, with its conditional Supports(SupportsCondition), /// A @viewport rule prelude. @@ -774,22 +833,27 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { "import" => { if self.state.get() <= State::Imports { self.state.set(State::Imports); - let url = try!(input.expect_url_or_string()); - let url = - try!(SpecifiedUrl::parse_from_string(url, - &self.context)); + let url_string = input.expect_url_or_string()?; + let specified_url = SpecifiedUrl::parse_from_string(url_string, &self.context)?; - let media = - Arc::new(RwLock::new(parse_media_query_list(input))); + let media = 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 { - url: url, + url: specified_url.take().unwrap(), stylesheet: Arc::new(Stylesheet { - rules: Arc::new(RwLock::new(CssRules(vec![]))), - media: media, + rules: CssRules::new(Vec::new(), self.shared_lock), + media: Arc::new(self.shared_lock.wrap(media)), + shared_lock: self.shared_lock.clone(), origin: self.context.stylesheet_origin, base_url: self.context.base_url.clone(), namespaces: RwLock::new(Namespaces::default()), @@ -797,15 +861,10 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { disabled: AtomicBool::new(false), }) } - )); - - if is_valid_url { - let loader = self.loader - .expect("Expected a stylesheet loader for @import"); - loader.request_stylesheet(&import_rule); - } - - return Ok(AtRuleType::WithoutBlock(CssRule::Import(import_rule))) + }, &mut |import_rule| { + Arc::new(self.shared_lock.wrap(import_rule)) + }); + return Ok(AtRuleType::WithoutBlock(CssRule::Import(arc))) } else { self.state.set(State::Invalid); return Err(()) // "@import must be before any rule but @charset" @@ -827,12 +886,12 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { None }; - return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new(RwLock::new( - NamespaceRule { + return Ok(AtRuleType::WithoutBlock(CssRule::Namespace(Arc::new( + self.shared_lock.wrap(NamespaceRule { prefix: opt_prefix, url: url, - } - ))))) + }) + )))) } else { self.state.set(State::Invalid); 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 struct NestedRuleParser<'a, 'b: 'a> { stylesheet_origin: Origin, + shared_lock: &'a SharedRwLock, context: &'a ParserContext<'b>, namespaces: &'b Namespaces, } impl<'a, 'b> NestedRuleParser<'a, 'b> { - fn parse_nested_rules(&self, input: &mut Parser) -> Arc> { + fn parse_nested_rules(&self, input: &mut Parser) -> Arc> { let mut iter = RuleListParser::new_for_nested_rule(input, self.clone()); let mut rules = Vec::new(); 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, "media" => { 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" => { 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 { match prelude { 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)))))) } 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, rules: self.parse_nested_rules(input), })))) } AtRulePrelude::Supports(cond) => { 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, rules: self.parse_nested_rules(input), enabled: enabled, })))) } AtRulePrelude::Viewport => { - Ok(CssRule::Viewport(Arc::new(RwLock::new( + Ok(CssRule::Viewport(Arc::new(self.shared_lock.wrap( try!(ViewportRule::parse(input, self.context)))))) } AtRulePrelude::Keyframes(name) => { - Ok(CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule { + Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule { 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, input: &mut Parser) -> Result { - 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, - block: Arc::new(RwLock::new(parse_property_declaration_list(self.context, input))) + block: Arc::new(self.shared_lock.wrap(declarations)) })))) } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index f7dd149e7d3..27d3dd4b10b 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -12,7 +12,6 @@ use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement}; use error_reporting::StdoutErrorReporter; use keyframes::KeyframesAnimation; use media_queries::Device; -use parking_lot::RwLock; use pdqsort::sort_by; use properties::{self, CascadeFlags, ComputedValues}; #[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::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector}; use selectors::parser::SelectorMethods; +use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use sink::Push; use smallvec::VecLike; use std::borrow::Borrow; @@ -158,6 +158,7 @@ impl Stylist { /// device is dirty, which means we need to re-evaluate media queries. pub fn update(&mut self, doc_stylesheets: &[Arc], + guards: &StylesheetGuards, ua_stylesheets: Option<&UserAgentStylesheets>, stylesheets_changed: bool) -> bool { if !(self.is_device_dirty || stylesheets_changed) { @@ -165,7 +166,9 @@ impl Stylist { } 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 = @@ -193,16 +196,16 @@ impl Stylist { if let Some(ua_stylesheets) = ua_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 { - 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() { - self.add_stylesheet(stylesheet); + self.add_stylesheet(stylesheet, guards.author); } debug!("Stylist stats:"); @@ -216,8 +219,9 @@ impl Stylist { SelectorImpl::each_precomputed_pseudo_element(|pseudo| { if let Some(map) = self.pseudos_map.remove(&pseudo) { let declarations = - map.user_agent.get_universal_rules(CascadeLevel::UANormal, - CascadeLevel::UAImportant); + map.user_agent.get_universal_rules( + guards.ua_or_user, CascadeLevel::UANormal, CascadeLevel::UAImportant + ); self.precomputed_pseudo_element_decls.insert(pseudo, declarations); } }); @@ -226,19 +230,19 @@ impl Stylist { true } - fn add_stylesheet(&mut self, stylesheet: &Stylesheet) { - if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device) { + fn add_stylesheet(&mut self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard) { + if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device, guard) { return; } // Cheap `Arc` clone so that the closure below can borrow `&mut Stylist`. let device = self.device.clone(); - stylesheet.effective_rules(&device, |rule| { + stylesheet.effective_rules(&device, guard, |rule| { match *rule { - CssRule::Style(ref style_rule) => { - let guard = style_rule.read(); - for selector in &guard.selectors.0 { + CssRule::Style(ref locked) => { + let style_rule = locked.read_with(&guard); + for selector in &style_rule.selectors.0 { let map = if let Some(ref pseudo) = selector.pseudo_element { self.pseudos_map .entry(pseudo.clone()) @@ -250,14 +254,14 @@ impl Stylist { map.insert(Rule { selector: selector.complex_selector.clone(), - style_rule: style_rule.clone(), + style_rule: locked.clone(), specificity: selector.specificity, source_order: self.rules_source_order, }); } 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); if selector.affects_siblings() { self.sibling_affecting_selectors.push(selector.clone()); @@ -269,13 +273,14 @@ impl Stylist { } } CssRule::Import(ref import) => { - let import = import.read(); - self.add_stylesheet(&import.stylesheet) + let import = import.read_with(guard); + self.add_stylesheet(&import.stylesheet, guard) } 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); - let animation = KeyframesAnimation::from_keyframes(&keyframes_rule.keyframes); + let animation = KeyframesAnimation::from_keyframes( + &keyframes_rule.keyframes, guard); debug!("Found valid keyframe animation: {:?}", 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 /// flows. pub fn precomputed_values_for_pseudo(&self, + guards: &StylesheetGuards, pseudo: &PseudoElement, parent: Option<&Arc>, cascade_flags: CascadeFlags) @@ -327,6 +333,7 @@ impl Stylist { let computed = properties::cascade(&self.device, &rule_node, + guards, parent.map(|p| &**p), parent.map(|p| &**p), None, @@ -338,6 +345,7 @@ impl Stylist { /// Returns the style for an anonymous box of the given type. #[cfg(feature = "servo")] pub fn style_for_anonymous_box(&self, + guards: &StylesheetGuards, pseudo: &PseudoElement, parent_style: &Arc) -> Arc { @@ -362,7 +370,7 @@ impl Stylist { if 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() } @@ -374,6 +382,7 @@ impl Stylist { /// Check the documentation on lazy pseudo-elements in /// docs/components/style.md pub fn lazily_compute_pseudo_element_style(&self, + guards: &StylesheetGuards, element: &E, pseudo: &PseudoElement, parent: &Arc) @@ -395,6 +404,7 @@ impl Stylist { None, AnimationRules(None, None), Some(pseudo), + guards, &mut declarations, &mut flags); @@ -409,6 +419,7 @@ impl Stylist { let computed = properties::cascade(&self.device, &rule_node, + guards, Some(&**parent), Some(&**parent), None, @@ -461,9 +472,10 @@ impl Stylist { /// FIXME(emilio): The semantics of the device for Servo and Gecko are /// different enough we may want to unify them. #[cfg(feature = "servo")] - pub fn set_device(&mut self, mut device: Device, stylesheets: &[Arc]) { + pub fn set_device(&mut self, mut device: Device, guard: &SharedRwLockReadGuard, + stylesheets: &[Arc]) { let cascaded_rule = ViewportRule { - declarations: viewport::Cascade::from_stylesheets(stylesheets, &device).finish(), + declarations: viewport::Cascade::from_stylesheets(stylesheets, guard, &device).finish(), }; self.viewport_constraints = @@ -473,15 +485,16 @@ impl Stylist { 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 { - 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 mq.evaluate(before) != mq.evaluate(after) { return true } } - mq_eval_changed(rules, before, after) + mq_eval_changed(guard, rules, before, after) }); if changed { return true @@ -490,12 +503,12 @@ impl Stylist { false } 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) { 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); @@ -528,9 +541,10 @@ impl Stylist { &self, element: &E, parent_bf: Option<&BloomFilter>, - style_attribute: Option<&Arc>>, + style_attribute: Option<&Arc>>, animation_rules: AnimationRules, pseudo_element: Option<&PseudoElement>, + guards: &StylesheetGuards, applicable_declarations: &mut V, flags: &mut ElementSelectorFlags) -> StyleRelations where E: TElement + @@ -556,6 +570,7 @@ impl Stylist { // Step 1: Normal user-agent rules. map.user_agent.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -580,6 +595,7 @@ impl Stylist { // Step 3: User and author normal rules. map.user.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -587,6 +603,7 @@ impl Stylist { debug!("user normal: {:?}", relations); map.author.get_all_matching_rules(element, parent_bf, + guards.author, applicable_declarations, &mut relations, flags, @@ -595,7 +612,7 @@ impl Stylist { // Step 4: Normal style attributes. if let Some(sa) = style_attribute { - if sa.read().any_normal() { + if sa.read_with(guards.author).any_normal() { relations |= AFFECTED_BY_STYLE_ATTRIBUTE; Push::push( applicable_declarations, @@ -621,6 +638,7 @@ impl Stylist { // Step 6: Author-supplied `!important` rules. map.author.get_all_matching_rules(element, parent_bf, + guards.author, applicable_declarations, &mut relations, flags, @@ -630,7 +648,7 @@ impl Stylist { // Step 7: `!important` style attributes. if let Some(sa) = style_attribute { - if sa.read().any_important() { + if sa.read_with(guards.author).any_important() { relations |= AFFECTED_BY_STYLE_ATTRIBUTE; Push::push( applicable_declarations, @@ -644,6 +662,7 @@ impl Stylist { // Step 8: User `!important` rules. map.user.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -657,6 +676,7 @@ impl Stylist { // Step 9: UA `!important` rules. map.user_agent.get_all_matching_rules(element, parent_bf, + guards.ua_or_user, applicable_declarations, &mut relations, flags, @@ -895,6 +915,7 @@ impl SelectorMap { pub fn get_all_matching_rules(&self, element: &E, parent_bf: Option<&BloomFilter>, + guard: &SharedRwLockReadGuard, matching_rules_list: &mut V, relations: &mut StyleRelations, flags: &mut ElementSelectorFlags, @@ -913,6 +934,7 @@ impl SelectorMap { parent_bf, &self.id_hash, &id, + guard, matching_rules_list, relations, flags, @@ -924,6 +946,7 @@ impl SelectorMap { parent_bf, &self.class_hash, class, + guard, matching_rules_list, relations, flags, @@ -939,6 +962,7 @@ impl SelectorMap { parent_bf, local_name_hash, element.get_local_name(), + guard, matching_rules_list, relations, flags, @@ -947,6 +971,7 @@ impl SelectorMap { SelectorMap::get_matching_rules(element, parent_bf, &self.other_rules, + guard, matching_rules_list, relations, flags, @@ -960,6 +985,7 @@ impl SelectorMap { /// Append to `rule_list` all universal Rules (rules with selector `*|*`) in /// `self` sorted by specificity and source order. pub fn get_universal_rules(&self, + guard: &SharedRwLockReadGuard, cascade_level: CascadeLevel, important_cascade_level: CascadeLevel) -> Vec { @@ -977,8 +1003,8 @@ impl SelectorMap { for rule in self.other_rules.iter() { if rule.selector.compound_selector.is_empty() && rule.selector.next.is_none() { - let guard = rule.style_rule.read(); - let block = guard.block.read(); + let style_rule = rule.style_rule.read_with(guard); + let block = style_rule.block.read_with(guard); if block.any_normal() { matching_rules_list.push( rule.to_applicable_declaration_block(cascade_level)); @@ -1006,6 +1032,7 @@ impl SelectorMap { parent_bf: Option<&BloomFilter>, hash: &FnvHashMap>, key: &BorrowedStr, + guard: &SharedRwLockReadGuard, matching_rules: &mut Vector, relations: &mut StyleRelations, flags: &mut ElementSelectorFlags, @@ -1019,6 +1046,7 @@ impl SelectorMap { SelectorMap::get_matching_rules(element, parent_bf, rules, + guard, matching_rules, relations, flags, @@ -1030,6 +1058,7 @@ impl SelectorMap { fn get_matching_rules(element: &E, parent_bf: Option<&BloomFilter>, rules: &[Rule], + guard: &SharedRwLockReadGuard, matching_rules: &mut V, relations: &mut StyleRelations, flags: &mut ElementSelectorFlags, @@ -1038,8 +1067,8 @@ impl SelectorMap { V: VecLike { for rule in rules.iter() { - let guard = rule.style_rule.read(); - let block = guard.block.read(); + let style_rule = rule.style_rule.read_with(guard); + let block = style_rule.block.read_with(guard); let any_declaration_for_importance = if cascade_level.is_important() { block.any_important() } else { @@ -1137,7 +1166,7 @@ pub struct Rule { pub selector: Arc>, /// The actual style rule. #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] - pub style_rule: Arc>, + pub style_rule: Arc>, /// The source order this style rule appears in. pub source_order: usize, /// The specificity of the rule this selector represents. @@ -1178,7 +1207,7 @@ impl ApplicableDeclarationBlock { /// Constructs an applicable declaration block from a given property /// declaration block and importance. #[inline] - pub fn from_declarations(declarations: Arc>, + pub fn from_declarations(declarations: Arc>, level: CascadeLevel) -> Self { ApplicableDeclarationBlock { diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 5c413b9c6bb..1b7c8042bae 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -312,7 +312,8 @@ pub trait DomTraversal : Sync { } /// Helper for the function below. -fn resolve_style_internal(context: &mut StyleContext, element: E, ensure_data: &F) +fn resolve_style_internal(context: &mut StyleContext, + element: E, ensure_data: &F) -> Option where E: TElement, F: Fn(E), diff --git a/components/style/viewport.rs b/components/style/viewport.rs index 9c364dc7249..690c06fd377 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -15,6 +15,7 @@ use cssparser::ToCss as ParserToCss; use euclid::size::TypedSize2D; use media_queries::Device; use parser::{ParserContext, log_css_error}; +use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use std::ascii::AsciiExt; use std::borrow::Cow; use std::fmt; @@ -504,9 +505,10 @@ impl ViewportRule { } } -impl ToCss for ViewportRule { +impl ToCssWithGuard for ViewportRule { // Serialization of ViewportRule is not specced. - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result + where W: fmt::Write { try!(dest.write_str("@viewport { ")); let mut iter = self.declarations.iter(); 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, I::Item: AsRef, { let mut cascade = Self::new(); 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 { cascade.add(Cow::Borrowed(declaration)) } diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index 9ed52128eaf..40e9b7e65ad 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -20,9 +20,7 @@ env_logger = {version = "0.4", default-features = false} # disable `regex` to re lazy_static = "0.2" libc = "0.2" log = {version = "0.3.5", features = ["release_max_level_info"]} -num_cpus = "1.1.0" parking_lot = "0.3" -rayon = "0.6" selectors = {path = "../../components/selectors"} servo_url = {path = "../../components/url"} style = {path = "../../components/style", features = ["gecko"]} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 16d8b0c9f36..177a6c076e8 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -6,13 +6,10 @@ use atomic_refcell::AtomicRefMut; use cssparser::Parser; use cssparser::ToCss as ParserToCss; use env_logger::LogBuilder; -use num_cpus; use parking_lot::RwLock; -use rayon; use selectors::Element; use servo_url::ServoUrl; use std::borrow::Cow; -use std::cmp; use std::env; use std::fmt::Write; use std::ptr; @@ -24,6 +21,7 @@ use style::data::{ElementData, ElementStyles, RestyleData}; use style::dom::{ShowSubtreeData, TElement, TNode}; use style::error_reporting::StdoutErrorReporter; use style::gecko::data::{PerDocumentStyleData, PerDocumentStyleDataImpl}; +use style::gecko::global_style_data::GLOBAL_STYLE_DATA; use style::gecko::restyle_damage::GeckoRestyleDamage; use style::gecko::selector_parser::{SelectorImpl, PseudoElement}; use style::gecko::traversal::RecalcStyleOnly; @@ -76,6 +74,7 @@ use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::selector_parser::PseudoElementCascadeType; use style::sequential; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; use style::string_cache::Atom; use style::stylesheets::{CssRule, CssRules, ImportRule, MediaRule, NamespaceRule}; use style::stylesheets::{Origin, Stylesheet, StyleRule}; @@ -85,7 +84,7 @@ use style::thread_state; use style::timer::Timer; use style::traversal::{resolve_style, DomTraversal, TraversalDriver}; 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 @@ -95,44 +94,7 @@ use stylesheet_loader::StylesheetLoader; * 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, -} - -impl GlobalStyleData { - pub fn new() -> Self { - let stylo_threads = env::var("STYLO_THREADS") - .map(|s| s.parse::().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] pub extern "C" fn Servo_Initialize() { @@ -160,12 +122,14 @@ pub extern "C" fn Servo_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 = ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone()); SharedStyleContext { stylist: per_doc_data.stylist.clone(), + guards: StylesheetGuards::same(guard), running_animations: per_doc_data.running_animations.clone(), expired_animations: per_doc_data.expired_animations.clone(), // FIXME(emilio): Stop boxing here. @@ -198,8 +162,9 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed, debug!("Traversing subtree:"); debug!("{:?}", ShowSubtreeData(element.as_node())); - let shared_style_context = create_shared_context(&per_doc_data); - let ref global_style_data = *GLOBAL_STYLE_DATA; + let 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() { TraversalDriver::Sequential @@ -328,6 +293,7 @@ pub extern "C" fn Servo_Element_ClearData(element: RawGeckoElementBorrowed) { #[no_mangle] 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 extra_data = ParserContextExtraData::default(); let origin = match mode { @@ -335,8 +301,9 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl SheetParsingMode::eUserSheetFeatures => Origin::User, SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, }; + let shared_lock = global_style_data.shared_lock.clone(); Arc::new(Stylesheet::from_str( - "", url, origin, Default::default(), None, + "", url, origin, Default::default(), shared_lock, None, &StdoutErrorReporter, extra_data) ).into_strong() } @@ -351,6 +318,7 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader, referrer: *mut ThreadSafeURIHolder, principal: *mut ThreadSafePrincipalHolder) -> RawServoStyleSheetStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; let input = unsafe { data.as_ref().unwrap().as_str_unchecked() }; let origin = match mode { @@ -378,8 +346,9 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader, Some(ref s) => Some(s), }; + let shared_lock = global_style_data.shared_lock.clone(); Arc::new(Stylesheet::from_str( - input, url, origin, Default::default(), loader, + input, url, origin, Default::default(), shared_lock, loader, &StdoutErrorReporter, extra_data) ).into_strong() } @@ -413,23 +382,22 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet }; 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] pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, 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 sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets.push(sheet.clone()); data.stylesheets_changed = true; 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, raw_sheet: RawServoStyleSheetBorrowed, 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 sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets.insert(0, sheet.clone()); data.stylesheets_changed = true; 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_reference: RawServoStyleSheetBorrowed, 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 sheet = HasArcFFI::as_arc(&raw_sheet); 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_changed = true; 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, raw_sheet: RawServoStyleSheetBorrowed, 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 sheet = HasArcFFI::as_arc(&raw_sheet); data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet)); data.stylesheets_changed = true; if flush { - data.flush_stylesheets(); + data.flush_stylesheets(&guard); } } #[no_mangle] 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(); - data.flush_stylesheets(); + data.flush_stylesheets(&guard); } #[no_mangle] @@ -491,7 +467,9 @@ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(raw_data: RawServoStyleS #[no_mangle] 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] @@ -502,7 +480,9 @@ pub extern "C" fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed) - #[no_mangle] pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed, result: nsTArrayBorrowed_uintptr_t) { - let rules = RwLock::::as_arc(&rules).read(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rules = Locked::::as_arc(&rules).read_with(&guard); let iter = rules.0.iter().map(|rule| rule.rule_type() as usize); let (size, upper) = iter.size_hint(); 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, rule: *const nsACString, index: u32, nested: bool, rule_type: *mut u16) -> nsresult { - let rules = RwLock::::as_arc(&rules); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let rules = Locked::::as_arc(&rules); let sheet = Stylesheet::as_arc(&sheet); 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) => { *unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16; nsresult::NS_OK @@ -528,8 +510,10 @@ pub extern "C" fn Servo_CssRules_InsertRule(rules: ServoCssRulesBorrowed, sheet: #[no_mangle] pub extern "C" fn Servo_CssRules_DeleteRule(rules: ServoCssRulesBorrowed, index: u32) -> nsresult { - let rules = RwLock::::as_arc(&rules); - match rules.write().remove_rule(index as usize) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let rules = Locked::::as_arc(&rules); + match rules.write_with(&mut guard).remove_rule(index as usize) { Ok(_) => nsresult::NS_OK, Err(err) => err.into() } @@ -543,7 +527,9 @@ macro_rules! impl_basic_rule_funcs { } => { #[no_mangle] pub extern "C" fn $getter(rules: ServoCssRulesBorrowed, index: u32) -> Strong<$raw_type> { - let rules = RwLock::::as_arc(&rules).read(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rules = Locked::::as_arc(&rules).read_with(&guard); match rules.0[index as usize] { CssRule::$name(ref rule) => rule.clone().into_strong(), _ => { @@ -555,15 +541,19 @@ macro_rules! impl_basic_rule_funcs { #[no_mangle] 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() }; - write!(result, "{:?}", *rule.read()).unwrap(); + write!(result, "{:?}", *rule.read_with(&guard)).unwrap(); } #[no_mangle] pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) { - let rule = RwLock::<$rule_type>::as_arc(&rule); - rule.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + 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] pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong { - let rule = RwLock::::as_arc(&rule); - rule.read().block.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).block.clone().into_strong() } #[no_mangle] pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed, declarations: RawServoDeclarationBlockBorrowed) { - let rule = RwLock::::as_arc(&rule); - let declarations = RwLock::::as_arc(&declarations); - rule.write().block = declarations.clone(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let rule = Locked::::as_arc(&rule); + let declarations = Locked::::as_arc(&declarations); + rule.write_with(&mut guard).block = declarations.clone(); } #[no_mangle] pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) { - let rule = RwLock::::as_arc(&rule); - rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); } #[no_mangle] pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong { - let rule = RwLock::::as_arc(&rule); - rule.read().media_queries.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).media_queries.clone().into_strong() } #[no_mangle] pub extern "C" fn Servo_MediaRule_GetRules(rule: RawServoMediaRuleBorrowed) -> ServoCssRulesStrong { - let rule = RwLock::::as_arc(&rule); - rule.read().rules.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).rules.clone().into_strong() } #[no_mangle] pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom { - let rule = RwLock::::as_arc(&rule); - rule.read().prefix.as_ref().unwrap_or(&atom!("")).as_ptr() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).prefix.as_ref().unwrap_or(&atom!("")).as_ptr() } #[no_mangle] pub extern "C" fn Servo_NamespaceRule_GetURI(rule: RawServoNamespaceRuleBorrowed) -> *mut nsIAtom { - let rule = RwLock::::as_arc(&rule); - rule.read().url.0.as_ptr() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let rule = Locked::::as_arc(&rule); + rule.read_with(&guard).url.0.as_ptr() } #[no_mangle] @@ -636,6 +640,9 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: skip_display_fixup: bool, raw_data: RawServoStyleSetBorrowed) -> 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 atom = Atom::from(pseudo_tag); 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 { 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) .values.unwrap() .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(), None if !is_probe => data.styles().primary.values().clone().into_strong(), 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) -> Option> { @@ -690,7 +699,9 @@ fn get_pseudo_style(element: GeckoElement, pseudo_tag: *mut nsIAtom, PseudoElementCascadeType::Lazy => { let d = doc_data.borrow_mut(); 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, base) .map(|s| s.values().clone()) @@ -725,8 +736,10 @@ pub extern "C" fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned) #[no_mangle] 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(); - data.reset_device(); + data.reset_device(&guard); } #[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) { Ok(parsed) => { + let global_style_data = &*GLOBAL_STYLE_DATA; let mut block = PropertyDeclarationBlock::new(); 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() } @@ -781,36 +795,47 @@ pub extern "C" fn Servo_ParseStyleAttribute(data: *const nsACString, base: *const nsACString, raw_extra_data: *const structs::GeckoParserExtraData) -> RawServoDeclarationBlockStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; let value = unsafe { data.as_ref().unwrap().as_str_unchecked() }; 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] 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] pub extern "C" fn Servo_DeclarationBlock_Clone(declarations: RawServoDeclarationBlockBorrowed) -> RawServoDeclarationBlockStrong { - let declarations = RwLock::::as_arc(&declarations); - Arc::new(RwLock::new(declarations.read().clone())).into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + Arc::new(global_style_data.shared_lock.wrap( + declarations.read_with(&guard).clone() + )).into_strong() } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed, b: RawServoDeclarationBlockBorrowed) -> bool { - *RwLock::::as_arc(&a).read().declarations() == - *RwLock::::as_arc(&b).read().declarations() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + *Locked::::as_arc(&a).read_with(&guard).declarations() == + *Locked::::as_arc(&b).read_with(&guard).declarations() } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed, result: *mut nsAString) { - let declarations = RwLock::::as_arc(&declarations); - declarations.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap(); } #[no_mangle] @@ -819,9 +844,11 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( property_id: nsCSSPropertyID, buffer: *mut nsAString) { let property_id = get_property_id_from_nscsspropertyid!(property_id, ()); - let declarations = RwLock::::as_arc(&declarations); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); 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()); write!(unsafe { &mut *buffer }, "{}", string).expect("Failed to copy string"); @@ -829,15 +856,19 @@ pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 { - let declarations = RwLock::::as_arc(&declarations); - declarations.read().declarations().len() as u32 + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard).declarations().len() as u32 } #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDeclarationBlockBorrowed, index: u32, result: *mut nsAString) -> bool { - let declarations = RwLock::::as_arc(&declarations); - if let Some(&(ref decl, _)) = declarations.read().declarations().get(index as usize) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + if let Some(&(ref decl, _)) = declarations.read_with(&guard).declarations().get(index as usize) { let result = unsafe { result.as_mut().unwrap() }; decl.id().to_css(result).unwrap(); true @@ -858,8 +889,12 @@ macro_rules! get_property_id_from_property { fn get_property_value(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId, value: *mut nsAString) { - let declarations = RwLock::::as_arc(&declarations); - declarations.read().property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard) + .property_value_to_css(&property_id, unsafe { value.as_mut().unwrap() }) + .unwrap(); } #[no_mangle] @@ -878,8 +913,10 @@ pub extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(declarations: RawS pub extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(declarations: RawServoDeclarationBlockBorrowed, property: *const nsACString) -> bool { let property_id = get_property_id_from_property!(property, false); - let declarations = RwLock::::as_arc(&declarations); - declarations.read().property_priority(&property_id).important() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let declarations = Locked::::as_arc(&declarations); + declarations.read_with(&guard).property_priority(&property_id).important() } 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)); if let Ok(parsed) = parse_one_declaration(property_id, value, &base_url, &StdoutErrorReporter, extra_data) { - let mut declarations = RwLock::::as_arc(&declarations).write(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let declarations = Locked::::as_arc(&declarations) + .write_with(&mut guard); let importance = if is_important { Importance::Important } else { Importance::Normal }; let mut changed = false; parsed.expand(|decl| { @@ -923,8 +963,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetPropertyById(declarations: RawServoD } fn remove_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId) { - let declarations = RwLock::::as_arc(&declarations); - declarations.write().remove_property(&property_id); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let declarations = Locked::::as_arc(&declarations); + declarations.write_with(&mut guard).remove_property(&property_id); } #[no_mangle] @@ -941,29 +983,37 @@ pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(declarations: RawSer #[no_mangle] pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) { - let list = RwLock::::as_arc(&list); - list.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap(); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let list = Locked::::as_arc(&list); + list.read_with(&guard).to_css(unsafe { result.as_mut().unwrap() }).unwrap(); } #[no_mangle] pub extern "C" fn Servo_MediaList_SetText(list: RawServoMediaListBorrowed, text: *const nsACString) { - let list = RwLock::::as_arc(&list); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let list = Locked::::as_arc(&list); let text = unsafe { text.as_ref().unwrap().as_str_unchecked() }; 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] pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 { - let list = RwLock::::as_arc(&list); - list.read().media_queries.len() as u32 + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let list = Locked::::as_arc(&list); + list.read_with(&guard).media_queries.len() as u32 } #[no_mangle] pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, index: u32, result: *mut nsAString) -> bool { - let list = RwLock::::as_arc(&list); - if let Some(media_query) = list.read().media_queries.get(index as usize) { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let list = Locked::::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(); true } else { @@ -974,17 +1024,21 @@ pub extern "C" fn Servo_MediaList_GetMediumAt(list: RawServoMediaListBorrowed, i #[no_mangle] pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed, new_medium: *const nsACString) { - let list = RwLock::::as_arc(&list); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let list = Locked::::as_arc(&list); 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] pub extern "C" fn Servo_MediaList_DeleteMedium(list: RawServoMediaListBorrowed, old_medium: *const nsACString) -> bool { - let list = RwLock::::as_arc(&list); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + let list = Locked::::as_arc(&list); 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 { @@ -1022,9 +1076,11 @@ pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(declarations: property: nsCSSPropertyID) -> bool { use style::properties::PropertyDeclarationId; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); 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] @@ -1037,12 +1093,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::longhands::_x_lang::computed_value::T as Lang; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let prop = match_wrap_declared! { long, 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] @@ -1055,7 +1113,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: use style::properties::longhands; use style::values::specified::{BorderStyle, NoCalcLength}; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let value = value as u32; @@ -1079,7 +1137,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: BorderBottomStyle => 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] @@ -1089,12 +1149,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetIntValue(declarations: RawServoDecla use style::properties::{PropertyDeclaration, LonghandId}; use style::properties::longhands::_x_span::computed_value::T as Span; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let prop = match_wrap_declared! { long, 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] @@ -1107,7 +1169,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations: use style::values::specified::BorderWidth; use style::values::specified::length::NoCalcLength; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); 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] @@ -1144,7 +1208,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::values::specified::length::Percentage; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let pc = Percentage(value); @@ -1156,7 +1220,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations: MarginBottom => 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] @@ -1166,7 +1232,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::values::specified::LengthOrPercentageOrAuto; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let auto = LengthOrPercentageOrAuto::Auto; @@ -1178,7 +1244,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations: MarginBottom => 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] @@ -1188,7 +1256,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations: use style::properties::{PropertyDeclaration, LonghandId}; use style::values::specified::{Color, CSSColor}; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let cc = CSSColor { parsed: Color::CurrentColor, authored: None }; @@ -1198,7 +1266,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations: BorderBottomColor => 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] @@ -1211,7 +1281,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations: use style::properties::longhands; use style::values::specified::{Color, CSSColor}; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let long = get_longhand_from_id!(property); let rgba = convert_nscolor_to_rgba(value); 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), 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] @@ -1235,13 +1307,15 @@ pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations: use style::properties::PropertyDeclaration; use style::properties::longhands::font_family::SpecifiedValue as FontFamily; - let declarations = RwLock::::as_arc(&declarations); + let declarations = Locked::::as_arc(&declarations); let string = unsafe { (*value).to_string() }; let mut parser = Parser::new(&string); if let Ok(family) = FontFamily::parse(&mut parser) { 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); - 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::longhands::text_decoration_line; - let declarations = RwLock::::as_arc(&declarations); + let global_style_data = &*GLOBAL_STYLE_DATA; + let mut guard = global_style_data.shared_lock.write(); + + let declarations = Locked::::as_arc(&declarations); let mut decoration = text_decoration_line::computed_value::none; decoration |= text_decoration_line::COLOR_OVERRIDE; let decl = PropertyDeclaration::TextDecorationLine(decoration); - declarations.write().push(decl, Importance::Normal); + declarations.write_with(&mut guard).push(decl, Importance::Normal); } #[no_mangle] @@ -1357,8 +1434,10 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed, pub extern "C" fn Servo_ImportRule_GetSheet(import_rule: RawServoImportRuleBorrowed) -> RawServoStyleSheetStrong { - let import_rule = RwLock::::as_arc(&import_rule); - import_rule.read().stylesheet.clone().into_strong() + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let import_rule = Locked::::as_arc(&import_rule); + import_rule.read_with(&guard).stylesheet.clone().into_strong() } #[no_mangle] @@ -1402,11 +1481,13 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed, raw_data: RawServoStyleSetBorrowed) -> ServoComputedValuesStrong { + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); let element = GeckoElement(element); let doc_data = PerDocumentStyleData::from_ffi(raw_data); let finish = |styles: &ElementStyles| -> Arc { 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 { 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. - 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 context = StyleContext { shared: &shared, @@ -1446,6 +1527,11 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis use style::properties::LonghandIdSet; use style::properties::declaration_block::Importance; 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 style = ComputedValues::as_arc(&style); @@ -1472,8 +1558,8 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis .filter(|&property| !property.mServoDeclarationBlock.mRawPtr.is_null()); for property in iter { let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() }; - let declarations = RwLock::::as_arc(&declarations); - let guard = declarations.read(); + let declarations = Locked::::as_arc(&declarations); + let guard = declarations.read_with(&guard); let anim_iter = guard.declarations() .iter() @@ -1537,15 +1623,18 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet use style::gecko_bindings::structs::Keyframe; use style::properties::LonghandIdSet; + let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); let name = unsafe { Atom::from(name.as_ref().unwrap().as_str_unchecked()) }; let style_timing_function = unsafe { timing_function.as_ref().unwrap() }; let style = ComputedValues::as_arc(&style); 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 { // 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() } else { *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, index: usize, style: &ComputedValues, - property: &TransitionProperty) { + property: &TransitionProperty, + shared_lock: &SharedRwLock) { let block = style.to_declaration_block(property.clone().into()); unsafe { (*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 // with additive composition. (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( - Arc::new(RwLock::new(block))); + Arc::new(shared_lock.wrap(block))); } } match step.value { KeyframesStepValue::ComputedValues => { 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 } => { - let guard = block.read(); + let guard = block.read_with(&guard); // Filter out non-animatable properties. let animatable = 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[index].mProperty = property.into(); (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( - declaration.clone(), Importance::Normal + Arc::new(global_style_data.shared_lock.wrap( + PropertyDeclarationBlock::with_one( + declaration.clone(), Importance::Normal )))); if step.start_percentage.0 == 0. || 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() }; for property in animation.properties_changed.iter() { 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; } } diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index 0bdbaa12f24..a7dd0561299 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -10,9 +10,7 @@ extern crate env_logger; #[macro_use] extern crate lazy_static; extern crate libc; #[macro_use] extern crate log; -extern crate num_cpus; extern crate parking_lot; -extern crate rayon; extern crate selectors; extern crate servo_url; #[macro_use] extern crate style; diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs index 3e6fb421c86..d904f1b9870 100644 --- a/ports/geckolib/stylesheet_loader.rs +++ b/ports/geckolib/stylesheet_loader.rs @@ -2,11 +2,12 @@ * 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 parking_lot::RwLock; use std::sync::Arc; use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; use style::gecko_bindings::structs::{Loader, ServoStyleSheet}; 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_traits::ToCss; @@ -19,11 +20,12 @@ impl StylesheetLoader { } impl StyleStylesheetLoader for StylesheetLoader { - fn request_stylesheet(&self, import_rule: &Arc>) { - let import = import_rule.read(); - let (spec_bytes, spec_len) = import.url.as_slice_components() - .expect("Import only loads valid URLs"); - + fn request_stylesheet( + &self, + media: MediaList, + make_import: &mut FnMut(MediaList) -> ImportRule, + make_arc: &mut FnMut(ImportRule) -> Arc>, + ) -> Arc> { // TODO(emilio): We probably want to share media representation with // Gecko in Stylo. // @@ -32,16 +34,27 @@ impl StyleStylesheetLoader for StylesheetLoader { // evaluate them on the main thread. // // 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 pointer inside will also move, + // but the Url it points to or the allocating backing the String inside that Url won’t, + // 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 { Gecko_LoadStyleSheet(self.0, self.1, - HasArcFFI::arc_as_borrowed(import_rule), + HasArcFFI::arc_as_borrowed(&arc), spec_bytes, spec_len as u32, - media.as_bytes().as_ptr(), - media.len() as u32); + media_string.as_bytes().as_ptr(), + media_string.len() as u32); } + arc } } diff --git a/tests/unit/style/Cargo.toml b/tests/unit/style/Cargo.toml index 98838676937..7939e617342 100644 --- a/tests/unit/style/Cargo.toml +++ b/tests/unit/style/Cargo.toml @@ -17,7 +17,6 @@ app_units = "0.4" cssparser = "0.12" euclid = "0.11" html5ever-atoms = "0.2" -owning_ref = "0.2.2" parking_lot = "0.3" rayon = "0.6" rustc-serialize = "0.3" diff --git a/tests/unit/style/keyframes.rs b/tests/unit/style/keyframes.rs index 051ff9ca792..9fe2f0d3f39 100644 --- a/tests/unit/style/keyframes.rs +++ b/tests/unit/style/keyframes.rs @@ -2,18 +2,19 @@ * 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 parking_lot::RwLock; use std::sync::Arc; use style::keyframes::{Keyframe, KeyframesAnimation, KeyframePercentage, KeyframeSelector}; use style::keyframes::{KeyframesStep, KeyframesStepValue}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, Importance}; use style::properties::animated_properties::TransitionProperty; +use style::shared_lock::SharedRwLock; use style::values::specified::{LengthOrPercentageOrAuto, NoCalcLength}; #[test] fn test_empty_keyframe() { + let shared_lock = SharedRwLock::new(); let keyframes = vec![]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![], properties_changed: vec![], @@ -24,13 +25,14 @@ fn test_empty_keyframe() { #[test] fn test_no_property_in_keyframe() { + let shared_lock = SharedRwLock::new(); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { 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 { steps: vec![], properties_changed: vec![], @@ -41,15 +43,16 @@ fn test_no_property_in_keyframe() { #[test] fn test_missing_property_in_initial_keyframe() { + let shared_lock = SharedRwLock::new(); let declarations_on_initial_keyframe = - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Width( LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))), Importance::Normal ))); let declarations_on_final_keyframe = - Arc::new(RwLock::new({ + Arc::new(shared_lock.wrap({ let mut block = PropertyDeclarationBlock::new(); block.push( PropertyDeclaration::Width( @@ -65,17 +68,17 @@ fn test_missing_property_in_initial_keyframe() { })); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), 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.)]), block: declarations_on_final_keyframe.clone(), })), ]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![ KeyframesStep { @@ -97,8 +100,9 @@ fn test_missing_property_in_initial_keyframe() { #[test] fn test_missing_property_in_final_keyframe() { + let shared_lock = SharedRwLock::new(); let declarations_on_initial_keyframe = - Arc::new(RwLock::new({ + Arc::new(shared_lock.wrap({ let mut block = PropertyDeclarationBlock::new(); block.push( PropertyDeclaration::Width( @@ -114,24 +118,24 @@ fn test_missing_property_in_final_keyframe() { })); let declarations_on_final_keyframe = - Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Height( LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(20f32))), Importance::Normal, ))); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing(vec![KeyframePercentage::new(0.)]), 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.)]), block: declarations_on_final_keyframe.clone(), })), ]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![ KeyframesStep { @@ -153,8 +157,9 @@ fn test_missing_property_in_final_keyframe() { #[test] fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { + let shared_lock = SharedRwLock::new(); let declarations = - Arc::new(RwLock::new({ + Arc::new(shared_lock.wrap({ let mut block = PropertyDeclarationBlock::new(); block.push( PropertyDeclaration::Width( @@ -170,22 +175,22 @@ fn test_missing_keyframe_in_both_of_initial_and_final_keyframe() { })); let keyframes = vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(shared_lock.wrap(Keyframe { 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)]), block: declarations.clone(), })), ]; - let animation = KeyframesAnimation::from_keyframes(&keyframes); + let animation = KeyframesAnimation::from_keyframes(&keyframes, &shared_lock.read()); let expected = KeyframesAnimation { steps: vec![ KeyframesStep { start_percentage: KeyframePercentage(0.), value: KeyframesStepValue::Declarations { - block: Arc::new(RwLock::new( + block: Arc::new(shared_lock.wrap( // XXX: Should we use ComputedValues in this case? PropertyDeclarationBlock::new() )) diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index 9d7cdcae651..887de470ffa 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -9,7 +9,6 @@ extern crate app_units; extern crate cssparser; extern crate euclid; #[macro_use] extern crate html5ever_atoms; -extern crate owning_ref; extern crate parking_lot; extern crate rayon; extern crate rustc_serialize; @@ -26,7 +25,6 @@ mod attr; mod keyframes; mod logical_geometry; mod media_queries; -mod owning_handle; mod parsing; mod properties; mod rule_tree; diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs index 95182676e3c..3d2f2809a63 100644 --- a/tests/unit/style/media_queries.rs +++ b/tests/unit/style/media_queries.rs @@ -11,6 +11,7 @@ use style::error_reporting::ParseErrorReporter; use style::media_queries::*; use style::parser::ParserContextExtraData; use style::servo::media_queries::*; +use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard}; use style::stylesheets::{Stylesheet, Origin, CssRule}; use style::values::specified; use style_traits::ToCss; @@ -29,26 +30,27 @@ fn test_media_rule(css: &str, callback: F) let url = ServoUrl::parse("http://localhost").unwrap(); let css_str = css.to_owned(); let stylesheet = Stylesheet::from_str( - css, url, Origin::Author, Default::default(), + css, url, Origin::Author, Default::default(), SharedRwLock::new(), None, &CSSErrorReporterTest, ParserContextExtraData::default()); 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; callback(mq, css); }); assert!(rule_count > 0, css_str); } -fn media_queries(rules: &[CssRule], f: &mut F) +fn media_queries(guard: &SharedRwLockReadGuard, rules: &[CssRule], f: &mut F) where F: FnMut(&MediaList), { 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 { f(mq) } - media_queries(rules, f) + media_queries(guard, rules, f) }) } } @@ -56,11 +58,11 @@ fn media_queries(rules: &[CssRule], f: &mut F) fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) { let url = ServoUrl::parse("http://localhost").unwrap(); let ss = Stylesheet::from_str( - css, url, Origin::Author, Default::default(), + css, url, Origin::Author, Default::default(), SharedRwLock::new(), None, &CSSErrorReporterTest, ParserContextExtraData::default()); 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()); } diff --git a/tests/unit/style/owning_handle.rs b/tests/unit/style/owning_handle.rs deleted file mode 100644 index cf792ef9605..00000000000 --- a/tests/unit/style/owning_handle.rs +++ /dev/null @@ -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"); -} diff --git a/tests/unit/style/rule_tree/bench.rs b/tests/unit/style/rule_tree/bench.rs index 37bef590a64..4d4012f16c1 100644 --- a/tests/unit/style/rule_tree/bench.rs +++ b/tests/unit/style/rule_tree/bench.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cssparser::{Parser, SourcePosition}; -use parking_lot::RwLock; use rayon; use servo_url::ServoUrl; use std::sync::Arc; @@ -12,6 +11,7 @@ use style::media_queries::MediaList; use style::parser::ParserContextExtraData; use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock}; use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; +use style::shared_lock::SharedRwLock; use style::stylesheets::{Origin, Stylesheet, CssRule}; use test::{self, Bencher}; @@ -44,10 +44,12 @@ fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> { MediaList { media_queries: vec![], }, + SharedRwLock::new(), None, &ErrorringErrorReporter, 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| { match *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()) } -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(); - 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( longhands::display::SpecifiedValue::block), Importance::Normal @@ -118,11 +122,12 @@ fn bench_expensive_insertion(b: &mut Bencher) { .bar { height: 500px; } \ .baz { display: block; }"); + let shared_lock = SharedRwLock::new(); b.iter(|| { let _gc = AutoGCRuleTree::new(&r); 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; } \ .baz { display: block; }"); + let shared_lock = SharedRwLock::new(); b.iter(|| { let _gc = AutoGCRuleTree::new(&r); @@ -175,12 +181,14 @@ fn bench_expensive_insersion_parallel(b: &mut Bencher) { s.spawn(|s| { for _ in 0..1000 { test::black_box(test_insertion_style_attribute(&r, - &rules_matched)); + &rules_matched, + &shared_lock)); } s.spawn(|_| { for _ in 0..100 { test::black_box(test_insertion_style_attribute(&r, - &rules_matched)); + &rules_matched, + &shared_lock)); } }) }) diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index a1d649c099c..fa6a26963f8 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -20,6 +20,7 @@ use style::properties::Importance; use style::properties::{CSSWideKeyword, DeclaredValueOwned, PropertyDeclaration, PropertyDeclarationBlock}; use style::properties::longhands; use style::properties::longhands::animation_play_state; +use style::shared_lock::SharedRwLock; use style::stylesheets::{Origin, Namespaces}; use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule}; use style::values::specified::{LengthOrPercentageOrAuto, Percentage}; @@ -62,24 +63,25 @@ fn test_parse_stylesheet() { }"; let url = ServoUrl::parse("about::test").unwrap(); let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(), - None, + SharedRwLock::new(), None, &CSSErrorReporterTest, ParserContextExtraData::default()); let mut namespaces = Namespaces::default(); namespaces.default = Some(ns!(html)); let expected = Stylesheet { 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), base_url: url, dirty_on_viewport_size_change: AtomicBool::new(false), disabled: AtomicBool::new(false), rules: CssRules::new(vec![ - CssRule::Namespace(Arc::new(RwLock::new(NamespaceRule { + CssRule::Namespace(Arc::new(stylesheet.shared_lock.wrap(NamespaceRule { prefix: None, 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![ Selector { complex_selector: Arc::new(ComplexSelector { @@ -107,7 +109,7 @@ fn test_parse_stylesheet() { 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), Importance::Important), (PropertyDeclaration::Custom(Atom::from("a"), @@ -115,7 +117,7 @@ fn test_parse_stylesheet() { Importance::Important), ]))), }))), - CssRule::Style(Arc::new(RwLock::new(StyleRule { + CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { selectors: SelectorList(vec![ Selector { complex_selector: Arc::new(ComplexSelector { @@ -152,12 +154,12 @@ fn test_parse_stylesheet() { 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), Importance::Normal), ]))), }))), - CssRule::Style(Arc::new(RwLock::new(StyleRule { + CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule { selectors: SelectorList(vec![ Selector { complex_selector: Arc::new(ComplexSelector { @@ -183,7 +185,7 @@ fn test_parse_stylesheet() { 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( longhands::background_color::SpecifiedValue { authored: Some("blue".to_owned().into_boxed_str()), @@ -233,22 +235,22 @@ fn test_parse_stylesheet() { Importance::Normal), ]))), }))), - CssRule::Keyframes(Arc::new(RwLock::new(KeyframesRule { + CssRule::Keyframes(Arc::new(stylesheet.shared_lock.wrap(KeyframesRule { name: "foo".into(), keyframes: vec![ - Arc::new(RwLock::new(Keyframe { + Arc::new(stylesheet.shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing( vec![KeyframePercentage::new(0.)]), - block: Arc::new(RwLock::new(block_from(vec![ + block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![ (PropertyDeclaration::Width( LengthOrPercentageOrAuto::Percentage(Percentage(0.))), Importance::Normal), ]))) })), - Arc::new(RwLock::new(Keyframe { + Arc::new(stylesheet.shared_lock.wrap(Keyframe { selector: KeyframeSelector::new_for_unit_testing( vec![KeyframePercentage::new(1.)]), - block: Arc::new(RwLock::new(block_from(vec![ + block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![ (PropertyDeclaration::Width( LengthOrPercentageOrAuto::Percentage(Percentage(1.))), Importance::Normal), @@ -261,7 +263,7 @@ fn test_parse_stylesheet() { ] }))) - ]), + ], &stylesheet.shared_lock), }; assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected)); @@ -324,7 +326,7 @@ fn test_report_error_stylesheet() { let errors = error_reporter.errors.clone(); Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(), - None, + SharedRwLock::new(), None, &error_reporter, ParserContextExtraData::default()); diff --git a/tests/unit/style/stylist.rs b/tests/unit/style/stylist.rs index ab04f2e5dd5..8f559703cbe 100644 --- a/tests/unit/style/stylist.rs +++ b/tests/unit/style/stylist.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use html5ever_atoms::LocalName; -use parking_lot::RwLock; use selectors::parser::LocalName as LocalNameSelector; use servo_atoms::Atom; use std::sync::Arc; @@ -11,40 +10,43 @@ use style::properties::{PropertyDeclarationBlock, PropertyDeclaration}; use style::properties::{longhands, Importance}; use style::rule_tree::CascadeLevel; use style::selector_parser::SelectorParser; +use style::shared_lock::SharedRwLock; use style::stylesheets::StyleRule; use style::stylist::{Rule, SelectorMap}; use style::thread_state; /// Helper method to get some Rules from selector strings. /// Each sublist of the result contains the Rules for one StyleRule. -fn get_mock_rules(css_selectors: &[&str]) -> Vec> { - css_selectors.iter().enumerate().map(|(i, selectors)| { +fn get_mock_rules(css_selectors: &[&str]) -> (Vec>, SharedRwLock) { + let shared_lock = SharedRwLock::new(); + (css_selectors.iter().enumerate().map(|(i, selectors)| { 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, - block: Arc::new(RwLock::new(PropertyDeclarationBlock::with_one( + block: Arc::new(shared_lock.wrap(PropertyDeclarationBlock::with_one( PropertyDeclaration::Display( longhands::display::SpecifiedValue::block), Importance::Normal ))), })); - let guard = rule.read(); - guard.selectors.0.iter().map(|s| { + let guard = shared_lock.read(); + let rule = locked.read_with(&guard); + rule.selectors.0.iter().map(|s| { Rule { selector: s.complex_selector.clone(), - style_rule: rule.clone(), + style_rule: locked.clone(), specificity: s.specificity, source_order: i, } }).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 selector_rules = get_mock_rules(selectors); + let (selector_rules, shared_lock) = get_mock_rules(selectors); for rules in selector_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] 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 b = &rules_list[1][0]; assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)), @@ -67,21 +69,21 @@ fn test_rule_ordering_same_specificity() { #[test] 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[1][0]), Some(Atom::from("top"))); } #[test] 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[1][0]), None); } #[test] 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)>| { assert!(SelectorMap::get_local_name(&rules_list[i][0]) == names.map(|(name, lower_name)| LocalNameSelector { @@ -96,7 +98,7 @@ fn test_get_local_name() { #[test] 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(); selector_map.insert(rules_list[1][0].clone()); assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order); @@ -108,10 +110,11 @@ fn test_insert() { #[test] fn test_get_universal_rules() { 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, - CascadeLevel::UserImportant); + let guard = shared_lock.read(); + let decls = map.get_universal_rules( + &guard, CascadeLevel::UserNormal, CascadeLevel::UserImportant); assert_eq!(decls.len(), 1); } diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index 166094ebdc1..7423286227d 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -9,6 +9,7 @@ use servo_config::prefs::{PREFS, PrefValue}; use servo_url::ServoUrl; use style::media_queries::{Device, MediaType}; use style::parser::{ParserContext, ParserContextExtraData}; +use style::shared_lock::SharedRwLock; use style::stylesheets::{Stylesheet, Origin}; use style::values::specified::LengthOrPercentageOrAuto::{self, Auto}; use style::values::specified::NoCalcLength::{self, ViewportPercentage}; @@ -19,11 +20,15 @@ use style_traits::viewport::*; macro_rules! stylesheet { ($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( $css, ServoUrl::parse("http://localhost").unwrap(), Origin::$origin, Default::default(), + $shared_lock, None, &$error_reporter, ParserContextExtraData::default() @@ -39,7 +44,7 @@ fn test_viewport_rule(css: &str, PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); let stylesheet = stylesheet!(css, Author, CSSErrorReporterTest); let mut rule_count = 0; - stylesheet.effective_viewport_rules(&device, |rule| { + stylesheet.effective_viewport_rules(&device, &stylesheet.shared_lock.read(), |rule| { rule_count += 1; callback(&rule.declarations, css); }); @@ -251,24 +256,31 @@ fn multiple_stylesheets_cascading() { PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.)); let error_reporter = CSSErrorReporterTest; + let shared_lock = SharedRwLock::new(); let stylesheets = vec![ - stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", UserAgent, error_reporter), - stylesheet!("@viewport { min-width: 200px; min-height: 200px; }", User, error_reporter), - stylesheet!("@viewport { min-width: 300px; }", Author, error_reporter)]; + stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", + UserAgent, error_reporter, shared_lock.clone()), + 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_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.)); assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px)); assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px)); 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; }", - User, error_reporter), + User, error_reporter, shared_lock.clone()), stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }", - Author, error_reporter)]; - let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish(); + Author, error_reporter, shared_lock.clone()) + ]; + let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish(); assert_decl_len!(declarations == 3); assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important); assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important); diff --git a/tests/unit/stylo/lib.rs b/tests/unit/stylo/lib.rs index c89687918ef..c0d04ffcbec 100644 --- a/tests/unit/stylo/lib.rs +++ b/tests/unit/stylo/lib.rs @@ -21,8 +21,5 @@ extern crate style_traits; mod sanity_checks; mod size_of; -#[path = "../../../ports/geckolib/stylesheet_loader.rs"] -mod stylesheet_loader; - mod servo_function_signatures; diff --git a/tests/unit/stylo/servo_function_signatures.rs b/tests/unit/stylo/servo_function_signatures.rs index 6bdeb6d5af7..30d6d02439b 100644 --- a/tests/unit/stylo/servo_function_signatures.rs +++ b/tests/unit/stylo/servo_function_signatures.rs @@ -10,6 +10,9 @@ use style::gecko_properties::*; 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)] mod glue { // this module pretends to be glue.rs, with the safe functions swapped for unsafe ones. This is