diff --git a/servo/components/layout/query.rs b/servo/components/layout/query.rs index 6b5940669630..c12a2b7f63d9 100644 --- a/servo/components/layout/query.rs +++ b/servo/components/layout/query.rs @@ -38,7 +38,6 @@ use style::logical_geometry::{WritingMode, BlockFlowDirection, InlineBaseDirecti use style::properties::{style_structs, PropertyId, PropertyDeclarationId, LonghandId}; use style::properties::longhands::{display, position}; use style::selector_parser::PseudoElement; -use style::stylist::Stylist; use style_traits::ToCss; use style_traits::cursor::Cursor; use webrender_traits::ClipId; @@ -54,9 +53,6 @@ pub struct LayoutThreadData { /// The root stacking context. pub display_list: Option>, - /// Performs CSS selector matching and style resolution. - pub stylist: ::StyleArc, - /// A queued response for the union of the content boxes of a node. pub content_box_response: Option>, diff --git a/servo/components/layout_thread/lib.rs b/servo/components/layout_thread/lib.rs index cf9be9178375..d67b1c8d23eb 100644 --- a/servo/components/layout_thread/lib.rs +++ b/servo/components/layout_thread/lib.rs @@ -95,6 +95,7 @@ use servo_config::resource_files::read_resource_file; use servo_geometry::max_rect; use servo_url::ServoUrl; use std::borrow::ToOwned; +use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::hash::BuildHasherDefault; use std::marker::PhantomData; @@ -131,6 +132,9 @@ pub struct LayoutThread { /// The URL of the pipeline that we belong to. url: ServoUrl, + /// Performs CSS selector matching and style resolution. + stylist: Stylist, + /// Is the current reflow of an iframe, as opposed to a root window? is_iframe: bool, @@ -165,7 +169,7 @@ pub struct LayoutThread { font_cache_thread: FontCacheThread, /// Is this the first reflow in this LayoutThread? - first_reflow: bool, + first_reflow: Cell, /// The workers that we use for parallel operation. parallel_traversal: Option, @@ -175,7 +179,7 @@ pub struct LayoutThread { /// Starts at zero, and increased by one every time a layout completes. /// This can be used to easily check for invalid stale data. - generation: u32, + generation: Cell, /// A channel on which new animations that have been triggered by style recalculation can be /// sent. @@ -188,7 +192,7 @@ pub struct LayoutThread { outstanding_web_fonts: Arc, /// The root of the flow tree. - root_flow: Option, + root_flow: RefCell>, /// The document-specific shared lock used for author-origin stylesheets document_shared_lock: Option, @@ -200,7 +204,7 @@ pub struct LayoutThread { expired_animations: StyleArc>>>, /// A counter for epoch messages - epoch: Epoch, + epoch: Cell, /// The size of the viewport. This may be different from the size of the screen due to viewport /// constraints. @@ -414,7 +418,7 @@ impl LayoutThread { let font_cache_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_font_cache_receiver); - let stylist = StyleArc::new(Stylist::new(device)); + let stylist = Stylist::new(device); let outstanding_web_fonts_counter = Arc::new(AtomicUsize::new(0)); let ua_stylesheets = &*UA_STYLESHEETS; let guard = ua_stylesheets.shared_lock.read(); @@ -439,27 +443,27 @@ impl LayoutThread { mem_profiler_chan: mem_profiler_chan, image_cache: image_cache.clone(), font_cache_thread: font_cache_thread, - first_reflow: true, + first_reflow: Cell::new(true), font_cache_receiver: font_cache_receiver, font_cache_sender: ipc_font_cache_sender, parallel_traversal: parallel_traversal, parallel_flag: true, - generation: 0, + generation: Cell::new(0), new_animations_sender: new_animations_sender, new_animations_receiver: new_animations_receiver, outstanding_web_fonts: outstanding_web_fonts_counter, - root_flow: None, + root_flow: RefCell::new(None), document_shared_lock: None, running_animations: StyleArc::new(RwLock::new(HashMap::new())), expired_animations: StyleArc::new(RwLock::new(HashMap::new())), - epoch: Epoch(0), + epoch: Cell::new(Epoch(0)), viewport_size: Size2D::new(Au(0), Au(0)), webrender_api: webrender_api_sender.create_api(), + stylist: stylist, rw_data: Arc::new(Mutex::new( LayoutThreadData { constellation_chan: constellation_chan, display_list: None, - stylist: stylist, content_box_response: None, content_boxes_response: Vec::new(), client_rect_response: Rect::zero(), @@ -507,9 +511,8 @@ impl LayoutThread { } // Create a layout context for use in building display lists, hit testing, &c. - fn build_layout_context<'a>(&self, + fn build_layout_context<'a>(&'a self, guards: StylesheetGuards<'a>, - rw_data: &LayoutThreadData, request_images: bool, snapshot_map: &'a SnapshotMap) -> LayoutContext<'a> { @@ -519,12 +522,12 @@ impl LayoutThread { LayoutContext { id: self.id, style_context: SharedStyleContext { - stylist: rw_data.stylist.clone(), + stylist: &self.stylist, options: StyleSystemOptions::default(), guards: guards, running_animations: self.running_animations.clone(), expired_animations: self.expired_animations.clone(), - error_reporter: Box::new(self.error_reporter.clone()), + error_reporter: &self.error_reporter, local_context_creation_data: Mutex::new(thread_local_style_context_creation_data), timer: self.timer.clone(), quirks_mode: self.quirks_mode.unwrap(), @@ -605,7 +608,7 @@ impl LayoutThread { Msg::AddStylesheet(style_info) => { self.handle_add_stylesheet(style_info, possibly_locked_rw_data) } - Msg::SetQuirksMode(mode) => self.handle_set_quirks_mode(possibly_locked_rw_data, mode), + Msg::SetQuirksMode(mode) => self.handle_set_quirks_mode(mode), Msg::GetRPC(response_chan) => { response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as Box).unwrap(); @@ -631,7 +634,7 @@ impl LayoutThread { }, Msg::GetCurrentEpoch(sender) => { let _rw_data = possibly_locked_rw_data.lock(); - sender.send(self.epoch).unwrap(); + sender.send(self.epoch.get()).unwrap(); }, Msg::AdvanceClockMs(how_many, do_tick) => { self.handle_advance_clock_ms(how_many, possibly_locked_rw_data, do_tick); @@ -676,11 +679,10 @@ impl LayoutThread { size: display_list.map_or(0, |sc| sc.heap_size_of_children()), }); - let stylist = rw_data.stylist.as_ref(); reports.push(Report { path: path![formatted_url, "layout-thread", "stylist"], kind: ReportKind::ExplicitJemallocHeapSize, - size: stylist.heap_size_of_children(), + size: self.stylist.heap_size_of_children(), }); // The LayoutThread has data in Persistent TLS... @@ -752,10 +754,10 @@ impl LayoutThread { let rw_data = possibly_locked_rw_data.lock(); let guard = stylesheet.shared_lock.read(); - if stylesheet.is_effective_for_device(&rw_data.stylist.device, &guard) { + if stylesheet.is_effective_for_device(&self.stylist.device, &guard) { add_font_face_rules(&*stylesheet, &guard, - &rw_data.stylist.device, + &self.stylist.device, &self.font_cache_thread, &self.font_cache_sender, &self.outstanding_web_fonts); @@ -776,12 +778,8 @@ impl LayoutThread { } /// Sets quirks mode for the document, causing the quirks mode stylesheet to be used. - fn handle_set_quirks_mode<'a, 'b>(&self, - possibly_locked_rw_data: &mut RwData<'a, 'b>, - quirks_mode: QuirksMode) { - let mut rw_data = possibly_locked_rw_data.lock(); - StyleArc::get_mut(&mut rw_data.stylist).unwrap().set_quirks_mode(quirks_mode); - possibly_locked_rw_data.block(rw_data); + fn handle_set_quirks_mode<'a, 'b>(&mut self, quirks_mode: QuirksMode) { + self.stylist.set_quirks_mode(quirks_mode); } fn try_get_layout_root(&self, node: N) -> Option { @@ -843,7 +841,7 @@ impl LayoutThread { /// Computes the stacking-relative positions of all flows and, if the painting is dirty and the /// reflow goal and query type need it, builds the display list. - fn compute_abs_pos_and_build_display_list(&mut self, + fn compute_abs_pos_and_build_display_list(&self, data: &Reflow, query_type: Option<&ReflowQueryType>, document: Option<&ServoLayoutDocument>, @@ -882,7 +880,7 @@ impl LayoutThread { let root_size = { let root_flow = flow::base(layout_root); - if rw_data.stylist.viewport_constraints().is_some() { + if self.stylist.viewport_constraints().is_some() { root_flow.position.size.to_physical(root_flow.writing_mode) } else { root_flow.overflow.scroll.size @@ -938,13 +936,14 @@ impl LayoutThread { let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(), self.viewport_size.height.to_f32_px()); - self.epoch.next(); - let Epoch(epoch_number) = self.epoch; + let mut epoch = self.epoch.get(); + epoch.next(); + self.epoch.set(epoch); let viewport_size = webrender_traits::LayoutSize::from_untyped(&viewport_size); self.webrender_api.set_display_list( Some(get_root_flow_background_color(layout_root)), - webrender_traits::Epoch(epoch_number), + webrender_traits::Epoch(epoch.0), viewport_size, builder.finalize(), true); @@ -1038,11 +1037,10 @@ impl LayoutThread { self.document_shared_lock = Some(document_shared_lock.clone()); let author_guard = document_shared_lock.read(); let device = Device::new(MediaType::Screen, initial_viewport); - StyleArc::get_mut(&mut rw_data.stylist).unwrap() - .set_device(device, &author_guard, &data.document_stylesheets); + self.stylist.set_device(device, &author_guard, &data.document_stylesheets); self.viewport_size = - rw_data.stylist.viewport_constraints().map_or(current_screen_size, |constraints| { + self.stylist.viewport_constraints().map_or(current_screen_size, |constraints| { debug!("Viewport constraints: {:?}", constraints); // other rules are evaluated against the actual viewport @@ -1052,7 +1050,7 @@ impl LayoutThread { let viewport_size_changed = self.viewport_size != old_viewport_size; if viewport_size_changed { - if let Some(constraints) = rw_data.stylist.viewport_constraints() { + if let Some(constraints) = self.stylist.viewport_constraints() { // let the constellation know about the viewport constraints rw_data.constellation_chan .send(ConstellationMsg::ViewportConstrained(self.id, constraints.clone())) @@ -1092,8 +1090,8 @@ impl LayoutThread { let mut extra_data = ExtraStyleData { marker: PhantomData, }; - let needs_dirtying = StyleArc::get_mut(&mut rw_data.stylist).unwrap().update( - &data.document_stylesheets, + let needs_dirtying = self.stylist.update( + data.document_stylesheets.iter(), &guards, Some(ua_stylesheets), data.stylesheets_changed, @@ -1158,7 +1156,7 @@ impl LayoutThread { // Create a layout context for use throughout the following passes. let mut layout_context = - self.build_layout_context(guards.clone(), &*rw_data, true, &map); + self.build_layout_context(guards.clone(), true, &map); // 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() { @@ -1185,7 +1183,7 @@ impl LayoutThread { || { // Perform CSS selector matching and flow construction. if traversal_driver.is_parallel() { - let pool = self.parallel_traversal.as_mut().unwrap(); + let pool = self.parallel_traversal.as_ref().unwrap(); // Parallel mode parallel::traverse_dom::( &traversal, element, token, pool); @@ -1208,7 +1206,7 @@ impl LayoutThread { 0); // Retrieve the (possibly rebuilt) root flow. - self.root_flow = self.try_get_layout_root(element.as_node()); + *self.root_flow.borrow_mut() = self.try_get_layout_root(element.as_node()); } for element in elements_with_snapshot { @@ -1229,7 +1227,7 @@ impl LayoutThread { unsafe { layout_context.style_context.stylist.rule_tree.maybe_gc(); } // Perform post-style recalculation layout passes. - if let Some(mut root_flow) = self.root_flow.clone() { + if let Some(mut root_flow) = self.root_flow.borrow().clone() { self.perform_post_style_recalc_layout_passes(&mut root_flow, &data.reflow_info, Some(&data.query_type), @@ -1243,7 +1241,7 @@ impl LayoutThread { &mut layout_context); } - fn respond_to_query_if_necessary(&mut self, + fn respond_to_query_if_necessary(&self, query_type: &ReflowQueryType, rw_data: &mut LayoutThreadData, context: &mut LayoutContext) { @@ -1253,7 +1251,7 @@ impl LayoutThread { }; rw_data.pending_images = pending_images; - let mut root_flow = match self.root_flow.clone() { + let mut root_flow = match self.root_flow.borrow().clone() { Some(root_flow) => root_flow, None => return, }; @@ -1390,7 +1388,7 @@ impl LayoutThread { println!("**** pipeline={}\tForDisplay\tSpecial\tAnimationTick", self.id); } - if let Some(mut root_flow) = self.root_flow.clone() { + if let Some(mut root_flow) = self.root_flow.borrow().clone() { let reflow_info = Reflow { goal: ReflowGoal::ForDisplay, page_clip_rect: max_rect(), @@ -1407,7 +1405,6 @@ impl LayoutThread { }; let snapshots = SnapshotMap::new(); let mut layout_context = self.build_layout_context(guards, - &*rw_data, false, &snapshots); @@ -1432,7 +1429,7 @@ impl LayoutThread { } } - fn perform_post_style_recalc_layout_passes(&mut self, + fn perform_post_style_recalc_layout_passes(&self, root_flow: &mut FlowRef, data: &Reflow, query_type: Option<&ReflowQueryType>, @@ -1486,7 +1483,7 @@ impl LayoutThread { || { let profiler_metadata = self.profiler_metadata(); - if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) { + if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_ref()) { // Parallel mode. LayoutThread::solve_constraints_parallel(traversal, FlowRef::deref_mut(root_flow), @@ -1515,31 +1512,31 @@ impl LayoutThread { context); } - fn perform_post_main_layout_passes(&mut self, + fn perform_post_main_layout_passes(&self, data: &Reflow, query_type: Option<&ReflowQueryType>, document: Option<&ServoLayoutDocument>, rw_data: &mut LayoutThreadData, layout_context: &mut LayoutContext) { // Build the display list if necessary, and send it to the painter. - if let Some(mut root_flow) = self.root_flow.clone() { + if let Some(mut root_flow) = self.root_flow.borrow().clone() { self.compute_abs_pos_and_build_display_list(data, query_type, document, FlowRef::deref_mut(&mut root_flow), &mut *layout_context, rw_data); - self.first_reflow = false; + self.first_reflow.set(false); if opts::get().trace_layout { - layout_debug::end_trace(self.generation); + layout_debug::end_trace(self.generation.get()); } if opts::get().dump_flow_tree { root_flow.print("Post layout flow tree".to_owned()); } - self.generation += 1; + self.generation.set(self.generation.get() + 1); } } @@ -1563,7 +1560,7 @@ impl LayoutThread { } else { TimerMetadataFrameType::RootWindow }, - incremental: if self.first_reflow { + incremental: if self.first_reflow.get() { TimerMetadataReflowType::FirstReflow } else { TimerMetadataReflowType::Incremental diff --git a/servo/components/style/animation.rs b/servo/components/style/animation.rs index 0a4c7cab3455..632588988c28 100644 --- a/servo/components/style/animation.rs +++ b/servo/components/style/animation.rs @@ -399,6 +399,7 @@ impl PropertyAnimation { // // TODO(emilio): Take rid of this mutex splitting SharedLayoutContex into a // cloneable part and a non-cloneable part.. +#[cfg(feature = "servo")] pub fn start_transitions_if_applicable(new_animations_sender: &Sender, opaque_node: OpaqueNode, unsafe_node: UnsafeNode, @@ -755,6 +756,7 @@ pub fn update_style_for_animation(context: &SharedStyleContext, } /// Update the style in the node when it finishes. +#[cfg(feature = "servo")] pub fn complete_expired_transitions(node: OpaqueNode, style: &mut Arc, context: &SharedStyleContext) -> bool { let had_animations_to_expire; diff --git a/servo/components/style/context.rs b/servo/components/style/context.rs index f319c76ba34a..a628ef1377f3 100644 --- a/servo/components/style/context.rs +++ b/servo/components/style/context.rs @@ -4,7 +4,8 @@ //! The context within which style is calculated. -use animation::{Animation, PropertyAnimation}; +#[cfg(feature = "servo")] use animation::Animation; +use animation::PropertyAnimation; use app_units::Au; use bit_vec::BitVec; use bloom::StyleBloom; @@ -17,18 +18,18 @@ use fnv::FnvHashMap; use font_metrics::FontMetricsProvider; #[cfg(feature = "gecko")] use gecko_bindings::structs; use matching::StyleSharingCandidateCache; -use parking_lot::RwLock; +#[cfg(feature = "servo")] use parking_lot::RwLock; #[cfg(feature = "gecko")] use properties::ComputedValues; use selector_parser::SnapshotMap; use selectors::matching::ElementSelectorFlags; #[cfg(feature = "servo")] use servo_config::opts; use shared_lock::StylesheetGuards; -use std::collections::HashMap; -#[cfg(not(feature = "servo"))] use std::env; +#[cfg(feature = "servo")] use std::collections::HashMap; +#[cfg(feature = "gecko")] use std::env; use std::fmt; use std::ops::Add; -use std::sync::Mutex; -use std::sync::mpsc::Sender; +#[cfg(feature = "servo")] use std::sync::Mutex; +#[cfg(feature = "servo")] use std::sync::mpsc::Sender; use stylearc::Arc; use stylist::Stylist; use thread_state; @@ -37,10 +38,12 @@ use timer::Timer; use traversal::{DomTraversal, TraversalFlags}; /// This structure is used to create a local style context from a shared one. +#[cfg(feature = "servo")] pub struct ThreadLocalStyleContextCreationInfo { new_animations_sender: Sender, } +#[cfg(feature = "servo")] impl ThreadLocalStyleContextCreationInfo { /// Trivially constructs a `ThreadLocalStyleContextCreationInfo`. pub fn new(animations_sender: Sender) -> Self { @@ -106,7 +109,7 @@ impl Default for StyleSystemOptions { /// shared among the worker threads. pub struct SharedStyleContext<'a> { /// The CSS selector stylist. - pub stylist: Arc, + pub stylist: &'a Stylist, /// Configuration options. pub options: StyleSystemOptions, @@ -114,17 +117,8 @@ pub struct SharedStyleContext<'a> { /// Guards for pre-acquired locks pub guards: StylesheetGuards<'a>, - /// The animations that are currently running. - pub running_animations: Arc>>>, - - /// The list of animations that have expired since the last style recalculation. - pub expired_animations: Arc>>>, - ///The CSS error reporter for all CSS loaded in this layout thread - pub error_reporter: Box, - - /// Data needed to create the thread-local style context from the shared one. - pub local_context_creation_data: Mutex, + pub error_reporter: &'a ParseErrorReporter, /// The current timer for transitions and animations. This is needed to test /// them. @@ -138,6 +132,19 @@ pub struct SharedStyleContext<'a> { /// A map with our snapshots in order to handle restyle hints. pub snapshot_map: &'a SnapshotMap, + + /// The animations that are currently running. + #[cfg(feature = "servo")] + pub running_animations: Arc>>>, + + /// The list of animations that have expired since the last style recalculation. + #[cfg(feature = "servo")] + pub expired_animations: Arc>>>, + + /// Data needed to create the thread-local style context from the shared one. + #[cfg(feature = "servo")] + pub local_context_creation_data: Mutex, + } impl<'a> SharedStyleContext<'a> { @@ -400,6 +407,7 @@ pub struct ThreadLocalStyleContext { pub bloom_filter: StyleBloom, /// A channel on which new animations that have been triggered by style /// recalculation can be sent. + #[cfg(feature = "servo")] pub new_animations_sender: Sender, /// A set of tasks to be run (on the parent thread) in sequential mode after /// the rest of the styling is complete. This is useful for infrequently-needed @@ -421,6 +429,7 @@ pub struct ThreadLocalStyleContext { impl ThreadLocalStyleContext { /// Creates a new `ThreadLocalStyleContext` from a shared one. + #[cfg(feature = "servo")] pub fn new(shared: &SharedStyleContext) -> Self { ThreadLocalStyleContext { style_sharing_candidate_cache: StyleSharingCandidateCache::new(), @@ -434,6 +443,20 @@ impl ThreadLocalStyleContext { } } + #[cfg(feature = "gecko")] + /// Creates a new `ThreadLocalStyleContext` from a shared one. + pub fn new(shared: &SharedStyleContext) -> Self { + ThreadLocalStyleContext { + style_sharing_candidate_cache: StyleSharingCandidateCache::new(), + bloom_filter: StyleBloom::new(), + tasks: Vec::new(), + selector_flags: SelectorFlagsMap::new(), + statistics: TraversalStatistics::default(), + current_element_info: None, + font_metrics_provider: E::FontMetricsProvider::create_from(shared), + } + } + /// Notes when the style system starts traversing an element. pub fn begin_element(&mut self, element: E, data: &ElementData) { debug_assert!(self.current_element_info.is_none()); diff --git a/servo/components/style/gecko/data.rs b/servo/components/style/gecko/data.rs index 64252c79afc8..d8397ddeb93f 100644 --- a/servo/components/style/gecko/data.rs +++ b/servo/components/style/gecko/data.rs @@ -18,14 +18,14 @@ use std::collections::HashMap; use std::sync::mpsc::{Receiver, Sender, channel}; use stylearc::Arc; use stylesheet_set::StylesheetSet; -use stylesheets::{FontFaceRule, Origin, Stylesheet}; +use stylesheets::{FontFaceRule, Origin}; use stylist::{ExtraStyleData, Stylist}; /// The container for data that a Servo-backed Gecko document needs to style /// itself. pub struct PerDocumentStyleDataImpl { /// Rule processor. - pub stylist: Arc, + pub stylist: Stylist, /// List of stylesheets, mirrored from Gecko. pub stylesheets: StylesheetSet, @@ -60,7 +60,7 @@ impl PerDocumentStyleData { let (new_anims_sender, new_anims_receiver) = channel(); PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl { - stylist: Arc::new(Stylist::new(device)), + stylist: Stylist::new(device), stylesheets: StylesheetSet::new(), new_animations_sender: new_anims_sender, new_animations_receiver: new_anims_receiver, @@ -86,10 +86,7 @@ impl PerDocumentStyleDataImpl { /// /// Implies also a stylesheet flush. 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(); - } + Arc::get_mut(&mut self.stylist.device).unwrap().reset(); self.stylesheets.force_dirty(); self.flush_stylesheets(guard); } @@ -100,21 +97,18 @@ impl PerDocumentStyleDataImpl { return; } - let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); let mut extra_data = ExtraStyleData { font_faces: &mut self.font_faces, }; let author_style_disabled = self.stylesheets.author_style_disabled(); - let mut stylesheets = Vec::>::new(); - self.stylesheets.flush(&mut stylesheets); - stylist.clear(); - stylist.rebuild(stylesheets.as_slice(), - &StylesheetGuards::same(guard), - /* ua_sheets = */ None, - /* stylesheets_changed = */ true, - author_style_disabled, - &mut extra_data); + self.stylist.clear(); + self.stylist.rebuild(self.stylesheets.flush(), + &StylesheetGuards::same(guard), + /* ua_sheets = */ None, + /* stylesheets_changed = */ true, + author_style_disabled, + &mut extra_data); } /// Get the default computed values for this document. @@ -125,8 +119,7 @@ impl PerDocumentStyleDataImpl { /// Clear the stylist. This will be a no-op if the stylist is /// already cleared; the stylist handles that. pub fn clear_stylist(&mut self) { - let mut stylist = Arc::get_mut(&mut self.stylist).unwrap(); - stylist.clear(); + self.stylist.clear(); } } diff --git a/servo/components/style/matching.rs b/servo/components/style/matching.rs index 40c2661d2453..530b3c1f591b 100644 --- a/servo/components/style/matching.rs +++ b/servo/components/style/matching.rs @@ -8,7 +8,6 @@ #![deny(missing_docs)] use Atom; -use animation::{self, Animation, PropertyAnimation}; use atomic_refcell::AtomicRefMut; use bit_vec::BitVec; use cache::{LRUCache, LRUCacheMutIterator}; @@ -721,6 +720,8 @@ trait PrivateMatchMethods: TElement { old_values: &mut Option>, new_values: &mut Arc, _primary_style: &ComputedStyle) { + use animation; + let possibly_expired_animations = &mut context.thread_local.current_element_info.as_mut().unwrap() .possibly_expired_animations; @@ -806,11 +807,14 @@ trait PrivateMatchMethods: TElement { } } + #[cfg(feature = "servo")] fn update_animations_for_cascade(&self, context: &SharedStyleContext, style: &mut Arc, - possibly_expired_animations: &mut Vec, + possibly_expired_animations: &mut Vec<::animation::PropertyAnimation>, font_metrics: &FontMetricsProvider) { + use animation::{self, Animation}; + // Finish any expired transitions. let this_opaque = self.as_node().opaque(); animation::complete_expired_transitions(this_opaque, style, context); diff --git a/servo/components/style/stylesheet_set.rs b/servo/components/style/stylesheet_set.rs index 0cc6f4fbf51f..da4e75e5ecaa 100644 --- a/servo/components/style/stylesheet_set.rs +++ b/servo/components/style/stylesheet_set.rs @@ -4,6 +4,7 @@ //! A centralized set of stylesheets for a document. +use std::slice; use stylearc::Arc; use stylesheets::Stylesheet; @@ -14,6 +15,17 @@ pub struct StylesheetSetEntry { sheet: Arc, } +/// A iterator over the stylesheets of a list of entries in the StylesheetSet. +#[derive(Clone)] +pub struct StylesheetIterator<'a>(slice::Iter<'a, StylesheetSetEntry>); + +impl<'a> Iterator for StylesheetIterator<'a> { + type Item = &'a Arc; + fn next(&mut self) -> Option { + self.0.next().map(|entry| &entry.sheet) + } +} + /// The set of stylesheets effective for a given document. pub struct StylesheetSet { /// The actual list of all the stylesheets that apply to the given document, @@ -108,12 +120,11 @@ impl StylesheetSet { self.dirty } - /// Flush the current set, unmarking it as dirty. - pub fn flush(&mut self, sheets: &mut Vec>) { + /// Flush the current set, unmarking it as dirty, and returns an iterator + /// over the new stylesheet list. + pub fn flush(&mut self) -> StylesheetIterator { self.dirty = false; - for entry in &self.entries { - sheets.push(entry.sheet.clone()) - } + StylesheetIterator(self.entries.iter()) } /// Mark the stylesheets as dirty, because something external may have diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs index 5df061e48f69..2cec8f597783 100644 --- a/servo/components/style/stylist.rs +++ b/servo/components/style/stylist.rs @@ -296,13 +296,15 @@ impl Stylist { /// This method resets all the style data each time the stylesheets change /// (which is indicated by the `stylesheets_changed` parameter), or the /// device is dirty, which means we need to re-evaluate media queries. - pub fn rebuild<'a>(&mut self, - doc_stylesheets: &[Arc], - guards: &StylesheetGuards, - ua_stylesheets: Option<&UserAgentStylesheets>, - stylesheets_changed: bool, - author_style_disabled: bool, - extra_data: &mut ExtraStyleData<'a>) -> bool { + pub fn rebuild<'a, 'b, I>(&mut self, + doc_stylesheets: I, + guards: &StylesheetGuards, + ua_stylesheets: Option<&UserAgentStylesheets>, + stylesheets_changed: bool, + author_style_disabled: bool, + extra_data: &mut ExtraStyleData<'a>) -> bool + where I: Iterator> + Clone, + { debug_assert!(!self.is_cleared || self.is_device_dirty); self.is_cleared = false; @@ -315,7 +317,7 @@ impl Stylist { let cascaded_rule = ViewportRule { declarations: viewport::Cascade::from_stylesheets( - doc_stylesheets, guards.author, &self.device + doc_stylesheets.clone(), guards.author, &self.device ).finish(), }; @@ -345,7 +347,7 @@ impl Stylist { } // Only use author stylesheets if author styles are enabled. - let sheets_to_add = doc_stylesheets.iter().filter(|s| { + let sheets_to_add = doc_stylesheets.filter(|s| { !author_style_disabled || s.origin != Origin::Author }); @@ -366,13 +368,15 @@ impl Stylist { /// clear the stylist and then rebuild it. Chances are, you want to use /// either clear() or rebuild(), with the latter done lazily, instead. - pub fn update<'a>(&mut self, - doc_stylesheets: &[Arc], - guards: &StylesheetGuards, - ua_stylesheets: Option<&UserAgentStylesheets>, - stylesheets_changed: bool, - author_style_disabled: bool, - extra_data: &mut ExtraStyleData<'a>) -> bool { + pub fn update<'a, 'b, I>(&mut self, + doc_stylesheets: I, + guards: &StylesheetGuards, + ua_stylesheets: Option<&UserAgentStylesheets>, + stylesheets_changed: bool, + author_style_disabled: bool, + extra_data: &mut ExtraStyleData<'a>) -> bool + where I: Iterator> + Clone, + { debug_assert!(!self.is_cleared || self.is_device_dirty); // We have to do a dirtiness check before clearing, because if @@ -385,7 +389,9 @@ impl Stylist { author_style_disabled, extra_data) } - fn add_stylesheet<'a>(&mut self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard, + fn add_stylesheet<'a>(&mut self, + stylesheet: &Stylesheet, + guard: &SharedRwLockReadGuard, extra_data: &mut ExtraStyleData<'a>) { if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device, guard) { return; @@ -711,10 +717,12 @@ 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, guard: &SharedRwLockReadGuard, + pub fn set_device(&mut self, + mut device: Device, + guard: &SharedRwLockReadGuard, stylesheets: &[Arc]) { let cascaded_rule = ViewportRule { - declarations: viewport::Cascade::from_stylesheets(stylesheets, guard, &device).finish(), + declarations: viewport::Cascade::from_stylesheets(stylesheets.iter(), guard, &device).finish(), }; self.viewport_constraints = diff --git a/servo/components/style/viewport.rs b/servo/components/style/viewport.rs index 7096c381d233..c887614ad575 100644 --- a/servo/components/style/viewport.rs +++ b/servo/components/style/viewport.rs @@ -26,6 +26,7 @@ use std::iter::Enumerate; use std::str::Chars; use style_traits::{PinchZoomFactor, ToCss}; use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom}; +use stylearc::Arc; use stylesheets::{Stylesheet, Origin}; use values::computed::{Context, ToComputedValue}; use values::specified::{NoCalcLength, LengthOrPercentageOrAuto, ViewportPercentageLength}; @@ -329,7 +330,6 @@ fn is_whitespace_separator_or_equals(c: &char) -> bool { } impl Parse for ViewportRule { - #[allow(missing_docs)] fn parse(context: &ParserContext, input: &mut Parser) -> Result { let parser = ViewportRuleParser { context: context }; @@ -545,14 +545,15 @@ impl Cascade { } } - pub fn from_stylesheets<'a, I>(stylesheets: I, guard: &SharedRwLockReadGuard, - device: &Device) -> Self - where I: IntoIterator, - I::Item: AsRef, + pub fn from_stylesheets<'a, I>(stylesheets: I, + guard: &SharedRwLockReadGuard, + device: &Device) + -> Self + where I: Iterator>, { let mut cascade = Self::new(); for stylesheet in stylesheets { - stylesheet.as_ref().effective_viewport_rules(device, guard, |rule| { + stylesheet.effective_viewport_rules(device, guard, |rule| { for declaration in &rule.declarations { cascade.add(Cow::Borrowed(declaration)) } diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index 5cb6cd92d120..0b209849aae0 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -11,9 +11,8 @@ use std::borrow::Cow; use std::env; use std::fmt::Write; use std::ptr; -use std::sync::Mutex; use style::context::{QuirksMode, SharedStyleContext, StyleContext}; -use style::context::{ThreadLocalStyleContext, ThreadLocalStyleContextCreationInfo}; +use style::context::ThreadLocalStyleContext; use style::data::{ElementData, ElementStyles, RestyleData}; use style::dom::{AnimationOnlyDirtyDescendants, DirtyDescendants}; use style::dom::{ShowSubtreeData, TElement, TNode}; @@ -149,24 +148,19 @@ unsafe fn dummy_url_data() -> &'static RefPtr { RefPtr::from_ptr_ref(&DUMMY_URL_DATA) } +static DEFAULT_ERROR_REPORTER: RustLogReporter = RustLogReporter; + fn create_shared_context<'a>(global_style_data: &GlobalStyleData, guard: &'a SharedRwLockReadGuard, - per_doc_data: &PerDocumentStyleDataImpl, + per_doc_data: &'a PerDocumentStyleDataImpl, traversal_flags: TraversalFlags, snapshot_map: &'a ServoElementSnapshotTable) -> SharedStyleContext<'a> { - let local_context_data = - ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone()); - SharedStyleContext { - stylist: per_doc_data.stylist.clone(), + stylist: &per_doc_data.stylist, options: global_style_data.options.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. - error_reporter: Box::new(RustLogReporter), - local_context_creation_data: Mutex::new(local_context_data), + error_reporter: &DEFAULT_ERROR_REPORTER, timer: Timer::new(), // FIXME Find the real QuirksMode information for this document quirks_mode: QuirksMode::NoQuirks, @@ -2025,9 +2019,10 @@ pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed, } // We don't have the style ready. Go ahead and compute it as necessary. + let data = doc_data.borrow(); let shared = create_shared_context(&global_style_data, &guard, - &mut doc_data.borrow_mut(), + &data, TraversalFlags::empty(), unsafe { &*snapshots }); let mut tlc = ThreadLocalStyleContext::new(&shared); diff --git a/servo/tests/unit/style/viewport.rs b/servo/tests/unit/style/viewport.rs index ed8b9b527eee..e9c11495878a 100644 --- a/servo/tests/unit/style/viewport.rs +++ b/servo/tests/unit/style/viewport.rs @@ -25,7 +25,7 @@ macro_rules! stylesheet { stylesheet!($css, $origin, $error_reporter, SharedRwLock::new()) }; ($css:expr, $origin:ident, $error_reporter:expr, $shared_lock:expr) => { - Box::new(Stylesheet::from_str( + Arc::new(Stylesheet::from_str( $css, ServoUrl::parse("http://localhost").unwrap(), Origin::$origin, @@ -269,7 +269,7 @@ fn multiple_stylesheets_cascading() { Author, error_reporter, shared_lock.clone()) ]; - let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish(); + let declarations = Cascade::from_stylesheets(stylesheets.iter(), &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)); @@ -283,7 +283,7 @@ fn multiple_stylesheets_cascading() { stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }", Author, error_reporter, shared_lock.clone()) ]; - let declarations = Cascade::from_stylesheets(&stylesheets, &shared_lock.read(), &device).finish(); + let declarations = Cascade::from_stylesheets(stylesheets.iter(), &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);