diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 7c7a2ab5a31..5b34392ac8c 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -10,7 +10,7 @@ use crate::style_ext::{ComputedValuesExt, DisplayInside}; use servo_arc::Arc; use style::properties::ComputedValues; -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) struct FloatBox { pub contents: IndependentFormattingContext, } diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index ae75b8f055b..5cee99440ad 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -23,12 +23,12 @@ use style::values::specified::text::TextAlignKeyword; use style::Zero; use webrender_api::FontInstanceKey; -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize)] pub(crate) struct InlineFormattingContext { pub(super) inline_level_boxes: Vec>, } -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) enum InlineLevelBox { InlineBox(InlineBox), TextRun(TextRun), @@ -37,9 +37,10 @@ pub(crate) enum InlineLevelBox { Atomic(IndependentFormattingContext), } -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) struct InlineBox { pub tag: OpaqueNode, + #[serde(skip_serializing)] pub style: Arc, pub first_fragment: bool, pub last_fragment: bool, @@ -47,9 +48,10 @@ pub(crate) struct InlineBox { } /// https://www.w3.org/TR/css-display-3/#css-text-run -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) struct TextRun { pub tag: OpaqueNode, + #[serde(skip_serializing)] pub parent_style: Arc, pub text: String, } diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index f407b4ffd0e..635b5d9cdc2 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -31,22 +31,23 @@ mod root; pub use root::{BoxTreeRoot, FragmentTreeRoot}; -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) struct BlockFormattingContext { pub contents: BlockContainer, pub contains_floats: bool, } -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) enum BlockContainer { BlockLevelBoxes(Vec>), InlineFormattingContext(InlineFormattingContext), } -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) enum BlockLevelBox { SameFormattingContextBlock { tag: OpaqueNode, + #[serde(skip_serializing)] style: Arc, contents: BlockContainer, }, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index ed880a3d9ce..f1fcad7fd45 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -28,6 +28,7 @@ use style::properties::ComputedValues; use style::values::computed::Length; use style_traits::CSSPixel; +#[derive(Serialize)] pub struct BoxTreeRoot(BlockFormattingContext); #[derive(Serialize)] diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index b8fc029c887..e4baf169476 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -18,9 +18,10 @@ use style::properties::ComputedValues; use style::values::computed::Length; /// https://drafts.csswg.org/css-display/#independent-formatting-context -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) struct IndependentFormattingContext { pub tag: OpaqueNode, + #[serde(skip_serializing)] pub style: Arc, /// If it was requested during construction @@ -38,7 +39,7 @@ pub(crate) struct IndependentLayout { // Private so that code outside of this module cannot match variants. // It should got through methods instead. -#[derive(Debug)] +#[derive(Debug, Serialize)] enum IndependentFormattingContextContents { Flow(BlockFormattingContext), diff --git a/components/layout_2020/layout_debug.rs b/components/layout_2020/layout_debug.rs index 4e28ce8ffeb..d7c59e6cf3c 100644 --- a/components/layout_2020/layout_debug.rs +++ b/components/layout_2020/layout_debug.rs @@ -5,7 +5,7 @@ //! Supports writing a trace file created during each layout scope //! that can be viewed by an external tool to make layout debugging easier. -use crate::flow::FragmentTreeRoot; +use crate::flow::{BoxTreeRoot, FragmentTreeRoot}; use serde_json::{to_string, to_value, Value}; use std::cell::RefCell; use std::fs::File; @@ -32,38 +32,52 @@ macro_rules! layout_debug_scope( ) ); +#[derive(Serialize)] +struct TreeValues { + pub box_tree: Value, + pub fragment_tree: Value, +} + #[derive(Serialize)] struct ScopeData { name: String, - pre: Value, - post: Value, + pre: TreeValues, + post: TreeValues, children: Vec>, } impl ScopeData { - fn new(name: String, pre: Value) -> ScopeData { + fn new(name: String, box_tree: Value, fragment_tree: Value) -> ScopeData { ScopeData { - name: name, - pre: pre, - post: Value::Null, + name, + pre: TreeValues { + box_tree, + fragment_tree, + }, + post: TreeValues { + box_tree: Value::Null, + fragment_tree: Value::Null, + }, children: vec![], } } } struct State { - fragment: Arc, + fragment_tree: Arc, + box_tree: Arc, scope_stack: Vec>, } -/// A layout debugging scope. The entire state of the fragment tree +/// A layout debugging scope. The entire state of the box and fragment trees /// will be output at the beginning and end of this scope. impl Scope { pub fn new(name: String) -> Scope { STATE_KEY.with(|ref r| { if let Some(ref mut state) = *r.borrow_mut() { - let fragment_tree = to_value(&state.fragment).unwrap(); - let data = Box::new(ScopeData::new(name.clone(), fragment_tree)); + let box_tree = to_value(&state.box_tree).unwrap(); + let fragment_tree = to_value(&state.fragment_tree).unwrap(); + let data = Box::new(ScopeData::new(name.clone(), box_tree, fragment_tree)); state.scope_stack.push(data); } }); @@ -77,7 +91,10 @@ impl Drop for Scope { STATE_KEY.with(|ref r| { if let Some(ref mut state) = *r.borrow_mut() { let mut current_scope = state.scope_stack.pop().unwrap(); - current_scope.post = to_value(&state.fragment).unwrap(); + current_scope.post = TreeValues { + box_tree: to_value(&state.box_tree).unwrap(), + fragment_tree: to_value(&state.fragment_tree).unwrap(), + }; let previous_scope = state.scope_stack.last_mut().unwrap(); previous_scope.children.push(current_scope); } @@ -93,14 +110,20 @@ pub fn generate_unique_debug_id() -> u16 { /// Begin a layout debug trace. If this has not been called, /// creating debug scopes has no effect. -pub fn begin_trace(root: Arc) { +pub fn begin_trace(box_tree: Arc, fragment_tree: Arc) { assert!(STATE_KEY.with(|ref r| r.borrow().is_none())); STATE_KEY.with(|ref r| { - let root_trace = to_value(&root).unwrap(); + let box_tree_value = to_value(&box_tree).unwrap(); + let fragment_tree_value = to_value(&fragment_tree).unwrap(); let state = State { - scope_stack: vec![Box::new(ScopeData::new("root".to_owned(), root_trace))], - fragment: root.clone(), + scope_stack: vec![Box::new(ScopeData::new( + "root".to_owned(), + box_tree_value, + fragment_tree_value, + ))], + box_tree, + fragment_tree, }; *r.borrow_mut() = Some(state); }); @@ -113,8 +136,10 @@ pub fn end_trace(generation: u32) { let mut thread_state = STATE_KEY.with(|ref r| r.borrow_mut().take().unwrap()); assert_eq!(thread_state.scope_stack.len(), 1); let mut root_scope = thread_state.scope_stack.pop().unwrap(); - root_scope.post = to_value(&thread_state.fragment).unwrap(); - + root_scope.post = TreeValues { + box_tree: to_value(&thread_state.box_tree).unwrap_or(Value::Null), + fragment_tree: to_value(&thread_state.fragment_tree).unwrap_or(Value::Null), + }; let result = to_string(&root_scope).unwrap(); let mut file = File::create(format!("layout_trace-{}.json", generation)).unwrap(); file.write_all(result.as_bytes()).unwrap(); diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 3c4ec876fc7..5314347e95b 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -18,7 +18,7 @@ use style::properties::ComputedValues; use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; use style::Zero; -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) struct AbsolutelyPositionedBox { pub contents: IndependentFormattingContext, } diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index d979c9df481..ba388c0521c 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -17,7 +17,7 @@ use style::values::computed::{Length, LengthOrAuto}; use style::values::CSSFloat; use style::Zero; -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) struct ReplacedContent { pub kind: ReplacedContentKind, intrinsic: IntrinsicSizes, @@ -41,7 +41,7 @@ pub(crate) struct IntrinsicSizes { pub ratio: Option, } -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) enum ReplacedContentKind { Image(Option>), } diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index f5dac929b84..b92360bf42f 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -48,7 +48,7 @@ impl ContentSizesRequest { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] pub(crate) struct ContentSizes { pub min_content: Length, pub max_content: Length, @@ -83,7 +83,7 @@ impl ContentSizes { } /// Optional min/max-content for storage in the box tree -#[derive(Debug)] +#[derive(Debug, Serialize)] pub(crate) enum BoxContentSizes { NoneWereRequested, // … during box construction Inline(ContentSizes), diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 6a2ba3b706b..3f2aed688d8 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -173,7 +173,7 @@ pub struct LayoutThread { outstanding_web_fonts: Arc, /// The root of the box tree. - box_tree_root: RefCell>, + box_tree_root: RefCell>>, /// The root of the fragment tree. fragment_tree_root: RefCell>>, @@ -1154,7 +1154,8 @@ impl LayoutThread { } else { build_box_tree() }; - Some(box_tree) + + Some(Arc::new(box_tree)) } else { None }; @@ -1167,13 +1168,13 @@ impl LayoutThread { self.viewport_size.height.to_f32_px(), ); let run_layout = || box_tree.layout(&layout_context, viewport_size); - let fragment_tree = if let Some(pool) = rayon_pool { + let fragment_tree = Arc::new(if let Some(pool) = rayon_pool { pool.install(run_layout) } else { run_layout() - }; + }); *self.box_tree_root.borrow_mut() = Some(box_tree); - *self.fragment_tree_root.borrow_mut() = Some(Arc::new(fragment_tree)); + *self.fragment_tree_root.borrow_mut() = Some(fragment_tree); } for element in elements_with_snapshot { @@ -1382,6 +1383,12 @@ impl LayoutThread { document: Option<&ServoLayoutDocument>, context: &mut LayoutContext, ) { + if self.trace_layout { + if let Some(box_tree) = &*self.box_tree_root.borrow() { + layout_debug::begin_trace(box_tree.clone(), fragment_tree.clone()); + } + } + if !reflow_goal.needs_display() { // Defer the paint step until the next ForDisplay. // @@ -1393,10 +1400,6 @@ impl LayoutThread { return; } - if self.trace_layout { - layout_debug::begin_trace(fragment_tree.clone()); - } - if let Some(document) = document { document.will_paint(); } diff --git a/etc/layout_viewer/viewer.html b/etc/layout_viewer/viewer.html index f60dcab8909..9bea6942485 100644 --- a/etc/layout_viewer/viewer.html +++ b/etc/layout_viewer/viewer.html @@ -54,6 +54,14 @@
+
+
+
+
Box Tree
+
+
+
+
@@ -90,10 +98,69 @@