Improve printing of DisplayLists

Use box tree characters to make DisplayLists easier to scan when
printing them out.
This commit is contained in:
Martin Robinson 2015-09-16 11:56:40 -07:00
parent 2879da54f9
commit 30963d76be
5 changed files with 127 additions and 85 deletions

View file

@ -47,6 +47,7 @@ use util::geometry::{self, Au, MAX_RECT, ZERO_RECT};
use util::linked_list::prepend_from; use util::linked_list::prepend_from;
use util::mem::HeapSizeOf; use util::mem::HeapSizeOf;
use util::opts; use util::opts;
use util::print_tree::PrintTree;
use util::range::Range; use util::range::Range;
// It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for // It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for
@ -59,8 +60,6 @@ pub mod optimizer;
/// items that involve a blur. This ensures that the display item boundaries include all the ink. /// items that involve a blur. This ensures that the display item boundaries include all the ink.
pub static BLUR_INFLATION_FACTOR: i32 = 3; pub static BLUR_INFLATION_FACTOR: i32 = 3;
const MIN_INDENTATION_LENGTH: usize = 4;
/// An opaque handle to a node. The only safe operation that can be performed on this node is to /// An opaque handle to a node. The only safe operation that can be performed on this node is to
/// compare it to another opaque handle or to another node. /// compare it to another opaque handle or to another node.
/// ///
@ -201,62 +200,44 @@ impl DisplayList {
result result
} }
// Print the display list. Only makes sense to call it after performing reflow. pub fn print(&self, title: String) {
pub fn print_items(&self, indentation: String) { let mut print_tree = PrintTree::new(title);
// Closures are so nice! self.print_with_tree(&mut print_tree);
let doit = |items: &Vec<DisplayItem>| { }
for item in items {
match *item {
DisplayItem::SolidColorClass(ref solid_color) => {
println!("{} SolidColor({},{},{},{}). {:?}",
indentation,
solid_color.color.r,
solid_color.color.g,
solid_color.color.b,
solid_color.color.a,
solid_color.base.bounds)
}
DisplayItem::TextClass(ref text) => {
println!("{} Text. {:?}", indentation, text.base.bounds)
}
DisplayItem::ImageClass(ref image) => {
println!("{} Image. {:?}", indentation, image.base.bounds)
}
DisplayItem::BorderClass(ref border) => {
println!("{} Border. {:?}", indentation, border.base.bounds)
}
DisplayItem::GradientClass(ref gradient) => {
println!("{} Gradient. {:?}", indentation, gradient.base.bounds)
}
DisplayItem::LineClass(ref line) => {
println!("{} Line. {:?}", indentation, line.base.bounds)
}
DisplayItem::BoxShadowClass(ref box_shadow) => {
println!("{} Box_shadow. {:?}", indentation, box_shadow.base.bounds)
}
}
}
println!("\n");
};
doit(&(self.all_display_items())); pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
if !self.children.is_empty() { fn print_display_list_section(print_tree: &mut PrintTree,
println!("{} Children stacking contexts list length: {}", items: &LinkedList<DisplayItem>,
indentation, title: &str) {
self.children.len()); if items.is_empty() {
for stacking_context in &self.children { return;
stacking_context.print(indentation.clone() +
&indentation[0..MIN_INDENTATION_LENGTH]);
} }
print_tree.new_level(title.to_owned());
for item in items {
print_tree.add_item(format!("{:?}", item));
}
print_tree.end_level();
} }
if !self.layered_children.is_empty() {
println!("{} Child layers list length: {}", print_display_list_section(print_tree,
indentation, &self.background_and_borders,
self.layered_children.len()); "Backgrounds and Borders");
for paint_layer in &self.layered_children { print_display_list_section(print_tree,
paint_layer.stacking_context.print(indentation.clone() + &self.block_backgrounds_and_borders,
&indentation[0..MIN_INDENTATION_LENGTH]); "Block Backgrounds and Borders");
} print_display_list_section(print_tree, &self.floats, "Floats");
print_display_list_section(print_tree, &self.content, "Content");
print_display_list_section(print_tree, &self.positioned_content, "Positioned Content");
print_display_list_section(print_tree, &self.outlines, "Outlines");
for stacking_context in &self.children {
stacking_context.print_with_tree(print_tree);
}
for paint_layer in &self.layered_children {
paint_layer.stacking_context.print_with_tree(print_tree);
} }
} }
} }
@ -375,8 +356,8 @@ impl StackingContext {
}; };
if opts::get().dump_display_list_optimized { if opts::get().dump_display_list_optimized {
println!("**** optimized display list. Tile bounds: {:?}", paint_context.page_rect); display_list.print(format!("Optimized display list. Tile bounds: {:?}",
display_list.print_items("####".to_owned()); paint_context.page_rect));
} }
// Set up our clip rect and transform. // Set up our clip rect and transform.
@ -645,25 +626,23 @@ impl StackingContext {
self.display_list.background_and_borders.iter().rev()) self.display_list.background_and_borders.iter().rev())
} }
pub fn print(&self, mut indentation: String) { pub fn print(&self, title: String) {
// We cover the case of an empty string. let mut print_tree = PrintTree::new(title);
if indentation.is_empty() { self.print_with_tree(&mut print_tree);
indentation = "####".to_owned(); }
fn print_with_tree(&self, print_tree: &mut PrintTree) {
if self.layer_id.is_some() {
print_tree.new_level(format!("Layered StackingContext at {:?} with overflow {:?}:",
self.bounds,
self.overflow));
} else {
print_tree.new_level(format!("StackingContext at {:?} with overflow {:?}:",
self.bounds,
self.overflow));
} }
self.display_list.print_with_tree(print_tree);
// We grow the indentation by 4 characters if needed. print_tree.end_level();
// I wish to push it all as a slice, but it won't work if the string is a single char.
while indentation.len() < MIN_INDENTATION_LENGTH {
let c = indentation.char_at(0);
indentation.push(c);
}
println!("{:?} Stacking context at {:?} with overflow {:?}:",
indentation,
self.bounds,
self.overflow);
self.display_list.print_items(indentation);
} }
} }
@ -1301,13 +1280,18 @@ impl fmt::Debug for DisplayItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} @ {:?} ({:x})", write!(f, "{} @ {:?} ({:x})",
match *self { match *self {
DisplayItem::SolidColorClass(_) => "SolidColor", DisplayItem::SolidColorClass(ref solid_color) =>
DisplayItem::TextClass(_) => "Text", format!("SolidColor rgba({}, {}, {}, {})",
DisplayItem::ImageClass(_) => "Image", solid_color.color.r,
DisplayItem::BorderClass(_) => "Border", solid_color.color.g,
DisplayItem::GradientClass(_) => "Gradient", solid_color.color.b,
DisplayItem::LineClass(_) => "Line", solid_color.color.a),
DisplayItem::BoxShadowClass(_) => "BoxShadow", DisplayItem::TextClass(_) => "Text".to_owned(),
DisplayItem::ImageClass(_) => "Image".to_owned(),
DisplayItem::BorderClass(_) => "Border".to_owned(),
DisplayItem::GradientClass(_) => "Gradient".to_owned(),
DisplayItem::LineClass(_) => "Line".to_owned(),
DisplayItem::BoxShadowClass(_) => "BoxShadow".to_owned(),
}, },
self.base().bounds, self.base().bounds,
self.base().metadata.node.id() self.base().metadata.node.id()

View file

@ -429,7 +429,6 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
&perspective, &perspective,
parent_id) parent_id)
} }
} }
} }
} }

View file

@ -1060,8 +1060,7 @@ impl LayoutTask {
stacking_context.clone()); stacking_context.clone());
if opts::get().dump_display_list { if opts::get().dump_display_list {
println!("#### start printing display list."); stacking_context.print("DisplayList".to_owned());
stacking_context.print("#".to_owned());
} }
if opts::get().dump_display_list_json { if opts::get().dump_display_list_json {
println!("{}", serde_json::to_string_pretty(&stacking_context).unwrap()); println!("{}", serde_json::to_string_pretty(&stacking_context).unwrap());

View file

@ -61,6 +61,7 @@ pub mod mem;
pub mod opts; pub mod opts;
pub mod persistent_list; pub mod persistent_list;
pub mod prefs; pub mod prefs;
pub mod print_tree;
pub mod range; pub mod range;
pub mod resource_files; pub mod resource_files;
pub mod str; pub mod str;

View file

@ -0,0 +1,59 @@
/* 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/. */
/// A struct that makes it easier to print out a pretty tree of data, which
/// can be visually scanned more easily.
pub struct PrintTree {
/// The current level of recursion.
level: u32,
/// An item which is queued up, so that we can determine if we need
/// a mid-tree prefix or a branch ending prefix.
queued_item: Option<String>,
}
impl PrintTree {
pub fn new(title: String) -> PrintTree {
println!("{}", title);
PrintTree {
level: 1,
queued_item: None,
}
}
/// Descend one level in the tree with the given title.
pub fn new_level(&mut self, title: String) {
self.flush_queued_item("├─");
self.print_level_prefix();
println!("├─ {}", title);
self.level = self.level + 1;
}
/// Ascend one level in the tree.
pub fn end_level(&mut self) {
self.flush_queued_item("└─");
self.level = self.level - 1;
}
/// Add an item to the current level in the tree.
pub fn add_item(&mut self, text: String) {
self.flush_queued_item("├─");
self.queued_item = Some(text);
}
fn print_level_prefix(&self) {
for _ in 0..self.level {
print!("");
}
}
fn flush_queued_item(&mut self, prefix: &str) {
if let Some(queued_item) = self.queued_item.take() {
self.print_level_prefix();
println!("{} {}", prefix, queued_item);
}
}
}