diff --git a/components/layout/query.rs b/components/layout/query.rs index 6b594066963..c12a2b7f63d 100644 --- a/components/layout/query.rs +++ b/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/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index cf9be917837..fbca9d3c890 100644 --- a/components/layout_thread/lib.rs +++ b/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: ::StyleArc, + /// 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. @@ -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,7 +679,7 @@ impl LayoutThread { size: display_list.map_or(0, |sc| sc.heap_size_of_children()), }); - let stylist = rw_data.stylist.as_ref(); + let stylist = self.stylist.as_ref(); reports.push(Report { path: path![formatted_url, "layout-thread", "stylist"], kind: ReportKind::ExplicitJemallocHeapSize, @@ -752,10 +755,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 +779,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) { + StyleArc::get_mut(&mut self.stylist).unwrap().set_quirks_mode(quirks_mode); } fn try_get_layout_root(&self, node: N) -> Option { @@ -843,7 +842,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 +881,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 +937,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 +1038,11 @@ 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() + StyleArc::get_mut(&mut self.stylist).unwrap() .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 +1052,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,7 +1092,7 @@ impl LayoutThread { let mut extra_data = ExtraStyleData { marker: PhantomData, }; - let needs_dirtying = StyleArc::get_mut(&mut rw_data.stylist).unwrap().update( + let needs_dirtying = StyleArc::get_mut(&mut self.stylist).unwrap().update( &data.document_stylesheets, &guards, Some(ua_stylesheets), @@ -1158,7 +1158,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 +1185,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 +1208,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 +1229,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 +1243,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 +1253,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 +1390,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 +1407,6 @@ impl LayoutThread { }; let snapshots = SnapshotMap::new(); let mut layout_context = self.build_layout_context(guards, - &*rw_data, false, &snapshots); @@ -1432,7 +1431,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 +1485,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 +1514,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 +1562,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/components/style/animation.rs b/components/style/animation.rs index 0a4c7cab345..632588988c2 100644 --- a/components/style/animation.rs +++ b/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/components/style/context.rs b/components/style/context.rs index f319c76ba34..a628ef1377f 100644 --- a/components/style/context.rs +++ b/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/components/style/matching.rs b/components/style/matching.rs index f8fbfd493c9..26d72f47347 100644 --- a/components/style/matching.rs +++ b/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}; @@ -719,6 +718,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; @@ -804,11 +805,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/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 9d37f8f01f8..bff003e84eb 100644 --- a/ports/geckolib/glue.rs +++ b/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}; @@ -148,24 +147,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, @@ -2024,9 +2018,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);