servo: Merge #15417 - layout: Remove cached thread local context from LayoutContext, and use LayoutContext for assign_inline_sizes() (from stshine:column-flexbox); r=emilio
authorPu Xingyu <pu.stshine@gmail.com>
Tue, 07 Feb 2017 17:16:05 -0800
changeset 341503 b06338ea3c957a53ae752beb11cf63343e36278b
parent 341502 f8e38e4b1bd13a73f91828ea96393ad57d0b3d1e
child 341504 387b80c4aba8383a0c512e11cf84f98577d896fd
push id86727
push userkwierso@gmail.com
push dateThu, 09 Feb 2017 00:21:26 +0000
treeherdermozilla-inbound@55a4f5189115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #15417 - layout: Remove cached thread local context from LayoutContext, and use LayoutContext for assign_inline_sizes() (from stshine:column-flexbox); r=emilio <!-- Please describe your changes on the following line: --> According to https://github.com/servo/servo/pull/3069 the cached thread local context is introduced for green threads. Now green threads has gone, and the existence of cache force us to create a `LayoutContext`, an `AssignISizes` and an `AssignBSizes` for each flow during parallel layout, so the pull request tries to remove it. And it also switch `assign_inline_sizes()` to accept a `LayoutContext` parameter, as according to my current design we need to do full layout to some flex items for column flexbox during assign isize traversal. Part of #14123. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because refactoring <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: e2b494b1d08b8929ca7e5ae369304f41af81ace2
servo/components/layout/animation.rs
servo/components/layout/block.rs
servo/components/layout/construct.rs
servo/components/layout/context.rs
servo/components/layout/display_list_builder.rs
servo/components/layout/flex.rs
servo/components/layout/flow.rs
servo/components/layout/fragment.rs
servo/components/layout/generated_content.rs
servo/components/layout/inline.rs
servo/components/layout/list_item.rs
servo/components/layout/multicol.rs
servo/components/layout/parallel.rs
servo/components/layout/query.rs
servo/components/layout/sequential.rs
servo/components/layout/table.rs
servo/components/layout/table_caption.rs
servo/components/layout/table_cell.rs
servo/components/layout/table_colgroup.rs
servo/components/layout/table_row.rs
servo/components/layout/table_rowgroup.rs
servo/components/layout/table_wrapper.rs
servo/components/layout/traversal.rs
servo/components/layout_thread/lib.rs
--- a/servo/components/layout/animation.rs
+++ b/servo/components/layout/animation.rs
@@ -1,15 +1,15 @@
 /* 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/. */
 
 //! CSS transitions and animations.
 
-use context::SharedLayoutContext;
+use context::LayoutContext;
 use flow::{self, Flow};
 use gfx::display_list::OpaqueNode;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::PipelineId;
 use script_traits::{AnimationState, ConstellationControlMsg, LayoutMsg as ConstellationMsg};
 use std::collections::HashMap;
 use std::sync::mpsc::Receiver;
 use style::animation::{Animation, update_style_for_animation};
@@ -127,17 +127,17 @@ pub fn update_animation_state(constellat
                       .unwrap();
 }
 
 /// Recalculates style for a set of animations. This does *not* run with the DOM
 /// lock held.
 // NB: This is specific for SelectorImpl, since the layout context and the
 // flows are SelectorImpl specific too. If that goes away at some point,
 // this should be made generic.
-pub fn recalc_style_for_animations(context: &SharedLayoutContext,
+pub fn recalc_style_for_animations(context: &LayoutContext,
                                    flow: &mut Flow,
                                    animations: &HashMap<OpaqueNode,
                                                         Vec<Animation>>) {
     let mut damage = RestyleDamage::empty();
     flow.mutate_fragments(&mut |fragment| {
         if let Some(ref animations) = animations.get(&fragment.node) {
             for animation in animations.iter() {
                 let old_style = fragment.style.clone();
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -23,17 +23,17 @@
 //! "CSS-SIZING" refers to the W3C "CSS Intrinsic & Extrinsic Sizing Module Level 3" document
 //! available here:
 //!
 //!   http://dev.w3.org/csswg/css-sizing/
 
 #![deny(unsafe_code)]
 
 use app_units::{Au, MAX_AU};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
 use display_list_builder::BlockFlowDisplayListBuilding;
 use euclid::{Point2D, Rect, Size2D};
 use floats::{ClearType, FloatKind, Floats, PlacementInfo};
 use flow::{self, BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ForceNonfloatedFlag};
 use flow::{BLOCK_POSITION_IS_STATIC, CLEARS_LEFT, CLEARS_RIGHT};
 use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, INLINE_POSITION_IS_STATIC};
 use flow::{FragmentationContext, MARGINS_CANNOT_COLLAPSE, PreorderFlowTraversal};
@@ -762,21 +762,21 @@ impl BlockFlow {
     /// with the extra content moved to another fragment (a flow like this one) which is returned.
     /// See `Flow::fragment`.
     ///
     /// The return value is always `None` when `fragmentation_context` is `None`.
     ///
     /// `inline(always)` because this is only ever called by in-order or non-in-order top-level
     /// methods.
     #[inline(always)]
-    pub fn assign_block_size_block_base<'a>(&mut self,
-                                            layout_context: &'a LayoutContext<'a>,
-                                            mut fragmentation_context: Option<FragmentationContext>,
-                                            margins_may_collapse: MarginsMayCollapseFlag)
-                                            -> Option<Arc<Flow>> {
+    pub fn assign_block_size_block_base(&mut self,
+                                        layout_context: &LayoutContext,
+                                        mut fragmentation_context: Option<FragmentationContext>,
+                                        margins_may_collapse: MarginsMayCollapseFlag)
+                                        -> Option<Arc<Flow>> {
         let _scope = layout_debug_scope!("assign_block_size_block_base {:x}",
                                          self.base.debug_id());
 
         let mut break_at = None;
         let content_box = self.fragment.content_box();
         if self.base.restyle_damage.contains(REFLOW) {
             // Our current border-box position.
             let mut cur_b = Au(0);
@@ -1457,19 +1457,19 @@ impl BlockFlow {
     ///
     /// Note that this is part of the assign-block-sizes traversal, not the assign-inline-sizes
     /// traversal as one might expect. That is because, in general, float placement cannot occur
     /// until heights are assigned. To work around this unfortunate circular dependency, by the
     /// time we get here we have already estimated the width of the block formatting context based
     /// on the floats we could see at the time of inline-size assignment. The job of this function,
     /// therefore, is not only to assign the final size but also to perform the layout again for
     /// this block formatting context if our speculation was wrong.
-    fn assign_inline_position_for_formatting_context<'a>(&mut self,
-                                                         layout_context: &'a LayoutContext<'a>,
-                                                         content_box: LogicalRect<Au>) {
+    fn assign_inline_position_for_formatting_context(&mut self,
+                                                     layout_context: &LayoutContext,
+                                                     content_box: LogicalRect<Au>) {
         debug_assert!(self.formatting_context_type() != FormattingContextType::None);
 
         if !self.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
             return
         }
 
         // We do this first to avoid recomputing our inline size when we propagate it.
         self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
@@ -1541,20 +1541,20 @@ impl BlockFlow {
         // If float speculation failed, fixup our layout, and re-layout all the children.
         if self.fragment.margin_box_inline_size() != self.base.position.size.inline {
             debug!("assign_inline_position_for_formatting_context: float speculation failed");
             // Fix-up our own layout.
             // We can't just traverse_flow_tree_preorder ourself, because that would re-run
             // float speculation, instead of acting on the actual results.
             self.fragment.border_box.size.inline = inline_size;
             // Assign final-final inline sizes on all our children.
-            self.assign_inline_sizes(&layout_context.shared.style_context);
+            self.assign_inline_sizes(layout_context);
             // Re-run layout on our children.
             for child in flow::mut_base(self).children.iter_mut() {
-                sequential::traverse_flow_tree_preorder(child, layout_context.shared);
+                sequential::traverse_flow_tree_preorder(child, layout_context);
             }
             // Assign our final-final block size.
             self.assign_block_size(layout_context);
         }
 
         debug_assert_eq!(self.fragment.margin_box_inline_size(), self.base.position.size.inline);
     }
 
@@ -1878,19 +1878,20 @@ impl Flow for BlockFlow {
         self.fragment.restyle_damage.remove(BUBBLE_ISIZES);
     }
 
     /// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
     /// When called on this context, the context has had its inline-size set by the parent context.
     ///
     /// Dual fragments consume some inline-size first, and the remainder is assigned to all child
     /// (block) contexts.
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("block::assign_inline_sizes {:x}", self.base.debug_id());
 
+        let shared_context = layout_context.shared_context();
         self.compute_inline_sizes(shared_context);
 
         // Move in from the inline-start border edge.
         let inline_start_content_edge = self.fragment.border_box.start.i +
             self.fragment.border_padding.inline_start;
 
         let padding_and_borders = self.fragment.border_padding.inline_start_end();
 
@@ -1909,21 +1910,21 @@ impl Flow for BlockFlow {
     }
 
     fn place_float_if_applicable<'a>(&mut self) {
         if self.base.flags.is_float() {
             self.place_float();
         }
     }
 
-    fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self,
-                                                            layout_context: &'a LayoutContext<'a>,
-                                                            parent_thread_id: u8,
-                                                            content_box: LogicalRect<Au>)
-                                                            -> bool {
+    fn assign_block_size_for_inorder_child_if_necessary(&mut self,
+                                                        layout_context: &LayoutContext,
+                                                        parent_thread_id: u8,
+                                                        content_box: LogicalRect<Au>)
+                                                        -> bool {
         if self.base.flags.is_float() {
             return false
         }
 
         let is_formatting_context = self.formatting_context_type() != FormattingContextType::None;
         if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) && is_formatting_context {
             self.assign_inline_position_for_formatting_context(layout_context, content_box);
         }
@@ -1945,17 +1946,17 @@ impl Flow for BlockFlow {
             let delta = self.base.position.size.block;
             self.base.floats.translate(LogicalSize::new(writing_mode, Au(0), -delta));
             return true
         }
 
         false
     }
 
-    fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, ctx: &LayoutContext) {
         let remaining = Flow::fragment(self, ctx, None);
         debug_assert!(remaining.is_none());
     }
 
     fn fragment(&mut self, layout_context: &LayoutContext,
                 fragmentation_context: Option<FragmentationContext>)
                 -> Option<Arc<Flow>> {
         if self.fragment.is_replaced() {
@@ -1993,17 +1994,17 @@ impl Flow for BlockFlow {
                    flow::base(self).debug_id());
             self.assign_block_size_block_base(
                 layout_context,
                 fragmentation_context,
                 MarginsMayCollapseFlag::MarginsMayCollapse)
         }
     }
 
-    fn compute_absolute_position(&mut self, _layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, _layout_context: &LayoutContext) {
         // FIXME (mbrubeck): Get the real container size, taking the container writing mode into
         // account.  Must handle vertical writing modes.
         let container_size = Size2D::new(self.base.block_container_inline_size, Au(0));
 
         if self.is_root() {
             self.base.clip = ClippingRegion::max();
         }
 
--- a/servo/components/layout/construct.rs
+++ b/servo/components/layout/construct.rs
@@ -10,17 +10,17 @@
 //! intermediate data that goes with a DOM node and hasn't found its "home" yet-maybe it's a box,
 //! maybe it's an absolute or fixed position thing that hasn't found its containing block yet.
 //! Construction items bubble up the tree from children to parents until they find their homes.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::BlockFlow;
-use context::LayoutContext;
+use context::{LayoutContext, with_thread_local_font_context};
 use data::{HAS_NEWLY_CONSTRUCTED_FLOW, PersistentLayoutData};
 use flex::FlexFlow;
 use floats::FloatKind;
 use flow::{self, AbsoluteDescendants, Flow, FlowClass, ImmutableFlowUtils};
 use flow::{CAN_BE_FRAGMENTED, IS_ABSOLUTELY_POSITIONED, MARGINS_CANNOT_COLLAPSE};
 use flow::{MutableFlowUtils, MutableOwnedFlowUtils};
 use flow_ref::FlowRef;
 use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo, SvgFragmentInfo};
@@ -310,35 +310,35 @@ impl InlineFragmentsAccumulator {
         }
         fragments
     }
 }
 
 /// An object that knows how to create flows.
 pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
     /// The layout context.
-    pub layout_context: &'a LayoutContext<'a>,
+    pub layout_context: &'a LayoutContext,
     /// 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<N>,
 }
 
 impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
   FlowConstructor<'a, ConcreteThreadSafeLayoutNode> {
     /// Creates a new flow constructor.
-    pub fn new(layout_context: &'a LayoutContext<'a>) -> Self {
+    pub fn new(layout_context: &'a LayoutContext) -> Self {
         FlowConstructor {
             layout_context: layout_context,
             phantom2: PhantomData,
         }
     }
 
     #[inline]
     fn style_context(&self) -> &SharedStyleContext {
-        self.layout_context.style_context()
+        self.layout_context.shared_context()
     }
 
     #[inline]
     fn set_flow_construction_result(&self,
                                     node: &ConcreteThreadSafeLayoutNode,
                                     result: ConstructionResult) {
         node.set_flow_construction_result(result);
     }
@@ -346,22 +346,22 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
     /// Builds the fragment for the given block or subclass thereof.
     fn build_fragment_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> Fragment {
         let specific_fragment_info = match node.type_id() {
             Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) => {
                 SpecificFragmentInfo::Iframe(IframeFragmentInfo::new(node))
             }
             Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) => {
                 let image_info = box ImageFragmentInfo::new(node.image_url(),
-                                                            &self.layout_context.shared);
+                                                            &self.layout_context);
                 SpecificFragmentInfo::Image(image_info)
             }
             Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => {
                 let image_info = box ImageFragmentInfo::new(node.object_data(),
-                                                            &self.layout_context.shared);
+                                                            &self.layout_context);
                 SpecificFragmentInfo::Image(image_info)
             }
             Some(LayoutNodeType::Element(LayoutElementType::HTMLTableElement)) => {
                 SpecificFragmentInfo::TableWrapper
             }
             Some(LayoutNodeType::Element(LayoutElementType::HTMLTableColElement)) => {
                 SpecificFragmentInfo::TableColumn(TableColumnFragmentInfo::new(node))
             }
@@ -429,18 +429,20 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
                 _ => {}
             }
         }
 
         // We must scan for runs before computing minimum ascent and descent because scanning
         // for runs might collapse so much whitespace away that only hypothetical fragments
         // remain. In that case the inline flow will compute its ascent and descent to be zero.
         let scanned_fragments =
-            TextRunScanner::new().scan_for_runs(&mut self.layout_context.font_context(),
-                                                fragments.fragments);
+            with_thread_local_font_context(self.layout_context, |font_context| {
+                TextRunScanner::new().scan_for_runs(font_context,
+                                                    mem::replace(&mut fragments.fragments, LinkedList::new()))
+            });
         let mut inline_flow_ref =
             FlowRef::new(Arc::new(InlineFlow::from_fragments(scanned_fragments,
                                                 node.style(self.style_context()).writing_mode)));
 
         // Add all the inline-block fragments as children of the inline flow.
         for inline_block_flow in &inline_block_flows {
             inline_flow_ref.add_new_child(inline_block_flow.clone());
         }
@@ -459,18 +461,19 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
         // See the comment above `flow::AbsoluteDescendantInfo` for more information.
         inline_flow_ref.take_applicable_absolute_descendants(&mut fragments.absolute_descendants);
         absolute_descendants.push_descendants(fragments.absolute_descendants);
 
         {
             // FIXME(#6503): Use Arc::get_mut().unwrap() here.
             let inline_flow = FlowRef::deref_mut(&mut inline_flow_ref).as_mut_inline();
             inline_flow.minimum_line_metrics =
-                inline_flow.minimum_line_metrics(&mut self.layout_context.font_context(),
-                                                 &node.style(self.style_context()))
+                with_thread_local_font_context(self.layout_context, |font_context| {
+                    inline_flow.minimum_line_metrics(font_context, &node.style(self.style_context()))
+                });
         }
 
         inline_flow_ref.finish();
         legalizer.add_child(self.style_context(), flow, inline_flow_ref)
     }
 
     fn build_block_flow_using_construction_result_of_child(
             &mut self,
@@ -1211,35 +1214,37 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
     fn build_flow_for_list_item(&mut self,
                                 node: &ConcreteThreadSafeLayoutNode,
                                 flotation: float::T)
                                 -> ConstructionResult {
         let flotation = FloatKind::from_property(flotation);
         let marker_fragments = match node.style(self.style_context()).get_list().list_style_image {
             Either::First(ref url_value) => {
                 let image_info = box ImageFragmentInfo::new(url_value.url().map(|u| u.clone()),
-                                                            &self.layout_context.shared);
+                                                            &self.layout_context);
                 vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info), self.layout_context)]
             }
             Either::Second(_none) => {
                 match ListStyleTypeContent::from_list_style_type(node.style(self.style_context())
                                                                      .get_list()
                                                                      .list_style_type) {
                     ListStyleTypeContent::None => Vec::new(),
                     ListStyleTypeContent::StaticText(ch) => {
                         let text = format!("{}\u{a0}", ch);
                         let mut unscanned_marker_fragments = LinkedList::new();
                         unscanned_marker_fragments.push_back(Fragment::new(
                             node,
                             SpecificFragmentInfo::UnscannedText(
                                 box UnscannedTextFragmentInfo::new(text, None)),
                             self.layout_context));
-                        let marker_fragments = TextRunScanner::new().scan_for_runs(
-                            &mut self.layout_context.font_context(),
-                            unscanned_marker_fragments);
+                        let marker_fragments =
+                            with_thread_local_font_context(self.layout_context, |mut font_context| {
+                                TextRunScanner::new().scan_for_runs(&mut font_context,
+                                                                    unscanned_marker_fragments)
+                            });
                         marker_fragments.fragments
                     }
                     ListStyleTypeContent::GeneratedContent(info) => {
                         vec![Fragment::new(node, SpecificFragmentInfo::GeneratedContent(info), self.layout_context)]
                     }
                 }
             }
         };
--- a/servo/components/layout/context.rs
+++ b/servo/components/layout/context.rs
@@ -15,93 +15,72 @@ use net_traits::image_cache_thread::{Ima
 use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
 use parking_lot::RwLock;
 use servo_config::opts;
 use servo_url::ServoUrl;
 use std::borrow::{Borrow, BorrowMut};
 use std::cell::{RefCell, RefMut};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
-use std::rc::Rc;
 use std::sync::{Arc, Mutex};
 use style::context::{SharedStyleContext, ThreadLocalStyleContext};
 use style::dom::TElement;
 
 /// TLS data scoped to the traversal.
 pub struct ScopedThreadLocalLayoutContext<E: TElement> {
     pub style_context: ThreadLocalStyleContext<E>,
 }
 
 impl<E: TElement> ScopedThreadLocalLayoutContext<E> {
-    pub fn new(shared: &SharedLayoutContext) -> Self {
+    pub fn new(context: &LayoutContext) -> Self {
         ScopedThreadLocalLayoutContext {
-            style_context: ThreadLocalStyleContext::new(&shared.style_context),
+            style_context: ThreadLocalStyleContext::new(&context.style_context),
         }
     }
 }
 
 impl<E: TElement> Borrow<ThreadLocalStyleContext<E>> for ScopedThreadLocalLayoutContext<E> {
     fn borrow(&self) -> &ThreadLocalStyleContext<E> {
         &self.style_context
     }
 }
 
 impl<E: TElement> BorrowMut<ThreadLocalStyleContext<E>> for ScopedThreadLocalLayoutContext<E> {
     fn borrow_mut(&mut self) -> &mut ThreadLocalStyleContext<E> {
         &mut self.style_context
     }
 }
 
-/// TLS data that persists across traversals.
-pub struct PersistentThreadLocalLayoutContext {
-    // FontContext uses Rc all over the place and so isn't Send, which means we
-    // can't use ScopedTLS for it. There's also no reason to scope it to the
-    // traversal, and performance is probably better if we don't.
-    pub font_context: RefCell<FontContext>,
-}
+thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<FontContext>> = RefCell::new(None));
 
-impl PersistentThreadLocalLayoutContext {
-    pub fn new(shared: &SharedLayoutContext) -> Rc<Self> {
-        let font_cache_thread = shared.font_cache_thread.lock().unwrap().clone();
-        Rc::new(PersistentThreadLocalLayoutContext {
-            font_context: RefCell::new(FontContext::new(font_cache_thread)),
-        })
-    }
+pub fn with_thread_local_font_context<F, R>(layout_context: &LayoutContext, f: F) -> R
+    where F: FnOnce(&mut FontContext) -> R
+{
+    FONT_CONTEXT_KEY.with(|k| {
+        let mut font_context = k.borrow_mut();
+        if font_context.is_none() {
+            let font_cache_thread = layout_context.font_cache_thread.lock().unwrap().clone();
+            *font_context = Some(FontContext::new(font_cache_thread));
+        }
+        f(&mut RefMut::map(font_context, |x| x.as_mut().unwrap()))
+    })
 }
 
-impl HeapSizeOf for PersistentThreadLocalLayoutContext {
-    fn heap_size_of_children(&self) -> usize {
-        self.font_context.heap_size_of_children()
-    }
-}
-
-thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<PersistentThreadLocalLayoutContext>>> = RefCell::new(None));
-
-fn create_or_get_persistent_context(shared: &SharedLayoutContext)
-                                    -> Rc<PersistentThreadLocalLayoutContext> {
-    LOCAL_CONTEXT_KEY.with(|r| {
-        let mut r = r.borrow_mut();
-        if let Some(context) = r.clone() {
-            context
+pub fn heap_size_of_persistent_local_context() -> usize {
+    FONT_CONTEXT_KEY.with(|r| {
+        if let Some(ref context) = *r.borrow() {
+            context.heap_size_of_children()
         } else {
-            let context = PersistentThreadLocalLayoutContext::new(shared);
-            *r = Some(context.clone());
-            context
+            0
         }
     })
 }
 
-pub fn heap_size_of_persistent_local_context() -> usize {
-    LOCAL_CONTEXT_KEY.with(|r| {
-        r.borrow().clone().map_or(0, |context| context.heap_size_of_children())
-    })
-}
-
 /// Layout information shared among all workers. This must be thread-safe.
-pub struct SharedLayoutContext {
+pub struct LayoutContext {
     /// Bits shared by the layout and style system.
     pub style_context: SharedStyleContext,
 
     /// The shared image cache thread.
     pub image_cache_thread: Mutex<ImageCacheThread>,
 
     /// A channel for the image cache to send responses to.
     pub image_cache_sender: Mutex<ImageCacheChan>,
@@ -110,52 +89,22 @@ pub struct SharedLayoutContext {
     pub font_cache_thread: Mutex<FontCacheThread>,
 
     /// A cache of WebRender image info.
     pub webrender_image_cache: Arc<RwLock<HashMap<(ServoUrl, UsePlaceholder),
                                                   WebRenderImageInfo,
                                                   BuildHasherDefault<FnvHasher>>>>,
 }
 
-pub struct LayoutContext<'a> {
-    pub shared: &'a SharedLayoutContext,
-    pub persistent: Rc<PersistentThreadLocalLayoutContext>,
-}
-
-impl<'a> LayoutContext<'a> {
-    pub fn new(shared: &'a SharedLayoutContext) -> Self
-    {
-        LayoutContext {
-            shared: shared,
-            persistent: create_or_get_persistent_context(shared),
-        }
-    }
-}
-
-impl<'a> LayoutContext<'a> {
-    // FIXME(bholley): The following two methods are identical and should be merged.
-    // shared_context() is the appropriate name, but it involves renaming a lot of
-    // calls.
+impl LayoutContext {
     #[inline(always)]
     pub fn shared_context(&self) -> &SharedStyleContext {
-        &self.shared.style_context
-    }
-
-    #[inline(always)]
-    pub fn style_context(&self) -> &SharedStyleContext {
-        &self.shared.style_context
+        &self.style_context
     }
 
-    #[inline(always)]
-    pub fn font_context(&self) -> RefMut<FontContext> {
-        self.persistent.font_context.borrow_mut()
-    }
-}
-
-impl SharedLayoutContext {
     fn get_or_request_image_synchronously(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
                                           -> Option<Arc<Image>> {
         debug_assert!(opts::get().output_file.is_some() || opts::get().exit_after_load);
 
         // See if the image is already available
         let result = self.image_cache_thread.lock().unwrap()
                                             .find_image(url.clone(), use_placeholder);
 
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -8,17 +8,17 @@
 //! list building, as the actual painting does not happen here—only deciding *what* we're going to
 //! paint.
 
 #![deny(unsafe_code)]
 
 use app_units::{AU_PER_PX, Au};
 use block::{BlockFlow, BlockStackingContextType};
 use canvas_traits::{CanvasData, CanvasMsg, FromLayoutMsg};
-use context::SharedLayoutContext;
+use context::LayoutContext;
 use euclid::{Point2D, Rect, SideOffsets2D, Size2D, TypedSize2D};
 use flex::FlexFlow;
 use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
 use flow_ref::FlowRef;
 use fragment::{CoordinateSystem, Fragment, ImageFragmentInfo, ScannedTextFragmentInfo};
 use fragment::{SpecificFragmentInfo, TruncatedFragmentInfo};
 use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem};
 use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
@@ -88,17 +88,17 @@ static THREAD_TINT_COLORS: [ColorF; 8] =
     ColorF { r: 137.0 / 255.0, g: 196.0 / 255.0, b: 78.0 / 255.0, a: 0.7 },
 ];
 
 fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
     &arr[index % arr.len()]
 }
 
 pub struct DisplayListBuildState<'a> {
-    pub shared_layout_context: &'a SharedLayoutContext,
+    pub layout_context: &'a LayoutContext,
     pub root_stacking_context: StackingContext,
     pub items: HashMap<StackingContextId, Vec<DisplayItem>>,
     pub stacking_context_children: HashMap<StackingContextId, Vec<StackingContext>>,
     pub scroll_roots: HashMap<ScrollRootId, ScrollRoot>,
     pub processing_scroll_root_element: bool,
 
     /// The current stacking context id, used to keep track of state when building.
     /// recursively building and processing the display list.
@@ -109,19 +109,19 @@ pub struct DisplayListBuildState<'a> {
     pub current_scroll_root_id: ScrollRootId,
 
     /// Vector containing iframe sizes, used to inform the constellation about
     /// new iframe sizes
     pub iframe_sizes: Vec<(PipelineId, TypedSize2D<f32, PagePx>)>,
 }
 
 impl<'a> DisplayListBuildState<'a> {
-    pub fn new(shared_layout_context: &'a SharedLayoutContext) -> DisplayListBuildState<'a> {
+    pub fn new(layout_context: &'a LayoutContext) -> DisplayListBuildState<'a> {
         DisplayListBuildState {
-            shared_layout_context: shared_layout_context,
+            layout_context: layout_context,
             root_stacking_context: StackingContext::root(),
             items: HashMap::new(),
             stacking_context_children: HashMap::new(),
             scroll_roots: HashMap::new(),
             processing_scroll_root_element: false,
             current_stacking_context_id: StackingContextId::root(),
             current_scroll_root_id: ScrollRootId::root(),
             iframe_sizes: Vec::new(),
@@ -677,17 +677,17 @@ impl FragmentDisplayListBuilding for Fra
                                                state: &mut DisplayListBuildState,
                                                style: &ServoComputedValues,
                                                display_list_section: DisplayListSection,
                                                absolute_bounds: &Rect<Au>,
                                                clip: &ClippingRegion,
                                                image_url: &ServoUrl,
                                                index: usize) {
         let background = style.get_background();
-        let webrender_image = state.shared_layout_context
+        let webrender_image = state.layout_context
                                    .get_webrender_image_for_url(image_url.clone(),
                                                                 UsePlaceholder::No);
 
         if let Some(webrender_image) = webrender_image {
             debug!("(building display list) building background image");
 
             // Use `background-size` to get the size.
             let mut bounds = *absolute_bounds;
--- a/servo/components/layout/flex.rs
+++ b/servo/components/layout/flex.rs
@@ -3,33 +3,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Layout for elements with a CSS `display` property of `flex`.
 
 #![deny(unsafe_code)]
 
 use app_units::{Au, MAX_AU};
 use block::{BlockFlow, MarginsMayCollapseFlag};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::{DisplayListBuildState, FlexFlowDisplayListBuilding};
 use euclid::Point2D;
 use floats::FloatKind;
 use flow;
 use flow::{Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use layout_debug;
 use model::{IntrinsicISizes, MaybeAuto, SizeConstraint};
 use model::{specified, specified_or_none};
 use std::cmp::{max, min};
 use std::ops::Range;
 use std::sync::Arc;
 use style::computed_values::{align_content, align_self, flex_direction, flex_wrap, justify_content};
 use style::computed_values::border_collapse;
-use style::context::SharedStyleContext;
 use style::logical_geometry::{Direction, LogicalSize};
 use style::properties::ServoComputedValues;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
 use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::computed::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone};
 
 /// The size of an axis. May be a specified size, a min/max
 /// constraint, or an unlimited size
@@ -484,17 +483,17 @@ impl FlexFlow {
         }
         self.block_flow.base.intrinsic_inline_sizes = computation.finish();
     }
 
     // TODO(zentner): This function needs to be radically different for multi-line flexbox.
     // Currently, this is the core of BlockFlow::propagate_assigned_inline_size_to_children() with
     // all float and table logic stripped out.
     fn block_mode_assign_inline_sizes(&mut self,
-                                      _shared_context: &SharedStyleContext,
+                                      _layout_context: &LayoutContext,
                                       inline_start_content_edge: Au,
                                       inline_end_content_edge: Au,
                                       content_inline_size: Au) {
         let _scope = layout_debug_scope!("flex::block_mode_assign_inline_sizes");
         debug!("flex::block_mode_assign_inline_sizes");
 
         // FIXME (mbrubeck): Get correct mode for absolute containing block
         let containing_block_mode = self.block_flow.base.writing_mode;
@@ -526,17 +525,17 @@ impl FlexFlow {
             }
             kid_base.block_container_inline_size = container_inline_size;
             kid_base.block_container_writing_mode = containing_block_mode;
             kid_base.position.start.i = inline_start_content_edge;
         }
     }
 
     fn inline_mode_assign_inline_sizes(&mut self,
-                                       _shared_context: &SharedStyleContext,
+                                       layout_context: &LayoutContext,
                                        inline_start_content_edge: Au,
                                        _inline_end_content_edge: Au,
                                        content_inline_size: Au) {
         let _scope = layout_debug_scope!("flex::inline_mode_assign_inline_sizes");
         debug!("inline_mode_assign_inline_sizes");
 
         debug!("content_inline_size = {:?}", content_inline_size);
 
@@ -553,17 +552,18 @@ impl FlexFlow {
         };
 
         let container_mode = self.block_flow.base.block_container_writing_mode;
         self.block_flow.base.position.size.inline = inline_size;
 
         // Calculate non-auto block size to pass to children.
         let box_border = self.block_flow.fragment.box_sizing_boundary(Direction::Block);
 
-        let parent_container_size = self.block_flow.explicit_block_containing_size(_shared_context);
+        let parent_container_size =
+            self.block_flow.explicit_block_containing_size(layout_context.shared_context());
         // https://drafts.csswg.org/css-ui-3/#box-sizing
         let explicit_content_size = self
                                     .block_flow
                                     .explicit_block_size(parent_container_size)
                                     .map(|x| max(x - box_border, Au(0)));
         let containing_block_text_align =
             self.block_flow.fragment.style().get_inheritedtext().text_align;
 
@@ -664,17 +664,17 @@ impl FlexFlow {
                 cur_b = cur_b + base.position.size.block;
             } else {
                 cur_b = cur_b - base.position.size.block;
                 base.position.start.b = cur_b;
             }
         }
     }
 
-    fn inline_mode_assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
+    fn inline_mode_assign_block_size(&mut self, layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("flex::inline_mode_assign_block_size");
 
         let line_count = self.lines.len() as i32;
         let line_align = self.block_flow.fragment.style().get_position().align_content;
         let mut cur_b = self.block_flow.fragment.border_padding.block_start;
         let mut total_cross_size = Au(0);
         let mut line_interval = Au(0);
 
@@ -855,30 +855,31 @@ impl Flow for FlexFlow {
         self.items = items;
 
         match self.main_mode {
             Direction::Inline => self.inline_mode_bubble_inline_sizes(),
             Direction::Block  => self.block_mode_bubble_inline_sizes()
         }
     }
 
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("flex::assign_inline_sizes {:x}", self.block_flow.base.debug_id());
         debug!("assign_inline_sizes");
 
         if !self.block_flow.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
             return
         }
 
-        self.block_flow.initialize_container_size_for_root(shared_context);
+        self.block_flow.initialize_container_size_for_root(layout_context.shared_context());
 
         // Our inline-size was set to the inline-size of the containing block by the flow's parent.
         // Now compute the real value.
         let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
-        self.block_flow.compute_used_inline_size(shared_context, containing_block_inline_size);
+        self.block_flow.compute_used_inline_size(layout_context.shared_context(),
+                                                 containing_block_inline_size);
         if self.block_flow.base.flags.is_float() {
             self.block_flow.float.as_mut().unwrap().containing_inline_size = containing_block_inline_size
         }
 
         let (available_block_size, available_inline_size) = {
             let style = &self.block_flow.fragment.style;
             let (specified_block_size, specified_inline_size) = if style.writing_mode.is_vertical() {
                 (style.get_position().width, style.get_position().height)
@@ -915,44 +916,44 @@ impl Flow for FlexFlow {
         debug!("self.block_flow.fragment.border_box.size.inline = {:?}",
                self.block_flow.fragment.border_box.size.inline);
         let content_inline_size = self.block_flow.fragment.border_box.size.inline - padding_and_borders;
 
         match self.main_mode {
             Direction::Inline => {
                 self.available_main_size = available_inline_size;
                 self.available_cross_size = available_block_size;
-                self.inline_mode_assign_inline_sizes(shared_context,
+                self.inline_mode_assign_inline_sizes(layout_context,
                                                      inline_start_content_edge,
                                                      inline_end_content_edge,
                                                      content_inline_size)
             }
             Direction::Block  => {
                 self.available_main_size = available_block_size;
                 self.available_cross_size = available_inline_size;
-                self.block_mode_assign_inline_sizes(shared_context,
+                self.block_mode_assign_inline_sizes(layout_context,
                                                     inline_start_content_edge,
                                                     inline_end_content_edge,
                                                     content_inline_size)
             }
         }
     }
 
-    fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, layout_context: &LayoutContext) {
         self.block_flow
             .assign_block_size_block_base(layout_context,
                                           None,
                                           MarginsMayCollapseFlag::MarginsMayNotCollapse);
         match self.main_mode {
             Direction::Inline => self.inline_mode_assign_block_size(layout_context),
             Direction::Block => self.block_mode_assign_block_size(),
         }
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn place_float_if_applicable<'a>(&mut self) {
         self.block_flow.place_float_if_applicable()
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -22,17 +22,17 @@
 //!
 //! * `InlineFlow`: A flow that establishes an inline context. It has a flat list of child
 //!   fragments/flows that are subject to inline layout and line breaking and structs to represent
 //!   line breaks and mapping to CSS boxes, for the purpose of handling `getClientRects()` and
 //!   similar methods.
 
 use app_units::Au;
 use block::{BlockFlow, FormattingContextType};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::{Point2D, Size2D};
 use flex::FlexFlow;
 use floats::{Floats, SpeculatedFloatPlacement};
 use flow_list::{FlowList, MutFlowListIterator};
 use flow_ref::{FlowRef, WeakFlowRef};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx::display_list::ClippingRegion;
@@ -188,22 +188,22 @@ pub trait Flow: fmt::Debug + Sync + Send
     /// called on this flow, all child flows have had their minimum and preferred inline-sizes set.
     /// This function must decide minimum/preferred inline-sizes based on its children's inline-
     /// sizes and the dimensions of any boxes it is responsible for flowing.
     fn bubble_inline_sizes(&mut self) {
         panic!("bubble_inline_sizes not yet implemented")
     }
 
     /// Pass 2 of reflow: computes inline-size.
-    fn assign_inline_sizes(&mut self, _shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, _ctx: &LayoutContext) {
         panic!("assign_inline_sizes not yet implemented")
     }
 
     /// Pass 3a of reflow: computes block-size.
-    fn assign_block_size<'a>(&mut self, _ctx: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, _ctx: &LayoutContext) {
         panic!("assign_block_size not yet implemented")
     }
 
     /// Like `assign_block_size`, but is recurses explicitly into descendants.
     /// Fit as much content as possible within `available_block_size`.
     /// If that’s not all of it, truncate the contents of `self`
     /// and return a new flow similar to `self` with the rest of the content.
     ///
@@ -229,21 +229,21 @@ pub trait Flow: fmt::Debug + Sync + Send
 
     /// Assigns block-sizes in-order; or, if this is a float, places the float. The default
     /// implementation simply assigns block-sizes if this flow might have floats in. Returns true
     /// if it was determined that this child might have had floats in or false otherwise.
     ///
     /// `parent_thread_id` is the thread ID of the parent. This is used for the layout tinting
     /// debug mode; if the block size of this flow was determined by its parent, we should treat
     /// it as laid out by its parent.
-    fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self,
-                                                            layout_context: &'a LayoutContext<'a>,
-                                                            parent_thread_id: u8,
-                                                            _content_box: LogicalRect<Au>)
-                                                            -> bool {
+    fn assign_block_size_for_inorder_child_if_necessary(&mut self,
+                                                        layout_context: &LayoutContext,
+                                                        parent_thread_id: u8,
+                                                        _content_box: LogicalRect<Au>)
+                                                        -> bool {
         let might_have_floats_in_or_out = base(self).might_have_floats_in() ||
             base(self).might_have_floats_out();
         if might_have_floats_in_or_out {
             mut_base(self).thread_id = parent_thread_id;
             self.assign_block_size(layout_context);
             mut_base(self).restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
         }
         might_have_floats_in_or_out
@@ -344,17 +344,17 @@ pub trait Flow: fmt::Debug + Sync + Send
                 }
             }
             _ => {}
         }
         mut_base(self).overflow = overflow
     }
 
     /// Phase 4 of reflow: computes absolute positions.
-    fn compute_absolute_position(&mut self, _: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, _: &LayoutContext) {
         // The default implementation is a no-op.
         mut_base(self).restyle_damage.remove(REPOSITION)
     }
 
     /// Phase 5 of reflow: builds display lists.
     fn build_display_list(&mut self, state: &mut DisplayListBuildState);
 
     /// Returns the union of all overflow rects of all of this flow's fragments.
--- a/servo/components/layout/fragment.rs
+++ b/servo/components/layout/fragment.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The `Fragment` type, which represents the leaves of the layout tree.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use canvas_traits::CanvasMsg;
-use context::{LayoutContext, SharedLayoutContext};
+use context::{LayoutContext, with_thread_local_font_context};
 use euclid::{Matrix4D, Point2D, Radians, Rect, Size2D};
 use floats::ClearType;
 use flow::{self, ImmutableFlowUtils};
 use flow_ref::FlowRef;
 use gfx;
 use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode};
 use gfx::text::glyph::ByteIndex;
 use gfx::text::text_run::{TextRun, TextRunSlice};
@@ -363,20 +363,20 @@ pub struct ImageFragmentInfo {
 }
 
 impl ImageFragmentInfo {
     /// Creates a new image fragment from the given URL and local image cache.
     ///
     /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little
     /// sense to me.
     pub fn new(url: Option<ServoUrl>,
-               shared_layout_context: &SharedLayoutContext)
+               layout_context: &LayoutContext)
                -> ImageFragmentInfo {
         let image_or_metadata = url.and_then(|url| {
-            shared_layout_context.get_or_request_image_or_meta(url, UsePlaceholder::Yes)
+            layout_context.get_or_request_image_or_meta(url, UsePlaceholder::Yes)
         });
 
         let (image, metadata) = match image_or_metadata {
             Some(ImageOrMetadataAvailable::ImageAvailable(i)) => {
                 (Some(i.clone()), Some(ImageMetadata { height: i.height, width: i.width } ))
             }
             Some(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
                 (None, Some(m))
@@ -637,18 +637,18 @@ impl TableColumnFragmentInfo {
 pub struct TruncatedFragmentInfo {
     pub text_info: Option<ScannedTextFragmentInfo>,
     pub full: Fragment,
 }
 
 impl Fragment {
     /// Constructs a new `Fragment` instance.
     pub fn new<N: ThreadSafeLayoutNode>(node: &N, specific: SpecificFragmentInfo, ctx: &LayoutContext) -> Fragment {
-        let style_context = ctx.style_context();
-        let style = node.style(style_context);
+        let shared_context = ctx.shared_context();
+        let style = node.style(shared_context);
         let writing_mode = style.writing_mode;
 
         let mut restyle_damage = node.restyle_damage();
         restyle_damage.remove(RECONSTRUCT_FLOW);
 
         Fragment {
             node: node.opaque(),
             style: style,
@@ -781,18 +781,19 @@ impl Fragment {
                                    text_overflow_string: String)
                                    -> Fragment {
         let mut unscanned_ellipsis_fragments = LinkedList::new();
         let mut ellipsis_fragment = self.transform(
             self.border_box.size,
             SpecificFragmentInfo::UnscannedText(
                 box UnscannedTextFragmentInfo::new(text_overflow_string, None)));
         unscanned_ellipsis_fragments.push_back(ellipsis_fragment);
-        let ellipsis_fragments = TextRunScanner::new().scan_for_runs(&mut layout_context.font_context(),
-                                                                     unscanned_ellipsis_fragments);
+        let ellipsis_fragments = with_thread_local_font_context(layout_context, |font_context| {
+            TextRunScanner::new().scan_for_runs(font_context, unscanned_ellipsis_fragments)
+        });
         debug_assert!(ellipsis_fragments.len() == 1);
         ellipsis_fragment = ellipsis_fragments.fragments.into_iter().next().unwrap();
         ellipsis_fragment.flags |= IS_ELLIPSIS;
         ellipsis_fragment
     }
 
     pub fn restyle_damage(&self) -> RestyleDamage {
         self.restyle_damage | self.specific.restyle_damage()
@@ -2106,18 +2107,19 @@ impl Fragment {
             }) |
             SpecificFragmentInfo::ScannedText(box ref info) => {
                 // Fragments with no glyphs don't contribute any inline metrics.
                 // TODO: Filter out these fragments during flow construction?
                 if info.insertion_point.is_none() && info.content_size.inline == Au(0) {
                     return InlineMetrics::new(Au(0), Au(0), Au(0));
                 }
                 // See CSS 2.1 § 10.8.1.
-                let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(),
-                                                                self.style.clone_font());
+                let font_metrics = with_thread_local_font_context(layout_context, |font_context| {
+                    text::font_metrics_for_style(font_context, self.style.clone_font())
+                });
                 let line_height = text::line_height_from_style(&*self.style, &font_metrics);
                 InlineMetrics::from_font_metrics(&info.run.font_metrics, line_height)
             }
             SpecificFragmentInfo::InlineBlock(ref info) => {
                 inline_metrics_of_block(&info.flow_ref, &*self.style)
             }
             SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => {
                 inline_metrics_of_block(&info.flow_ref, &*self.style)
@@ -2189,19 +2191,19 @@ impl Fragment {
             // If any of the inline styles say `top` or `bottom`, adjust the vertical align
             // appropriately.
             //
             // FIXME(#5624, pcwalton): This passes our current reftests but isn't the right thing
             // to do.
             match style.get_box().vertical_align {
                 vertical_align::T::baseline => {}
                 vertical_align::T::middle => {
-                    let font_metrics =
-                        text::font_metrics_for_style(&mut layout_context.font_context(),
-                                                     style.clone_font());
+                    let font_metrics = with_thread_local_font_context(layout_context, |font_context| {
+                        text::font_metrics_for_style(font_context, self.style.clone_font())
+                    });
                     offset += (content_inline_metrics.ascent -
                                content_inline_metrics.space_below_baseline -
                                font_metrics.x_height).scale_by(0.5)
                 }
                 vertical_align::T::sub => {
                     offset += minimum_line_metrics.space_needed()
                                                   .scale_by(FONT_SUBSCRIPT_OFFSET_RATIO)
                 }
--- a/servo/components/layout/generated_content.rs
+++ b/servo/components/layout/generated_content.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! The generated content assignment phase.
 //!
 //! This phase handles CSS counters, quotes, and ordered lists per CSS § 12.3-12.5. It cannot be
 //! done in parallel and is therefore a sequential pass that runs on as little of the flow tree
 //! as possible.
 
-use context::LayoutContext;
+use context::{LayoutContext, with_thread_local_font_context};
 use flow::{self, AFFECTS_COUNTERS, Flow, HAS_COUNTER_AFFECTING_CHILDREN, ImmutableFlowUtils};
 use flow::InorderFlowTraversal;
 use fragment::{Fragment, GeneratedContentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
 use gfx::display_list::OpaqueNode;
 use script_layout_interface::wrapper_traits::PseudoElementType;
 use smallvec::SmallVec;
 use std::collections::{HashMap, LinkedList};
 use std::sync::Arc;
@@ -92,28 +92,28 @@ static KATAKANA_IROHA: [char; 47] = [
     'タ', 'レ', 'ソ', 'ツ', 'ネ', 'ナ', 'ラ', 'ム', 'ウ', 'ヰ', 'ノ', 'オ', 'ク', 'ヤ', 'マ',
     'ケ', 'フ', 'コ', 'エ', 'テ', 'ア', 'サ', 'キ', 'ユ', 'メ', 'ミ', 'シ', 'ヱ',
     'ヒ', 'モ', 'セ', 'ス'
 ];
 
 /// The generated content resolution traversal.
 pub struct ResolveGeneratedContent<'a> {
     /// The layout context.
-    layout_context: &'a LayoutContext<'a>,
+    layout_context: &'a LayoutContext,
     /// The counter representing an ordered list item.
     list_item: Counter,
     /// Named CSS counters.
     counters: HashMap<String, Counter>,
     /// The level of quote nesting.
     quote: u32,
 }
 
 impl<'a> ResolveGeneratedContent<'a> {
     /// Creates a new generated content resolution traversal.
-    pub fn new(layout_context: &'a LayoutContext<'a>) -> ResolveGeneratedContent<'a> {
+    pub fn new(layout_context: &'a LayoutContext) -> ResolveGeneratedContent<'a> {
         ResolveGeneratedContent {
             layout_context: layout_context,
             list_item: Counter::new(),
             counters: HashMap::new(),
             quote: 0,
         }
     }
 }
@@ -439,18 +439,19 @@ fn render_text(layout_context: &LayoutCo
     fragments.push_back(Fragment::from_opaque_node_and_style(node,
                                                              pseudo,
                                                              style.clone(),
                                                              style,
                                                              RestyleDamage::rebuild_and_reflow(),
                                                              info));
     // FIXME(pcwalton): This should properly handle multiple marker fragments. This could happen
     // due to text run splitting.
-    let fragments = TextRunScanner::new().scan_for_runs(&mut layout_context.font_context(),
-                                                        fragments);
+    let fragments = with_thread_local_font_context(layout_context, |font_context| {
+        TextRunScanner::new().scan_for_runs(font_context, fragments)
+    });
     if fragments.is_empty() {
         None
     } else {
         Some(fragments.fragments.into_iter().next().unwrap().specific)
     }
 }
 
 /// Appends string that represents the value rendered using the system appropriate for the given
--- a/servo/components/layout/inline.rs
+++ b/servo/components/layout/inline.rs
@@ -1,17 +1,17 @@
 /* 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/. */
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::AbsoluteAssignBSizesTraversal;
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::{DisplayListBuildState, InlineFlowDisplayListBuilding};
 use euclid::{Point2D, Size2D};
 use floats::{FloatKind, Floats, PlacementInfo};
 use flow::{self, BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED};
 use flow::{CONTAINS_TEXT_OR_REPLACED_FRAGMENTS, EarlyAbsolutePositionInfo, MutableFlowUtils};
 use flow::OpaqueFlow;
 use flow_ref::FlowRef;
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
@@ -27,17 +27,16 @@ use range::{Range, RangeIndex};
 use script_layout_interface::wrapper_traits::PseudoElementType;
 use std::{fmt, i32, isize, mem};
 use std::cmp::max;
 use std::collections::VecDeque;
 use std::sync::Arc;
 use style::arc_ptr_eq;
 use style::computed_values::{display, overflow_x, position, text_align, text_justify};
 use style::computed_values::{vertical_align, white_space};
-use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
 use style::properties::{longhands, ServoComputedValues};
 use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPOSITION, RESOLVE_GENERATED_CONTENT};
 use text;
 use unicode_bidi;
 
 /// `Line`s are represented as offsets into the child list, rather than
 /// as an object that "owns" fragments. Choosing a different set of line
@@ -1342,17 +1341,17 @@ impl Flow for InlineFlow {
         intrinsic_sizes_for_flow.union_block(&intrinsic_sizes_for_inline_run.finish());
 
         // Finish up the computation.
         self.base.intrinsic_inline_sizes = intrinsic_sizes_for_flow.finish()
     }
 
     /// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
     /// When called on this context, the context has had its inline-size set by the parent context.
-    fn assign_inline_sizes(&mut self, _: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, _: &LayoutContext) {
         let _scope = layout_debug_scope!("inline::assign_inline_sizes {:x}", self.base.debug_id());
 
         // Initialize content fragment inline-sizes if they haven't been initialized already.
         //
         // TODO: Combine this with `LineBreaker`'s walk in the fragment list, or put this into
         // `Fragment`.
 
         debug!("InlineFlow::assign_inline_sizes: floats in: {:?}", self.base.floats);
@@ -1501,17 +1500,17 @@ impl Flow for InlineFlow {
         });
 
         self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
         for fragment in &mut self.fragments.fragments {
             fragment.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
         }
     }
 
-    fn compute_absolute_position(&mut self, _: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, _: &LayoutContext) {
         // First, gather up the positions of all the containing blocks (if any).
         //
         // FIXME(pcwalton): This will get the absolute containing blocks inside `...` wrong in the
         // case of something like:
         //
         //      <span style="position: relative">
         //          Foo
         //          <span style="display: inline-block">...</span>
--- a/servo/components/layout/list_item.rs
+++ b/servo/components/layout/list_item.rs
@@ -4,28 +4,27 @@
 
 //! Layout for elements with a CSS `display` property of `list-item`. These elements consist of a
 //! block and an extra inline fragment for the marker.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::BlockFlow;
-use context::{LayoutContext, SharedLayoutContext};
+use context::{LayoutContext, with_thread_local_font_context};
 use display_list_builder::{DisplayListBuildState, ListItemFlowDisplayListBuilding};
 use euclid::Point2D;
 use floats::FloatKind;
 use flow::{Flow, FlowClass, OpaqueFlow};
 use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo};
 use fragment::Overflow;
 use generated_content;
 use inline::InlineFlow;
 use std::sync::Arc;
 use style::computed_values::{list_style_type, position};
-use style::context::SharedStyleContext;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 use style::servo::restyle_damage::RESOLVE_GENERATED_CONTENT;
 
 /// A block with the CSS `display` property equal to `list-item`.
 #[derive(Debug)]
 pub struct ListItemFlow {
     /// Data common to all block flows.
@@ -74,56 +73,59 @@ impl Flow for ListItemFlow {
         &self.block_flow
     }
 
     fn bubble_inline_sizes(&mut self) {
         // The marker contributes no intrinsic inline-size, so…
         self.block_flow.bubble_inline_sizes()
     }
 
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
-        self.block_flow.assign_inline_sizes(shared_context);
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
+        self.block_flow.assign_inline_sizes(layout_context);
 
         let mut marker_inline_start = self.block_flow.fragment.border_box.start.i;
 
         for marker in self.marker_fragments.iter_mut().rev() {
             let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
-            let container_block_size = self.block_flow.explicit_block_containing_size(shared_context);
+            let container_block_size =
+                self.block_flow.explicit_block_containing_size(layout_context.shared_context());
             marker.assign_replaced_inline_size_if_necessary(containing_block_inline_size, container_block_size);
 
             // Do this now. There's no need to do this in bubble-widths, since markers do not
             // contribute to the inline size of this flow.
             let intrinsic_inline_sizes = marker.compute_intrinsic_inline_sizes();
 
             marker.border_box.size.inline =
                 intrinsic_inline_sizes.content_intrinsic_sizes.preferred_inline_size;
             marker_inline_start = marker_inline_start - marker.border_box.size.inline;
             marker.border_box.start.i = marker_inline_start;
         }
     }
 
-    fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, layout_context: &LayoutContext) {
         self.block_flow.assign_block_size(layout_context);
 
         // FIXME(pcwalton): Do this during flow construction, like `InlineFlow` does?
-        let marker_line_metrics =
+        let marker_line_metrics = with_thread_local_font_context(layout_context, |font_context| {
             InlineFlow::minimum_line_metrics_for_fragments(&self.marker_fragments,
-                                                           &mut layout_context.font_context(),
-                                                           &*self.block_flow.fragment.style);
+                                                           font_context,
+                                                           &*self.block_flow.fragment.style)
+        });
+
         for marker in &mut self.marker_fragments {
             marker.assign_replaced_block_size_if_necessary();
             let marker_inline_metrics = marker.aligned_inline_metrics(layout_context,
                                                                       &marker_line_metrics,
                                                                       Some(&marker_line_metrics));
             marker.border_box.start.b = marker_line_metrics.space_above_baseline -
                 marker_inline_metrics.ascent;
         }
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn place_float_if_applicable<'a>(&mut self) {
         self.block_flow.place_float_if_applicable()
     }
 
     fn is_absolute_containing_block(&self) -> bool {
--- a/servo/components/layout/multicol.rs
+++ b/servo/components/layout/multicol.rs
@@ -3,28 +3,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! CSS Multi-column layout http://dev.w3.org/csswg/css-multicol/
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::BlockFlow;
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use euclid::Size2D;
 use floats::FloatKind;
 use flow::{Flow, FlowClass, OpaqueFlow, mut_base, FragmentationContext};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use std::cmp::{min, max};
 use std::fmt;
 use std::sync::Arc;
-use style::context::SharedStyleContext;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 use style::values::Either;
 use style::values::computed::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
 
 pub struct MulticolFlow {
     pub block_flow: BlockFlow,
 
@@ -71,30 +70,31 @@ impl Flow for MulticolFlow {
         self
     }
 
     fn bubble_inline_sizes(&mut self) {
         // FIXME(SimonSapin) http://dev.w3.org/csswg/css-sizing/#multicol-intrinsic
         self.block_flow.bubble_inline_sizes();
     }
 
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol");
+        let shared_context = layout_context.shared_context();
         self.block_flow.compute_inline_sizes(shared_context);
 
         // Move in from the inline-start border edge.
         let inline_start_content_edge = self.block_flow.fragment.border_box.start.i +
             self.block_flow.fragment.border_padding.inline_start;
 
         // Distance from the inline-end margin edge to the inline-end content edge.
         let inline_end_content_edge =
             self.block_flow.fragment.margin.inline_end +
             self.block_flow.fragment.border_padding.inline_end;
 
-        self.block_flow.assign_inline_sizes(shared_context);
+        self.block_flow.assign_inline_sizes(layout_context);
         let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
         let content_inline_size =
             self.block_flow.fragment.border_box.size.inline - padding_and_borders;
         let column_width;
         {
             let column_style = self.block_flow.fragment.style.get_column();
 
             let column_gap = match column_style.column_gap {
@@ -119,17 +119,17 @@ impl Flow for MulticolFlow {
 
         self.block_flow.fragment.border_box.size.inline = content_inline_size + padding_and_borders;
 
         self.block_flow.propagate_assigned_inline_size_to_children(
             shared_context, inline_start_content_edge, inline_end_content_edge, column_width,
             |_, _, _, _, _, _| {});
     }
 
-    fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, ctx: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for multicol");
 
         let fragmentation_context = Some(FragmentationContext {
             this_fragment_is_empty: true,
             available_block_size: {
                 let style = &self.block_flow.fragment.style;
                 if let LengthOrPercentageOrAuto::Length(length) = style.content_block_size() {
                     length
@@ -158,17 +158,17 @@ impl Flow for MulticolFlow {
             self.block_flow.base.children.push_back_arc(column);
             column = match remaining {
                 Some(remaining) => remaining,
                 None => break
             };
         }
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context);
         let pitch = LogicalSize::new(self.block_flow.base.writing_mode, self.column_pitch, Au(0));
         let pitch = pitch.to_physical(self.block_flow.base.writing_mode);
         for (i, child) in self.block_flow.base.children.iter_mut().enumerate() {
             let point = &mut mut_base(child).stacking_relative_position;
             *point = *point + Size2D::new(pitch.width * i as i32, pitch.height * i as i32);
         }
     }
@@ -230,33 +230,33 @@ impl Flow for MulticolColumnFlow {
     fn as_block(&self) -> &BlockFlow {
         &self.block_flow
     }
 
     fn bubble_inline_sizes(&mut self) {
         self.block_flow.bubble_inline_sizes();
     }
 
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol column");
-        self.block_flow.assign_inline_sizes(shared_context);
+        self.block_flow.assign_inline_sizes(layout_context);
     }
 
-    fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, ctx: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for multicol column");
         self.block_flow.assign_block_size(ctx);
     }
 
     fn fragment(&mut self, layout_context: &LayoutContext,
                 fragmentation_context: Option<FragmentationContext>)
                 -> Option<Arc<Flow>> {
         Flow::fragment(&mut self.block_flow, layout_context, fragmentation_context)
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
         self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
     }
 
     fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
--- a/servo/components/layout/parallel.rs
+++ b/servo/components/layout/parallel.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Implements parallel traversals over the DOM and flow trees.
 //!
 //! This code is highly unsafe. Keep this file small and easy to audit.
 
 #![allow(unsafe_code)]
 
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use flow::{self, Flow, MutableFlowUtils, PostorderFlowTraversal, PreorderFlowTraversal};
 use flow_ref::FlowRef;
 use profile_traits::time::{self, TimerMetadata, profile};
 use rayon;
 use servo_config::opts;
 use std::mem;
 use std::sync::atomic::{AtomicIsize, Ordering};
 use style::dom::UnsafeNode;
@@ -44,21 +44,16 @@ pub fn mut_owned_flow_to_unsafe_flow(flo
 }
 
 pub fn borrowed_flow_to_unsafe_flow(flow: &Flow) -> UnsafeFlow {
     unsafe {
         mem::transmute::<&Flow, UnsafeFlow>(flow)
     }
 }
 
-pub type ChunkedFlowTraversalFunction<'scope> =
-    extern "Rust" fn(Box<[UnsafeFlow]>, &rayon::Scope<'scope>, &'scope SharedLayoutContext);
-
-pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &LayoutContext);
-
 /// Information that we need stored in each flow.
 pub struct FlowParallelInfo {
     /// The number of children that still need work done.
     pub children_count: AtomicIsize,
     /// The address of the parent flow.
     pub parent: UnsafeFlow,
 }
 
@@ -66,189 +61,134 @@ impl FlowParallelInfo {
     pub fn new() -> FlowParallelInfo {
         FlowParallelInfo {
             children_count: AtomicIsize::new(0),
             parent: null_unsafe_flow(),
         }
     }
 }
 
-/// A parallel bottom-up flow traversal.
-trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
-    /// Process current flow and potentially traverse its ancestors.
-    ///
-    /// If we are the last child that finished processing, recursively process
-    /// our parent. Else, stop. Also, stop at the root.
-    ///
-    /// Thus, if we start with all the leaves of a tree, we end up traversing
-    /// the whole tree bottom-up because each parent will be processed exactly
-    /// once (by the last child that finishes processing).
-    ///
-    /// The only communication between siblings is that they both
-    /// fetch-and-subtract the parent's children count.
-    fn run_parallel(&self, mut unsafe_flow: UnsafeFlow) {
-        loop {
-            // Get a real flow.
-            let flow: &mut Flow = unsafe {
-                mem::transmute(unsafe_flow)
-            };
+/// Process current flow and potentially traverse its ancestors.
+///
+/// If we are the last child that finished processing, recursively process
+/// our parent. Else, stop. Also, stop at the root.
+///
+/// Thus, if we start with all the leaves of a tree, we end up traversing
+/// the whole tree bottom-up because each parent will be processed exactly
+/// once (by the last child that finishes processing).
+///
+/// The only communication between siblings is that they both
+/// fetch-and-subtract the parent's children count.
+fn buttom_up_flow(mut unsafe_flow: UnsafeFlow,
+                  assign_bsize_traversal: &AssignBSizes) {
+    loop {
+        // Get a real flow.
+        let flow: &mut Flow = unsafe {
+            mem::transmute(unsafe_flow)
+        };
 
-            // Perform the appropriate traversal.
-            if self.should_process(flow) {
-                self.process(flow);
-            }
+        // Perform the appropriate traversal.
+        if assign_bsize_traversal.should_process(flow) {
+            assign_bsize_traversal.process(flow);
+        }
 
 
-            let base = flow::mut_base(flow);
+        let base = flow::mut_base(flow);
 
-            // Reset the count of children for the next layout traversal.
-            base.parallel.children_count.store(base.children.len() as isize,
-                                               Ordering::Relaxed);
+        // Reset the count of children for the next layout traversal.
+        base.parallel.children_count.store(base.children.len() as isize,
+                                           Ordering::Relaxed);
 
-            // Possibly enqueue the parent.
-            let unsafe_parent = base.parallel.parent;
-            if unsafe_parent == null_unsafe_flow() {
-                // We're done!
-                break
-            }
+        // Possibly enqueue the parent.
+        let unsafe_parent = base.parallel.parent;
+        if unsafe_parent == null_unsafe_flow() {
+            // We're done!
+            break
+        }
 
-            // No, we're not at the root yet. Then are we the last child
-            // of our parent to finish processing? If so, we can continue
-            // on with our parent; otherwise, we've gotta wait.
-            let parent: &mut Flow = unsafe {
-                mem::transmute(unsafe_parent)
-            };
-            let parent_base = flow::mut_base(parent);
-            if parent_base.parallel.children_count.fetch_sub(1, Ordering::Relaxed) == 1 {
-                // We were the last child of our parent. Reflow our parent.
-                unsafe_flow = unsafe_parent
-            } else {
-                // Stop.
-                break
-            }
+        // No, we're not at the root yet. Then are we the last child
+        // of our parent to finish processing? If so, we can continue
+        // on with our parent; otherwise, we've gotta wait.
+        let parent: &mut Flow = unsafe {
+            mem::transmute(unsafe_parent)
+        };
+        let parent_base = flow::mut_base(parent);
+        if parent_base.parallel.children_count.fetch_sub(1, Ordering::Relaxed) == 1 {
+            // We were the last child of our parent. Reflow our parent.
+            unsafe_flow = unsafe_parent
+        } else {
+            // Stop.
+            break
         }
     }
 }
 
-/// A parallel top-down flow traversal.
-trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
-    fn run_parallel<'scope>(&self,
-                            unsafe_flows: &[UnsafeFlow],
-                            scope: &rayon::Scope<'scope>,
-                            shared: &'scope SharedLayoutContext);
-
-    fn should_record_thread_ids(&self) -> bool;
-
-    #[inline(always)]
-    fn run_parallel_helper<'scope>(&self,
-                                   unsafe_flows: &[UnsafeFlow],
-                                   scope: &rayon::Scope<'scope>,
-                                   shared: &'scope SharedLayoutContext,
-                                   top_down_func: ChunkedFlowTraversalFunction<'scope>,
-                                   bottom_up_func: FlowTraversalFunction)
-    {
-        let mut discovered_child_flows = vec![];
-        let context = LayoutContext::new(&shared);
+fn top_down_flow<'scope>(unsafe_flows: &[UnsafeFlow],
+                         scope: &rayon::Scope<'scope>,
+                         assign_isize_traversal: &'scope AssignISizes,
+                         assign_bsize_traversal: &'scope AssignBSizes)
+{
+    let mut discovered_child_flows = vec![];
 
-        for unsafe_flow in unsafe_flows {
-            let mut had_children = false;
-            unsafe {
-                // Get a real flow.
-                let flow: &mut Flow = mem::transmute(*unsafe_flow);
+    for unsafe_flow in unsafe_flows {
+        let mut had_children = false;
+        unsafe {
+            // Get a real flow.
+            let flow: &mut Flow = mem::transmute(*unsafe_flow);
 
-                if self.should_record_thread_ids() {
-                    // FIXME(emilio): With the switch to rayon we can no longer
-                    // access a thread id from here easily. Either instrument
-                    // rayon (the unstable feature) to get a worker thread
-                    // identifier, or remove all the layout tinting mode.
-                    //
-                    // flow::mut_base(flow).thread_id = proxy.worker_index();
-                }
+            // FIXME(emilio): With the switch to rayon we can no longer
+            // access a thread id from here easily. Either instrument
+            // rayon (the unstable feature) to get a worker thread
+            // identifier, or remove all the layout tinting mode.
+            //
+            // flow::mut_base(flow).thread_id = proxy.worker_index();
 
-                if self.should_process(flow) {
-                    // Perform the appropriate traversal.
-                    self.process(flow);
-                }
-
-                // Possibly enqueue the children.
-                for kid in flow::child_iter_mut(flow) {
-                    had_children = true;
-                    discovered_child_flows.push(borrowed_flow_to_unsafe_flow(kid));
-                }
+            if assign_isize_traversal.should_process(flow) {
+                // Perform the appropriate traversal.
+                assign_isize_traversal.process(flow);
             }
 
-            // If there were no more children, start assigning block-sizes.
-            if !had_children {
-                bottom_up_func(*unsafe_flow, &context)
+            // Possibly enqueue the children.
+            for kid in flow::child_iter_mut(flow) {
+                had_children = true;
+                discovered_child_flows.push(borrowed_flow_to_unsafe_flow(kid));
             }
         }
 
-        for chunk in discovered_child_flows.chunks(CHUNK_SIZE) {
-            let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();
-
-            scope.spawn(move |scope| {
-                top_down_func(nodes, scope, shared);
-            });
+        // If there were no more children, start assigning block-sizes.
+        if !had_children {
+            buttom_up_flow(*unsafe_flow, &assign_bsize_traversal)
         }
     }
-}
-
-impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> {
-    fn run_parallel<'scope>(&self,
-                                  unsafe_flows: &[UnsafeFlow],
-                                  scope: &rayon::Scope<'scope>,
-                                  shared: &'scope SharedLayoutContext)
-    {
-        self.run_parallel_helper(unsafe_flows,
-                                 scope,
-                                 shared,
-                                 assign_inline_sizes,
-                                 assign_block_sizes_and_store_overflow)
-    }
 
-    fn should_record_thread_ids(&self) -> bool {
-        true
-    }
-}
-
-impl<'a> ParallelPostorderFlowTraversal for AssignBSizes<'a> {}
+    for chunk in discovered_child_flows.chunks(CHUNK_SIZE) {
+        let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();
 
-fn assign_inline_sizes<'scope>(unsafe_flows: Box<[UnsafeFlow]>,
-                               scope: &rayon::Scope<'scope>,
-                               shared: &'scope SharedLayoutContext) {
-    let assign_inline_sizes_traversal = AssignISizes {
-        shared_context: &shared.style_context,
-    };
-    assign_inline_sizes_traversal.run_parallel(&unsafe_flows, scope, shared)
-}
-
-fn assign_block_sizes_and_store_overflow(
-        unsafe_flow: UnsafeFlow,
-        context: &LayoutContext) {
-    let assign_block_sizes_traversal = AssignBSizes {
-        layout_context: context,
-    };
-    assign_block_sizes_traversal.run_parallel(unsafe_flow)
+        scope.spawn(move |scope| {
+            top_down_flow(&nodes, scope, &assign_isize_traversal, &assign_bsize_traversal);
+        });
+    }
 }
 
 pub fn traverse_flow_tree_preorder(
         root: &mut Flow,
         profiler_metadata: Option<TimerMetadata>,
         time_profiler_chan: time::ProfilerChan,
-        shared: &SharedLayoutContext,
+        context: &LayoutContext,
         queue: &rayon::ThreadPool) {
     if opts::get().bubble_inline_sizes_separately {
-        let context = LayoutContext::new(shared);
         let bubble_inline_sizes = BubbleISizes { layout_context: &context };
         root.traverse_postorder(&bubble_inline_sizes);
     }
 
+    let assign_isize_traversal = &AssignISizes { layout_context: &context };
+    let assign_bsize_traversal = &AssignBSizes { layout_context: &context };
     let nodes = vec![borrowed_flow_to_unsafe_flow(root)].into_boxed_slice();
 
     queue.install(move || {
         rayon::scope(move |scope| {
             profile(time::ProfilerCategory::LayoutParallelWarmup,
                     profiler_metadata, time_profiler_chan, move || {
-                assign_inline_sizes(nodes, scope, &shared);
+                        top_down_flow(&nodes, scope, assign_isize_traversal, assign_bsize_traversal);
             });
         });
     });
 }
--- a/servo/components/layout/query.rs
+++ b/servo/components/layout/query.rs
@@ -1,17 +1,17 @@
 /* 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/. */
 
 //! Utilities for querying the layout, as needed by the layout thread.
 
 use app_units::Au;
 use construct::ConstructionResult;
-use context::SharedLayoutContext;
+use context::LayoutContext;
 use euclid::point::Point2D;
 use euclid::rect::Rect;
 use euclid::size::Size2D;
 use flow::{self, Flow};
 use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
 use gfx::display_list::{DisplayItemMetadata, DisplayList, OpaqueNode, ScrollOffsetMap};
 use gfx_traits::ScrollRootId;
 use inline::LAST_FRAGMENT_OF_ELEMENT;
@@ -691,17 +691,17 @@ pub fn process_node_scroll_area_request<
             Rect::new(Point2D::new(iterator.origin_rect.origin.x, top),
                       Size2D::new(right, iterator.origin_rect.size.height))
         }
     }
 }
 
 /// Return the resolved value of property for a given (pseudo)element.
 /// https://drafts.csswg.org/cssom/#resolved-value
-pub fn process_resolved_style_request<'a, N>(shared: &SharedLayoutContext,
+pub fn process_resolved_style_request<'a, N>(context: &LayoutContext,
                                              node: N,
                                              pseudo: &Option<PseudoElement>,
                                              property: &PropertyId,
                                              layout_root: &mut Flow) -> String
     where N: LayoutNode,
 {
     use style::traversal::resolve_style;
     let element = node.as_element().unwrap();
@@ -710,19 +710,19 @@ pub fn process_resolved_style_request<'a
     // traversal, so in the common case, the element is styled.
     if element.get_data().is_some() {
         return process_resolved_style_request_internal(node, pseudo, property, layout_root);
     }
 
     // However, the element may be in a display:none subtree. The style system
     // has a mechanism to give us that within a defined scope (after which point
     // it's cleared to maintained style system invariants).
-    let mut tlc = ThreadLocalStyleContext::new(&shared.style_context);
+    let mut tlc = ThreadLocalStyleContext::new(&context.style_context);
     let context = StyleContext {
-        shared: &shared.style_context,
+        shared: &context.style_context,
         thread_local: &mut tlc,
     };
     let mut result = None;
     let ensure = |el: N::ConcreteElement| el.as_node().initialize_data();
     let clear = |el: N::ConcreteElement| el.as_node().clear_data();
     resolve_style(&context, element, &ensure, &clear, |_: &_| {
         let s = process_resolved_style_request_internal(node, pseudo, property, layout_root);
         result = Some(s);
--- a/servo/components/layout/sequential.rs
+++ b/servo/components/layout/sequential.rs
@@ -1,86 +1,83 @@
 /* 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/. */
 
 //! Implements sequential traversals over the DOM and flow trees.
 
 use app_units::Au;
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::point::Point2D;
 use floats::SpeculatedFloatPlacement;
 use flow::{self, Flow, ImmutableFlowUtils, InorderFlowTraversal, MutableFlowUtils};
 use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
 use flow::IS_ABSOLUTELY_POSITIONED;
 use fragment::FragmentBorderBoxIterator;
 use generated_content::ResolveGeneratedContent;
 use servo_config::opts;
 use style::servo::restyle_damage::{REFLOW, STORE_OVERFLOW};
 use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
 
 pub use style::sequential::traverse_dom;
 
-pub fn resolve_generated_content(root: &mut Flow, shared: &SharedLayoutContext) {
+pub fn resolve_generated_content(root: &mut Flow, layout_context: &LayoutContext) {
     fn doit(flow: &mut Flow, level: u32, traversal: &mut ResolveGeneratedContent) {
         if !traversal.should_process(flow) {
             return
         }
 
         traversal.process(flow, level);
 
         for kid in flow::mut_base(flow).children.iter_mut() {
             doit(kid, level + 1, traversal)
         }
     }
 
-    let layout_context = LayoutContext::new(shared);
     let mut traversal = ResolveGeneratedContent::new(&layout_context);
     doit(root, 0, &mut traversal)
 }
 
 pub fn traverse_flow_tree_preorder(root: &mut Flow,
-                                   shared: &SharedLayoutContext) {
+                                   layout_context: &LayoutContext) {
     fn doit(flow: &mut Flow,
             assign_inline_sizes: AssignISizes,
             assign_block_sizes: AssignBSizes) {
         if assign_inline_sizes.should_process(flow) {
             assign_inline_sizes.process(flow);
         }
 
         for kid in flow::child_iter_mut(flow) {
             doit(kid, assign_inline_sizes, assign_block_sizes);
         }
 
         if assign_block_sizes.should_process(flow) {
             assign_block_sizes.process(flow);
         }
     }
 
-    let layout_context = LayoutContext::new(shared);
-
     if opts::get().bubble_inline_sizes_separately {
         let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context };
         {
             let root: &mut Flow = root;
             root.traverse_postorder(&bubble_inline_sizes);
         }
     }
 
-    let assign_inline_sizes = AssignISizes { shared_context: layout_context.shared_context() };
+    let assign_inline_sizes = AssignISizes { layout_context: &layout_context };
     let assign_block_sizes  = AssignBSizes { layout_context: &layout_context };
 
     doit(root, assign_inline_sizes, assign_block_sizes);
 }
 
 pub fn build_display_list_for_subtree<'a>(flow_root: &mut Flow,
-                                          shared_layout_context: &'a SharedLayoutContext)
+                                          layout_context: &'a LayoutContext)
                                           -> DisplayListBuildState<'a> {
-    let mut state = DisplayListBuildState::new(shared_layout_context);
+    let mut state = DisplayListBuildState::new(layout_context);
     flow_root.collect_stacking_contexts(&mut state);
 
     let mut build_display_list = BuildDisplayList { state: state };
     build_display_list.traverse(flow_root);
     build_display_list.state
 }
 
 pub fn iterate_through_flow_tree_fragment_border_boxes(root: &mut Flow,
--- a/servo/components/layout/table.rs
+++ b/servo/components/layout/table.rs
@@ -4,17 +4,17 @@
 
 //! CSS table formatting contexts.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::{BlockFlow, CandidateBSizeIterator, ISizeAndMarginsComputer};
 use block::{ISizeConstraintInput, ISizeConstraintSolution};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::Point2D;
 use flow;
 use flow::{BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow_list::MutFlowListIterator;
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
@@ -340,21 +340,22 @@ impl Flow for TableFlow {
         computation.union_block(&style_specified_intrinsic_inline_size);
         computation.surrounding_size += total_horizontal_spacing;
 
         self.block_flow.base.intrinsic_inline_sizes = computation.finish()
     }
 
     /// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
     /// When called on this context, the context has had its inline-size set by the parent context.
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("table::assign_inline_sizes {:x}",
                                             self.block_flow.base.debug_id());
         debug!("assign_inline_sizes({}): assigning inline_size for flow", "table");
 
+        let shared_context = layout_context.shared_context();
         // The position was set to the containing block by the flow's parent.
         let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
 
         let mut num_unspecified_inline_sizes = 0;
         let mut num_percentage_inline_sizes = 0;
         let mut total_column_inline_size = Au(0);
         let mut total_column_percentage_size = 0.0;
         for column_inline_size in &self.column_intrinsic_inline_sizes {
@@ -459,23 +460,23 @@ impl Flow for TableFlow {
                 let child_table_rowgroup = child_flow.as_mut_table_rowgroup();
                 child_table_rowgroup.populate_collapsed_border_spacing(
                     collapsed_inline_direction_border_widths_for_table,
                     &mut collapsed_block_direction_border_widths_for_table);
             }
         });
     }
 
-    fn assign_block_size<'a>(&mut self, _: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, _: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for table");
         let vertical_spacing = self.spacing().vertical;
         self.block_flow.assign_block_size_for_table_like_flow(vertical_spacing)
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
         self.block_flow.generated_containing_block_size(flow)
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
--- a/servo/components/layout/table_caption.rs
+++ b/servo/components/layout/table_caption.rs
@@ -3,25 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! CSS table formatting contexts.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::BlockFlow;
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use flow::{Flow, FlowClass, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use std::fmt;
 use std::sync::Arc;
-use style::context::SharedStyleContext;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 
 /// A table formatting context.
 pub struct TableCaptionFlow {
     pub block_flow: BlockFlow,
 }
 
@@ -49,27 +48,27 @@ impl Flow for TableCaptionFlow {
     fn as_block(&self) -> &BlockFlow {
         &self.block_flow
     }
 
     fn bubble_inline_sizes(&mut self) {
         self.block_flow.bubble_inline_sizes();
     }
 
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_caption");
-        self.block_flow.assign_inline_sizes(shared_context);
+        self.block_flow.assign_inline_sizes(layout_context);
     }
 
-    fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, layout_context: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for table_caption");
         self.block_flow.assign_block_size(layout_context);
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
         self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
     }
 
     fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
--- a/servo/components/layout/table_cell.rs
+++ b/servo/components/layout/table_cell.rs
@@ -3,30 +3,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! CSS table formatting contexts.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use cssparser::Color;
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
 use flow::{self, Flow, FlowClass, IS_ABSOLUTELY_POSITIONED, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
 use model::MaybeAuto;
 use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode;
 use std::fmt;
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_top_style, vertical_align};
-use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
 use style::properties::ServoComputedValues;
 use table::InternalTable;
 use table_row::{CollapsedBorder, CollapsedBorderProvenance};
 
 /// A table formatting context.
 #[derive(Serialize)]
 pub struct TableCellFlow {
@@ -77,17 +76,17 @@ impl TableCellFlow {
         &mut self.block_flow.fragment
     }
 
     /// Assign block-size for table-cell flow.
     ///
     /// inline(always) because this is only ever called by in-order or non-in-order top-level
     /// methods.
     #[inline(always)]
-    fn assign_block_size_table_cell_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
+    fn assign_block_size_table_cell_base(&mut self, layout_context: &LayoutContext) {
         let remaining = self.block_flow.assign_block_size_block_base(
             layout_context,
             None,
             MarginsMayCollapseFlag::MarginsMayNotCollapse);
         debug_assert!(remaining.is_none());
     }
 
     /// Position this cell's children according to vertical-align.
@@ -188,21 +187,22 @@ impl Flow for TableCellFlow {
             self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size =
                 self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size;
         }
     }
 
     /// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
     /// When called on this context, the context has had its inline-size set by the parent table
     /// row.
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("table_cell::assign_inline_sizes {:x}",
                                             self.block_flow.base.debug_id());
         debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_cell");
 
+        let shared_context = layout_context.shared_context();
         // The position was set to the column inline-size by the parent flow, table row flow.
         let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
 
         let inline_size_computer = InternalTable {
             border_collapse: self.block_flow.fragment.style.get_inheritedtable().border_collapse,
         };
         inline_size_computer.compute_used_inline_size(&mut self.block_flow,
                                                       shared_context,
@@ -221,22 +221,22 @@ impl Flow for TableCellFlow {
 
         self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
                                                                    inline_start_content_edge,
                                                                    inline_end_content_edge,
                                                                    content_inline_size,
                                                                    |_, _, _, _, _, _| {});
     }
 
-    fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, layout_context: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for table_cell");
         self.assign_block_size_table_cell_base(layout_context);
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
         self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
     }
 
     fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
--- a/servo/components/layout/table_colgroup.rs
+++ b/servo/components/layout/table_colgroup.rs
@@ -11,17 +11,16 @@ use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use flow::{BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
 use layout_debug;
 use std::cmp::max;
 use std::fmt;
 use std::sync::Arc;
-use style::context::SharedStyleContext;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 use style::values::computed::LengthOrPercentageOrAuto;
 
 /// A table formatting context.
 pub struct TableColGroupFlow {
     /// Data common to all flows.
     pub base: BaseFlow,
@@ -75,17 +74,17 @@ impl Flow for TableColGroupFlow {
             for _ in 0..span {
                 self.inline_sizes.push(inline_size)
             }
         }
     }
 
     /// Table column inline-sizes are assigned in the table flow and propagated to table row flows
     /// and/or rowgroup flows. Therefore, table colgroup flows do not need to assign inline-sizes.
-    fn assign_inline_sizes(&mut self, _: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, _: &LayoutContext) {
     }
 
     /// Table columns do not have block-size.
     fn assign_block_size(&mut self, _: &LayoutContext) {
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {}
 
--- a/servo/components/layout/table_row.rs
+++ b/servo/components/layout/table_row.rs
@@ -3,33 +3,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! CSS table formatting contexts.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use cssparser::{Color, RGBA};
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::Point2D;
 use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow_list::MutFlowListIterator;
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
 use model::MaybeAuto;
 use serde::{Serialize, Serializer};
 use std::cmp::max;
 use std::fmt;
 use std::iter::{Enumerate, IntoIterator, Peekable};
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_spacing, border_top_style};
-use style::context::SharedStyleContext;
 use style::logical_geometry::{LogicalSize, PhysicalSide, WritingMode};
 use style::properties::ServoComputedValues;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
 use style::values::computed::LengthOrPercentageOrAuto;
 use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, VecExt};
 use table_cell::{CollapsedBordersForCell, TableCellFlow};
 
 /// A single row of a table.
@@ -333,21 +332,22 @@ impl Flow for TableRowFlow {
             }
         }
 
         self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
         self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size,
                                                                                 pref_inline_size);
     }
 
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("table_row::assign_inline_sizes {:x}",
                                          self.block_flow.base.debug_id());
         debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_row");
 
+        let shared_context = layout_context.shared_context();
         // The position was set to the containing block by the flow's parent.
         let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
         // FIXME: In case of border-collapse: collapse, inline_start_content_edge should be
         // border_inline_start.
         let inline_start_content_edge = Au(0);
         let inline_end_content_edge = Au(0);
 
         let inline_size_computer = InternalTable {
@@ -449,17 +449,17 @@ impl Flow for TableRowFlow {
         })
     }
 
     fn assign_block_size(&mut self, layout_context: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for table_row");
         self.assign_block_size_table_row_base(layout_context);
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
         self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
     }
 
     fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
--- a/servo/components/layout/table_rowgroup.rs
+++ b/servo/components/layout/table_rowgroup.rs
@@ -3,29 +3,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! CSS table formatting contexts.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use flow::{Flow, FlowClass, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
 use serde::{Serialize, Serializer};
 use std::fmt;
 use std::iter::{IntoIterator, Iterator, Peekable};
 use std::sync::Arc;
 use style::computed_values::{border_collapse, border_spacing};
-use style::context::SharedStyleContext;
 use style::logical_geometry::LogicalSize;
 use style::properties::ServoComputedValues;
 use table::{ColumnIntrinsicInlineSize, InternalTable, TableLikeFlow};
 
 /// A table formatting context.
 pub struct TableRowGroupFlow {
     /// Fields common to all block flows.
     pub block_flow: BlockFlow,
@@ -114,21 +113,22 @@ impl Flow for TableRowGroupFlow {
         let _scope = layout_debug_scope!("table_rowgroup::bubble_inline_sizes {:x}",
                                          self.block_flow.base.debug_id());
         // Proper calculation of intrinsic sizes in table layout requires access to the entire
         // table, which we don't have yet. Defer to our parent.
     }
 
     /// Recursively (top-down) determines the actual inline-size of child contexts and fragments.
     /// When called on this context, the context has had its inline-size set by the parent context.
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("table_rowgroup::assign_inline_sizes {:x}",
                                             self.block_flow.base.debug_id());
         debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_rowgroup");
 
+        let shared_context = layout_context.shared_context();
         // The position was set to the containing block by the flow's parent.
         let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
         let (inline_start_content_edge, inline_end_content_edge) = (Au(0), Au(0));
         let content_inline_size = containing_block_inline_size;
 
         let border_collapse = self.block_flow.fragment.style.get_inheritedtable().border_collapse;
         let inline_size_computer = InternalTable {
             border_collapse: border_collapse,
@@ -155,22 +155,22 @@ impl Flow for TableRowGroupFlow {
                 let child_table_row = child_flow.as_mut_table_row();
                 child_table_row.populate_collapsed_border_spacing(
                     collapsed_inline_direction_border_widths_for_table,
                     &mut collapsed_block_direction_border_widths_for_table);
             }
         });
     }
 
-    fn assign_block_size<'a>(&mut self, _: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, _: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for table_rowgroup");
         self.block_flow.assign_block_size_for_table_like_flow(self.spacing.vertical)
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
         self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
     }
 
     fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) {
--- a/servo/components/layout/table_wrapper.rs
+++ b/servo/components/layout/table_wrapper.rs
@@ -11,17 +11,17 @@
 //!
 //! Hereafter this document is referred to as INTRINSIC.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::{AbsoluteNonReplaced, BlockFlow, FloatNonReplaced, ISizeAndMarginsComputer, ISizeConstraintInput};
 use block::{ISizeConstraintSolution, MarginsMayCollapseFlag};
-use context::{LayoutContext, SharedLayoutContext};
+use context::LayoutContext;
 use display_list_builder::DisplayListBuildState;
 use euclid::Point2D;
 use floats::FloatKind;
 use flow::{Flow, FlowClass, ImmutableFlowUtils, INLINE_POSITION_IS_STATIC, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use model::MaybeAuto;
 use std::cmp::{max, min};
@@ -328,24 +328,25 @@ impl Flow for TableWrapperFlow {
                 let table = kid.as_table();
                 self.column_intrinsic_inline_sizes = table.column_intrinsic_inline_sizes.clone();
             }
         }
 
         self.block_flow.bubble_inline_sizes();
     }
 
-    fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
+    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
         debug!("assign_inline_sizes({}): assigning inline_size for flow",
                if self.block_flow.base.flags.is_float() {
                    "floated table_wrapper"
                } else {
                    "table_wrapper"
                });
 
+        let shared_context = layout_context.shared_context();
         self.block_flow.initialize_container_size_for_root(shared_context);
 
         let mut intermediate_column_inline_sizes = self.column_intrinsic_inline_sizes
                                                        .iter()
                                                        .map(|column_intrinsic_inline_size| {
             IntermediateColumnInlineSize {
                 size: column_intrinsic_inline_size.minimum_length,
                 percentage: column_intrinsic_inline_size.percentage,
@@ -414,38 +415,38 @@ impl Flow for TableWrapperFlow {
                             assigned_column_inline_sizes.to_vec();
                     }
                 })
             }
         }
 
     }
 
-    fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
+    fn assign_block_size(&mut self, layout_context: &LayoutContext) {
         debug!("assign_block_size: assigning block_size for table_wrapper");
         let remaining = self.block_flow.assign_block_size_block_base(
             layout_context,
             None,
             MarginsMayCollapseFlag::MarginsMayNotCollapse);
         debug_assert!(remaining.is_none());
     }
 
-    fn compute_absolute_position(&mut self, layout_context: &SharedLayoutContext) {
+    fn compute_absolute_position(&mut self, layout_context: &LayoutContext) {
         self.block_flow.compute_absolute_position(layout_context)
     }
 
     fn place_float_if_applicable<'a>(&mut self) {
         self.block_flow.place_float_if_applicable()
     }
 
-    fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self,
-                                                            layout_context: &'a LayoutContext<'a>,
-                                                            parent_thread_id: u8,
-                                                            content_box: LogicalRect<Au>)
-                                                            -> bool {
+    fn assign_block_size_for_inorder_child_if_necessary(&mut self,
+                                                        layout_context: &LayoutContext,
+                                                        parent_thread_id: u8,
+                                                        content_box: LogicalRect<Au>)
+                                                        -> bool {
         self.block_flow.assign_block_size_for_inorder_child_if_necessary(layout_context,
                                                                          parent_thread_id,
                                                                          content_box)
     }
 
     fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
         self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
     }
--- a/servo/components/layout/traversal.rs
+++ b/servo/components/layout/traversal.rs
@@ -1,56 +1,56 @@
 /* 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/. */
 
 //! Traversals over the DOM and flow trees, running the layout computations.
 
 use atomic_refcell::AtomicRefCell;
 use construct::FlowConstructor;
-use context::{LayoutContext, ScopedThreadLocalLayoutContext, SharedLayoutContext};
+use context::{LayoutContext, ScopedThreadLocalLayoutContext};
 use display_list_builder::DisplayListBuildState;
 use flow::{self, PreorderFlowTraversal};
 use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
 use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
 use servo_config::opts;
 use style::context::{SharedStyleContext, StyleContext};
 use style::data::ElementData;
 use style::dom::{NodeInfo, TElement, TNode};
 use style::selector_parser::RestyleDamage;
 use style::servo::restyle_damage::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT};
 use style::traversal::{DomTraversal, TraversalDriver, recalc_style_at};
 use style::traversal::PerLevelTraversalData;
 use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData};
 use wrapper::ThreadSafeLayoutNodeHelpers;
 
 pub struct RecalcStyleAndConstructFlows {
-    shared: SharedLayoutContext,
+    context: LayoutContext,
     driver: TraversalDriver,
 }
 
 impl RecalcStyleAndConstructFlows {
-    pub fn shared_layout_context(&self) -> &SharedLayoutContext {
-        &self.shared
+    pub fn layout_context(&self) -> &LayoutContext {
+        &self.context
     }
 }
 
 impl RecalcStyleAndConstructFlows {
     /// Creates a traversal context, taking ownership of the shared layout context.
-    pub fn new(shared: SharedLayoutContext, driver: TraversalDriver) -> Self {
+    pub fn new(context: LayoutContext, driver: TraversalDriver) -> Self {
         RecalcStyleAndConstructFlows {
-            shared: shared,
+            context: context,
             driver: driver,
         }
     }
 
     /// Consumes this traversal context, returning ownership of the shared layout
     /// context to the caller.
-    pub fn destroy(self) -> SharedLayoutContext {
-        self.shared
+    pub fn destroy(self) -> LayoutContext {
+        self.context
     }
 }
 
 #[allow(unsafe_code)]
 impl<E> DomTraversal<E> for RecalcStyleAndConstructFlows
     where E: TElement,
           E::ConcreteNode: LayoutNode,
 {
@@ -61,26 +61,25 @@ impl<E> DomTraversal<E> for RecalcStyleA
         // FIXME(pcwalton): Stop allocating here. Ideally this should just be
         // done by the HTML parser.
         node.initialize_data();
 
         if !node.is_text_node() {
             let el = node.as_element().unwrap();
             let mut data = el.mutate_data().unwrap();
             let mut context = StyleContext {
-                shared: &self.shared.style_context,
+                shared: &self.context.shared_context(),
                 thread_local: &mut thread_local.style_context,
             };
             recalc_style_at(self, traversal_data, &mut context, el, &mut data);
         }
     }
 
     fn process_postorder(&self, thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode) {
-        let context = LayoutContext::new(&self.shared);
-        construct_flows_at(&context, thread_local, node);
+        construct_flows_at(&self.context, thread_local, node);
     }
 
     fn text_node_needs_traversal(node: E::ConcreteNode) -> bool {
         // Text nodes never need styling. However, there are two cases they may need
         // flow construction:
         // (1) They child doesn't yet have layout data (preorder traversal initializes it).
         // (2) The parent element has restyle damage (so the text flow also needs fixup).
         node.get_raw_data().is_none() ||
@@ -92,38 +91,38 @@ impl<E> DomTraversal<E> for RecalcStyleA
         element.get_data().unwrap()
     }
 
     unsafe fn clear_element_data(element: &E) {
         element.as_node().clear_data();
     }
 
     fn shared_context(&self) -> &SharedStyleContext {
-        &self.shared.style_context
+        &self.context.style_context
     }
 
     fn create_thread_local_context(&self) -> Self::ThreadLocalContext {
-        ScopedThreadLocalLayoutContext::new(&self.shared)
+        ScopedThreadLocalLayoutContext::new(&self.context)
     }
 
     fn is_parallel(&self) -> bool {
         self.driver.is_parallel()
     }
 }
 
 /// A bottom-up, parallelizable traversal.
 pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> {
     /// The operation to perform. Return true to continue or false to stop.
     fn process(&mut self, node: &ConcreteThreadSafeLayoutNode);
 }
 
 /// The flow construction traversal, which builds flows for styled nodes.
 #[inline]
 #[allow(unsafe_code)]
-fn construct_flows_at<'a, N>(context: &LayoutContext<'a>,
+fn construct_flows_at<N>(context: &LayoutContext,
                              _thread_local: &mut ScopedThreadLocalLayoutContext<N::ConcreteElement>,
                              node: N)
     where N: LayoutNode,
 {
     debug!("construct_flows_at: {:?}", node);
 
     // Construct flows for this node.
     {
@@ -148,17 +147,17 @@ fn construct_flows_at<'a, N>(context: &L
     if let Some(el) = node.as_element() {
         unsafe { el.unset_dirty_descendants(); }
     }
 }
 
 /// 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<'a>,
+    pub layout_context: &'a LayoutContext,
 }
 
 impl<'a> PostorderFlowTraversal for BubbleISizes<'a> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         flow.bubble_inline_sizes();
         flow::mut_base(flow).restyle_damage.remove(BUBBLE_ISIZES);
     }
@@ -167,37 +166,37 @@ impl<'a> PostorderFlowTraversal for Bubb
     fn should_process(&self, flow: &mut Flow) -> bool {
         flow::base(flow).restyle_damage.contains(BUBBLE_ISIZES)
     }
 }
 
 /// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`.
 #[derive(Copy, Clone)]
 pub struct AssignISizes<'a> {
-    pub shared_context: &'a SharedStyleContext,
+    pub layout_context: &'a LayoutContext,
 }
 
 impl<'a> PreorderFlowTraversal for AssignISizes<'a> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
-        flow.assign_inline_sizes(self.shared_context);
+        flow.assign_inline_sizes(self.layout_context);
     }
 
     #[inline]
     fn should_process(&self, flow: &mut Flow) -> bool {
         flow::base(flow).restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW)
     }
 }
 
 /// The assign-block-sizes-and-store-overflow traversal, the last (and most expensive) part of
 /// layout computation. Determines the final block-sizes for all layout objects and computes
 /// positions. In Gecko this corresponds to `Reflow`.
 #[derive(Copy, Clone)]
 pub struct AssignBSizes<'a> {
-    pub layout_context: &'a LayoutContext<'a>,
+    pub layout_context: &'a LayoutContext,
 }
 
 impl<'a> PostorderFlowTraversal for AssignBSizes<'a> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         // Can't do anything with anything that floats might flow through until we reach their
         // inorder parent.
         //
@@ -216,17 +215,17 @@ impl<'a> PostorderFlowTraversal for Assi
         base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) &&
         // The fragmentation countainer is responsible for calling Flow::fragment recursively
         !base.flags.contains(CAN_BE_FRAGMENTED)
     }
 }
 
 #[derive(Copy, Clone)]
 pub struct ComputeAbsolutePositions<'a> {
-    pub layout_context: &'a SharedLayoutContext,
+    pub layout_context: &'a LayoutContext,
 }
 
 impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> {
     #[inline]
     fn process(&self, flow: &mut Flow) {
         flow.compute_absolute_position(self.layout_context);
     }
 }
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -54,17 +54,17 @@ use gfx::font;
 use gfx::font_cache_thread::FontCacheThread;
 use gfx::font_context;
 use gfx_traits::{Epoch, FragmentType, ScrollRootId};
 use heapsize::HeapSizeOf;
 use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 use ipc_channel::router::ROUTER;
 use layout::animation;
 use layout::construct::ConstructionResult;
-use layout::context::{LayoutContext, SharedLayoutContext};
+use layout::context::LayoutContext;
 use layout::context::heap_size_of_persistent_local_context;
 use layout::display_list_builder::ToGfxColor;
 use layout::flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
 use layout::flow_ref::FlowRef;
 use layout::incremental::{LayoutDamageComputation, REFLOW_ENTIRE_DOCUMENT};
 use layout::layout_debug;
 use layout::parallel;
 use layout::query::{LayoutRPCImpl, LayoutThreadData, process_content_box_request, process_content_boxes_request};
@@ -501,25 +501,25 @@ impl LayoutThread {
             possibly_locked_rw_data: &mut possibly_locked_rw_data,
         };
         while self.handle_request(&mut rw_data) {
             // Loop indefinitely.
         }
     }
 
     // Create a layout context for use in building display lists, hit testing, &c.
-    fn build_shared_layout_context(&self,
-                                   rw_data: &LayoutThreadData,
-                                   screen_size_changed: bool,
-                                   goal: ReflowGoal)
-                                   -> SharedLayoutContext {
+    fn build_layout_context(&self,
+                            rw_data: &LayoutThreadData,
+                            screen_size_changed: bool,
+                            goal: ReflowGoal)
+                            -> LayoutContext {
         let thread_local_style_context_creation_data =
             ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
 
-        SharedLayoutContext {
+        LayoutContext {
             style_context: SharedStyleContext {
                 viewport_size: self.viewport_size.clone(),
                 screen_size_changed: screen_size_changed,
                 stylist: rw_data.stylist.clone(),
                 goal: goal,
                 running_animations: self.running_animations.clone(),
                 expired_animations: self.expired_animations.clone(),
                 error_reporter: self.error_reporter.clone(),
@@ -618,19 +618,19 @@ impl LayoutThread {
             let flow = flow::mut_base(FlowRef::deref_mut(&mut root_flow));
             flow.restyle_damage.insert(REPAINT);
         }
 
         let reflow_info = Reflow {
             goal: ReflowGoal::ForDisplay,
             page_clip_rect: max_rect(),
         };
-        let mut layout_context = self.build_shared_layout_context(&*rw_data,
-                                                                  false,
-                                                                  reflow_info.goal);
+        let mut layout_context = self.build_layout_context(&*rw_data,
+                                                           false,
+                                                           reflow_info.goal);
 
         self.perform_post_style_recalc_layout_passes(&reflow_info,
                                                      None,
                                                      None,
                                                      &mut *rw_data,
                                                      &mut layout_context);
 
 
@@ -850,79 +850,79 @@ impl LayoutThread {
     }
 
     /// Performs layout constraint solving.
     ///
     /// This corresponds to `Reflow()` in Gecko and `layout()` in WebKit/Blink and should be
     /// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling.
     #[inline(never)]
     fn solve_constraints(layout_root: &mut Flow,
-                         shared_layout_context: &SharedLayoutContext) {
+                         layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("solve_constraints");
-        sequential::traverse_flow_tree_preorder(layout_root, shared_layout_context);
+        sequential::traverse_flow_tree_preorder(layout_root, layout_context);
     }
 
     /// Performs layout constraint solving in parallel.
     ///
     /// This corresponds to `Reflow()` in Gecko and `layout()` in WebKit/Blink and should be
     /// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling.
     #[inline(never)]
     fn solve_constraints_parallel(traversal: &rayon::ThreadPool,
                                   layout_root: &mut Flow,
                                   profiler_metadata: Option<TimerMetadata>,
                                   time_profiler_chan: time::ProfilerChan,
-                                  shared_layout_context: &SharedLayoutContext) {
+                                  layout_context: &LayoutContext) {
         let _scope = layout_debug_scope!("solve_constraints_parallel");
 
         // NOTE: this currently computes borders, so any pruning should separate that
         // operation out.
         parallel::traverse_flow_tree_preorder(layout_root,
                                               profiler_metadata,
                                               time_profiler_chan,
-                                              shared_layout_context,
+                                              layout_context,
                                               traversal);
     }
 
     /// 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,
                                               data: &Reflow,
                                               query_type: Option<&ReflowQueryType>,
                                               document: Option<&ServoLayoutDocument>,
                                               layout_root: &mut Flow,
-                                              shared_layout_context: &mut SharedLayoutContext,
+                                              layout_context: &mut LayoutContext,
                                               rw_data: &mut LayoutThreadData) {
         let writing_mode = flow::base(layout_root).writing_mode;
         let (metadata, sender) = (self.profiler_metadata(), self.time_profiler_chan.clone());
         profile(time::ProfilerCategory::LayoutDispListBuild,
                 metadata.clone(),
                 sender.clone(),
                 || {
             flow::mut_base(layout_root).stacking_relative_position =
                 LogicalPoint::zero(writing_mode).to_physical(writing_mode,
                                                              self.viewport_size);
 
             flow::mut_base(layout_root).clip =
                 ClippingRegion::from_rect(&data.page_clip_rect);
 
             if flow::base(layout_root).restyle_damage.contains(REPOSITION) {
                 layout_root.traverse_preorder(&ComputeAbsolutePositions {
-                    layout_context: shared_layout_context
+                    layout_context: layout_context
                 });
             }
 
             if flow::base(layout_root).restyle_damage.contains(REPAINT) ||
                     rw_data.display_list.is_none() {
                 let display_list_needed = query_type.map(reflow_query_type_needs_display_list)
                                                     .unwrap_or(false);
                 match (data.goal, display_list_needed) {
                     (ReflowGoal::ForDisplay, _) | (ReflowGoal::ForScriptQuery, true) => {
                         let mut build_state =
                             sequential::build_display_list_for_subtree(layout_root,
-                                                                       shared_layout_context);
+                                                                       layout_context);
 
                         debug!("Done building display list.");
 
                         let root_size = {
                             let root_flow = flow::base(layout_root);
                             if rw_data.stylist.viewport_constraints().is_some() {
                                 root_flow.position.size.to_physical(root_flow.writing_mode)
                             } else {
@@ -1162,28 +1162,28 @@ impl LayoutThread {
                 if let Some(s) = restyle.snapshot {
                     restyle_data.snapshot.ensure(move || s);
                 }
                 debug!("Noting restyle for {:?}: {:?}", el, restyle_data);
             }
         }
 
         // Create a layout context for use throughout the following passes.
-        let mut shared_layout_context = self.build_shared_layout_context(&*rw_data,
-                                                                         viewport_size_changed,
-                                                                         data.reflow_info.goal);
+        let mut layout_context = self.build_layout_context(&*rw_data,
+                                                           viewport_size_changed,
+                                                           data.reflow_info.goal);
 
         // 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() {
             TraversalDriver::Parallel
         } else {
             TraversalDriver::Sequential
         };
 
-        let traversal = RecalcStyleAndConstructFlows::new(shared_layout_context, traversal_driver);
+        let traversal = RecalcStyleAndConstructFlows::new(layout_context, traversal_driver);
         let dom_depth = Some(0); // This is always the root node.
         let token = {
             let stylist = &<RecalcStyleAndConstructFlows as
                             DomTraversal<ServoLayoutElement>>::shared_context(&traversal).stylist;
             <RecalcStyleAndConstructFlows as
              DomTraversal<ServoLayoutElement>>::pre_traverse(element, stylist, /* skip_root = */ false)
         };
 
@@ -1216,45 +1216,45 @@ impl LayoutThread {
                                     text_shaping_time,
                                     0,
                                     0);
 
             // Retrieve the (possibly rebuilt) root flow.
             self.root_flow = self.try_get_layout_root(element.as_node());
         }
 
-        shared_layout_context = traversal.destroy();
+        layout_context = traversal.destroy();
 
         if opts::get().dump_style_tree {
             println!("{:?}", ShowSubtreeDataAndPrimaryValues(element.as_node()));
         }
 
         if opts::get().dump_rule_tree {
-            shared_layout_context.style_context.stylist.rule_tree.dump_stdout();
+            layout_context.style_context.stylist.rule_tree.dump_stdout();
         }
 
         // GC the rule tree if some heuristics are met.
-        unsafe { shared_layout_context.style_context.stylist.rule_tree.maybe_gc(); }
+        unsafe { layout_context.style_context.stylist.rule_tree.maybe_gc(); }
 
         // Perform post-style recalculation layout passes.
         self.perform_post_style_recalc_layout_passes(&data.reflow_info,
                                                      Some(&data.query_type),
                                                      Some(&document),
                                                      &mut rw_data,
-                                                     &mut shared_layout_context);
+                                                     &mut layout_context);
 
         self.respond_to_query_if_necessary(&data.query_type,
                                            &mut *rw_data,
-                                           &mut shared_layout_context);
+                                           &mut layout_context);
     }
 
     fn respond_to_query_if_necessary(&mut self,
                                      query_type: &ReflowQueryType,
                                      rw_data: &mut LayoutThreadData,
-                                     shared: &mut SharedLayoutContext) {
+                                     context: &mut LayoutContext) {
         let mut root_flow = match self.root_flow.clone() {
             Some(root_flow) => root_flow,
             None => return,
         };
         let root_flow = FlowRef::deref_mut(&mut root_flow);
         match *query_type {
             ReflowQueryType::ContentBoxQuery(node) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
@@ -1306,17 +1306,17 @@ impl LayoutThread {
             },
             ReflowQueryType::NodeScrollRootIdQuery(node) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
                 rw_data.scroll_root_id_response = Some(process_node_scroll_root_id_request(node));
             },
             ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
                 rw_data.resolved_style_response =
-                    process_resolved_style_request(shared,
+                    process_resolved_style_request(context,
                                                    node,
                                                    pseudo,
                                                    property,
                                                    root_flow);
             },
             ReflowQueryType::OffsetParentQuery(node) => {
                 let node = unsafe { ServoLayoutNode::new(&node) };
                 rw_data.offset_parent_response = process_offset_parent_query(node, root_flow);
@@ -1363,19 +1363,19 @@ impl LayoutThread {
             println!("**** pipeline={}\tForDisplay\tSpecial\tAnimationTick", self.id);
         }
 
         let reflow_info = Reflow {
             goal: ReflowGoal::ForDisplay,
             page_clip_rect: max_rect(),
         };
 
-        let mut layout_context = self.build_shared_layout_context(&*rw_data,
-                                                                  false,
-                                                                  reflow_info.goal);
+        let mut layout_context = self.build_layout_context(&*rw_data,
+                                                           false,
+                                                           reflow_info.goal);
 
         if let Some(mut root_flow) = self.root_flow.clone() {
             // Perform an abbreviated style recalc that operates without access to the DOM.
             let animations = self.running_animations.read();
             profile(time::ProfilerCategory::LayoutStyleRecalc,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || {
@@ -1396,19 +1396,19 @@ impl LayoutThread {
         let mut rw_data = possibly_locked_rw_data.lock();
         font_context::invalidate_font_caches();
 
         let reflow_info = Reflow {
             goal: ReflowGoal::ForDisplay,
             page_clip_rect: max_rect(),
         };
 
-        let mut layout_context = self.build_shared_layout_context(&*rw_data,
-                                                                  false,
-                                                                  reflow_info.goal);
+        let mut layout_context = self.build_layout_context(&*rw_data,
+                                                           false,
+                                                           reflow_info.goal);
 
         // No need to do a style recalc here.
         if self.root_flow.is_none() {
             return
         }
         self.perform_post_style_recalc_layout_passes(&reflow_info,
                                                      None,
                                                      None,
@@ -1416,17 +1416,17 @@ impl LayoutThread {
                                                      &mut layout_context);
     }
 
     fn perform_post_style_recalc_layout_passes(&mut self,
                                                data: &Reflow,
                                                query_type: Option<&ReflowQueryType>,
                                                document: Option<&ServoLayoutDocument>,
                                                rw_data: &mut LayoutThreadData,
-                                               shared: &mut SharedLayoutContext) {
+                                               context: &mut LayoutContext) {
         if let Some(mut root_flow) = self.root_flow.clone() {
             // Kick off animations if any were triggered, expire completed ones.
             animation::update_animation_state(&self.constellation_chan,
                                               &self.script_chan,
                                               &mut *self.running_animations.write(),
                                               &mut *self.expired_animations.write(),
                                               &self.new_animations_receiver,
                                               self.id,
@@ -1448,17 +1448,17 @@ impl LayoutThread {
             if opts::get().trace_layout {
                 layout_debug::begin_trace(root_flow.clone());
             }
 
             // Resolve generated content.
             profile(time::ProfilerCategory::LayoutGeneratedContent,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
-                    || sequential::resolve_generated_content(FlowRef::deref_mut(&mut root_flow), &shared));
+                    || sequential::resolve_generated_content(FlowRef::deref_mut(&mut root_flow), &context));
 
             // Guess float placement.
             profile(time::ProfilerCategory::LayoutFloatPlacementSpeculation,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || sequential::guess_float_placement(FlowRef::deref_mut(&mut root_flow)));
 
             // Perform the primary layout passes over the flow tree to compute the locations of all
@@ -1471,47 +1471,46 @@ impl LayoutThread {
                     let profiler_metadata = self.profiler_metadata();
 
                     if let (true, Some(traversal)) = (self.parallel_flag, self.parallel_traversal.as_mut()) {
                         // Parallel mode.
                         LayoutThread::solve_constraints_parallel(traversal,
                                                                  FlowRef::deref_mut(&mut root_flow),
                                                                  profiler_metadata,
                                                                  self.time_profiler_chan.clone(),
-                                                                 &*shared);
+                                                                 &*context);
                     } else {
                         //Sequential mode
-                        LayoutThread::solve_constraints(FlowRef::deref_mut(&mut root_flow), &shared)
+                        LayoutThread::solve_constraints(FlowRef::deref_mut(&mut root_flow), &context)
                     }
                 });
             }
 
             profile(time::ProfilerCategory::LayoutStoreOverflow,
                     self.profiler_metadata(),
                     self.time_profiler_chan.clone(),
                     || {
-                let context = LayoutContext::new(&shared);
-                sequential::store_overflow(&context,
+                sequential::store_overflow(context,
                                            FlowRef::deref_mut(&mut root_flow) as &mut Flow);
             });
 
             self.perform_post_main_layout_passes(data,
                                                  query_type,
                                                  document,
                                                  rw_data,
-                                                 shared);
+                                                 context);
         }
     }
 
     fn perform_post_main_layout_passes(&mut self,
                                        data: &Reflow,
                                        query_type: Option<&ReflowQueryType>,
                                        document: Option<&ServoLayoutDocument>,
                                        rw_data: &mut LayoutThreadData,
-                                       layout_context: &mut SharedLayoutContext) {
+                                       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() {
             self.compute_abs_pos_and_build_display_list(data,
                                                         query_type,
                                                         document,
                                                         FlowRef::deref_mut(&mut root_flow),
                                                         &mut *layout_context,
                                                         rw_data);