Skip to content
Permalink
Browse files

Remove cached thread local context from LayoutContext

Remove cached thread local context from LayoutContext, use LayoutContext for
assign_inline_sizes(), and simplify the parallel flow traversal code.
  • Loading branch information
stshine committed Feb 8, 2017
1 parent f07bfaa commit 336aa795b4b9933436c9df0200de64e18b6f3b7e
@@ -4,7 +4,7 @@

//! CSS transitions and animations.

use context::SharedLayoutContext;
use context::LayoutContext;
use flow::{self, Flow};
use gfx::display_list::OpaqueNode;
use ipc_channel::ipc::IpcSender;
@@ -132,7 +132,7 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
// 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>>) {
@@ -28,7 +28,7 @@
#![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};
@@ -767,11 +767,11 @@ impl BlockFlow {
/// `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());

@@ -1462,9 +1462,9 @@ impl BlockFlow {
/// 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) {
@@ -1546,10 +1546,10 @@ impl BlockFlow {
// 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);
@@ -1883,9 +1883,10 @@ impl Flow for BlockFlow {
///
/// 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.
@@ -1914,11 +1915,11 @@ impl Flow for BlockFlow {
}
}

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
}
@@ -1950,7 +1951,7 @@ impl Flow for BlockFlow {
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());
}
@@ -1998,7 +1999,7 @@ impl Flow for BlockFlow {
}
}

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));
@@ -15,7 +15,7 @@

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;
@@ -315,7 +315,7 @@ impl InlineFragmentsAccumulator {
/// An object that knows how to create flows.
pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
/// The layout context.
pub layout_context: &'a LayoutContext<'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>,
@@ -324,7 +324,7 @@ pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
FlowConstructor<'a, ConcreteThreadSafeLayoutNode> {
/// Creates a new flow constructor.
pub fn new(layout_context: &'a LayoutContext<'a>) -> Self {
pub fn new(layout_context: &'a LayoutContext) -> Self {
FlowConstructor {
layout_context: layout_context,
phantom2: PhantomData,
@@ -351,12 +351,12 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
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)) => {
@@ -434,8 +434,10 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// 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)));
@@ -464,8 +466,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// 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();
@@ -1216,7 +1219,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
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) => {
@@ -1232,9 +1235,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
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) => {
@@ -20,7 +20,6 @@ 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;
@@ -31,9 +30,9 @@ pub struct ScopedThreadLocalLayoutContext<E: TElement> {
}

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),
}
}
}
@@ -50,53 +49,33 @@ impl<E: TElement> BorrowMut<ThreadLocalStyleContext<E>> for ScopedThreadLocalLay
}
}

/// 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>,
}

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)),
})
}
}
thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<FontContext>> = RefCell::new(None));

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
} else {
let context = PersistentThreadLocalLayoutContext::new(shared);
*r = Some(context.clone());
context
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()))
})
}

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())
FONT_CONTEXT_KEY.with(|r| {
if let Some(ref context) = *r.borrow() {
context.heap_size_of_children()
} else {
0
}
})
}

/// 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,

@@ -115,34 +94,12 @@ pub struct SharedLayoutContext {
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> {
impl LayoutContext {
#[inline(always)]
pub fn shared_context(&self) -> &SharedStyleContext {
&self.shared.style_context
}

#[inline(always)]
pub fn font_context(&self) -> RefMut<FontContext> {
self.persistent.font_context.borrow_mut()
&self.style_context
}
}

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);
@@ -13,7 +13,7 @@
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};
@@ -93,7 +93,7 @@ fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
}

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>>,
@@ -114,9 +114,9 @@ pub struct DisplayListBuildState<'a> {
}

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(),
@@ -682,7 +682,7 @@ impl FragmentDisplayListBuilding for Fragment {
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);

0 comments on commit 336aa79

Please sign in to comment.
You can’t perform that action at this time.