Skip to content

Commit

Permalink
Dump box tree state into json files and display it on layout 2020 viewer
Browse files Browse the repository at this point in the history
  • Loading branch information
ferjm committed Feb 21, 2020
1 parent aaa3cd9 commit a042f85
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 56 deletions.
2 changes: 1 addition & 1 deletion components/layout_2020/flow/float.rs
Expand Up @@ -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,
}
Expand Down
10 changes: 6 additions & 4 deletions components/layout_2020/flow/inline.rs
Expand Up @@ -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<Arc<InlineLevelBox>>,
}

#[derive(Debug)]
#[derive(Debug, Serialize)]
pub(crate) enum InlineLevelBox {
InlineBox(InlineBox),
TextRun(TextRun),
Expand All @@ -37,19 +37,21 @@ pub(crate) enum InlineLevelBox {
Atomic(IndependentFormattingContext),
}

#[derive(Debug)]
#[derive(Debug, Serialize)]
pub(crate) struct InlineBox {
pub tag: OpaqueNode,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
pub first_fragment: bool,
pub last_fragment: bool,
pub children: Vec<Arc<InlineLevelBox>>,
}

/// 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<ComputedValues>,
pub text: String,
}
Expand Down
7 changes: 4 additions & 3 deletions components/layout_2020/flow/mod.rs
Expand Up @@ -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<Arc<BlockLevelBox>>),
InlineFormattingContext(InlineFormattingContext),
}

#[derive(Debug)]
#[derive(Debug, Serialize)]
pub(crate) enum BlockLevelBox {
SameFormattingContextBlock {
tag: OpaqueNode,
#[serde(skip_serializing)]
style: Arc<ComputedValues>,
contents: BlockContainer,
},
Expand Down
1 change: 1 addition & 0 deletions components/layout_2020/flow/root.rs
Expand Up @@ -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)]
Expand Down
5 changes: 3 additions & 2 deletions components/layout_2020/formatting_contexts.rs
Expand Up @@ -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<ComputedValues>,

/// If it was requested during construction
Expand All @@ -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),

Expand Down
61 changes: 43 additions & 18 deletions components/layout_2020/layout_debug.rs
Expand Up @@ -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;
Expand All @@ -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<Box<ScopeData>>,
}

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<FragmentTreeRoot>,
fragment_tree: Arc<FragmentTreeRoot>,
box_tree: Arc<BoxTreeRoot>,
scope_stack: Vec<Box<ScopeData>>,
}

/// 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);
}
});
Expand All @@ -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);
}
Expand All @@ -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<FragmentTreeRoot>) {
pub fn begin_trace(box_tree: Arc<BoxTreeRoot>, fragment_tree: Arc<FragmentTreeRoot>) {
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);
});
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion components/layout_2020/positioned.rs
Expand Up @@ -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,
}
Expand Down
4 changes: 2 additions & 2 deletions components/layout_2020/replaced.rs
Expand Up @@ -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,
Expand All @@ -41,7 +41,7 @@ pub(crate) struct IntrinsicSizes {
pub ratio: Option<CSSFloat>,
}

#[derive(Debug)]
#[derive(Debug, Serialize)]
pub(crate) enum ReplacedContentKind {
Image(Option<Arc<Image>>),
}
Expand Down
4 changes: 2 additions & 2 deletions components/layout_2020/sizing.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down
21 changes: 12 additions & 9 deletions components/layout_thread_2020/lib.rs
Expand Up @@ -173,7 +173,7 @@ pub struct LayoutThread {
outstanding_web_fonts: Arc<AtomicUsize>,

/// The root of the box tree.
box_tree_root: RefCell<Option<BoxTreeRoot>>,
box_tree_root: RefCell<Option<Arc<BoxTreeRoot>>>,

/// The root of the fragment tree.
fragment_tree_root: RefCell<Option<Arc<FragmentTreeRoot>>>,
Expand Down Expand Up @@ -1154,7 +1154,8 @@ impl LayoutThread {
} else {
build_box_tree()
};
Some(box_tree)

Some(Arc::new(box_tree))
} else {
None
};
Expand All @@ -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 {
Expand Down Expand Up @@ -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.
//
Expand All @@ -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();
}
Expand Down

0 comments on commit a042f85

Please sign in to comment.