Auto merge of #7648 - mrobinson:print-tree, r=glennw

Improve printing of DisplayLists

Use box tree characters to make DisplayLists easier to scan when
printing them out.

This is what the output looked like before:
```
#### start printing display list.
"####" Stacking context at Rect(800px×608px at (0px,0px)) with overflow Rect(800px×608px at (0px,0px)):
#### SolidColor(0,0,0,0). Rect(800px×608px at (0px,0px))
#### SolidColor(0,0,0,0). Rect(784px×0px at (8px,0px))
#### SolidColor(0,0.5019608,0,1). Rect(100px×100px at (0px,0px))


#### Child layers list length: 1
"########" Stacking context at Rect(100px×100px at (0px,0px)) with overflow Rect(100px×100px at (0px,0px)):
######## SolidColor(1,0,0,1). Rect(100px×100px at (0px,0px))


######## Child layers list length: 1
"############" Stacking context at Rect(100px×100px at (0px,0px)) with overflow Rect(100px×100px at (0px,0px)):
```

This is what it looks like after this patch:
```
┌ DisplayList
│  ├─ Layered StackingContext at Rect(800px×608px at (0px,0px)) with overflow Rect(800px×608px at (0px,0px)):
│  │  ├─ Block Backgrounds and Borders
│  │  │  ├─ SolidColor rgba(0, 0, 0, 0) @ Rect(800px×608px at (0px,0px)) (7f926f46f1f0)
│  │  │  └─ SolidColor rgba(0, 0, 0, 0) @ Rect(784px×0px at (8px,0px)) (7f926f46f2e0)
│  │  ├─ Layered StackingContext at Rect(100px×100px at (0px,0px)) with overflow Rect(100px×100px at (0px,0px)):
│  │  │  ├─ Backgrounds and Borders
│  │  │  │  └─ SolidColor rgba(1, 0, 0, 1) @ Rect(100px×100px at (0px,0px)) (7f926f46f310)
│  │  │  ├─ Layered StackingContext at Rect(100px×100px at (0px,0px)) with overflow Rect(100px×100px at (0px,0px)):
│  │  ├─ Layered StackingContext at Rect(100px×100px at (0px,0px)) with overflow Rect(100px×100px at (0px,0px)):
│  │  │  ├─ Backgrounds and Borders
│  │  │  │  └─ SolidColor rgba(0, 0.5019608, 0, 1) @ Rect(100px×100px at (0px,0px)) (7f926f46f3a0)
```

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7648)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-09-16 20:43:59 -06:00
commit 4e9a888f1a
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::mem::HeapSizeOf;
use util::opts;
use util::print_tree::PrintTree;
use util::range::Range;
// 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.
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
/// compare it to another opaque handle or to another node.
///
@ -201,62 +200,44 @@ impl DisplayList {
result
}
// Print the display list. Only makes sense to call it after performing reflow.
pub fn print_items(&self, indentation: String) {
// Closures are so nice!
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");
};
pub fn print(&self, title: String) {
let mut print_tree = PrintTree::new(title);
self.print_with_tree(&mut print_tree);
}
doit(&(self.all_display_items()));
if !self.children.is_empty() {
println!("{} Children stacking contexts list length: {}",
indentation,
self.children.len());
for stacking_context in &self.children {
stacking_context.print(indentation.clone() +
&indentation[0..MIN_INDENTATION_LENGTH]);
pub fn print_with_tree(&self, print_tree: &mut PrintTree) {
fn print_display_list_section(print_tree: &mut PrintTree,
items: &LinkedList<DisplayItem>,
title: &str) {
if items.is_empty() {
return;
}
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: {}",
indentation,
self.layered_children.len());
for paint_layer in &self.layered_children {
paint_layer.stacking_context.print(indentation.clone() +
&indentation[0..MIN_INDENTATION_LENGTH]);
}
print_display_list_section(print_tree,
&self.background_and_borders,
"Backgrounds and Borders");
print_display_list_section(print_tree,
&self.block_backgrounds_and_borders,
"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 {
println!("**** optimized display list. Tile bounds: {:?}", paint_context.page_rect);
display_list.print_items("####".to_owned());
display_list.print(format!("Optimized display list. Tile bounds: {:?}",
paint_context.page_rect));
}
// Set up our clip rect and transform.
@ -645,25 +626,23 @@ impl StackingContext {
self.display_list.background_and_borders.iter().rev())
}
pub fn print(&self, mut indentation: String) {
// We cover the case of an empty string.
if indentation.is_empty() {
indentation = "####".to_owned();
pub fn print(&self, title: String) {
let mut print_tree = PrintTree::new(title);
self.print_with_tree(&mut print_tree);
}
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));
}
// We grow the indentation by 4 characters if needed.
// 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);
self.display_list.print_with_tree(print_tree);
print_tree.end_level();
}
}
@ -1301,13 +1280,18 @@ impl fmt::Debug for DisplayItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} @ {:?} ({:x})",
match *self {
DisplayItem::SolidColorClass(_) => "SolidColor",
DisplayItem::TextClass(_) => "Text",
DisplayItem::ImageClass(_) => "Image",
DisplayItem::BorderClass(_) => "Border",
DisplayItem::GradientClass(_) => "Gradient",
DisplayItem::LineClass(_) => "Line",
DisplayItem::BoxShadowClass(_) => "BoxShadow",
DisplayItem::SolidColorClass(ref solid_color) =>
format!("SolidColor rgba({}, {}, {}, {})",
solid_color.color.r,
solid_color.color.g,
solid_color.color.b,
solid_color.color.a),
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().metadata.node.id()

View file

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

View file

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

View file

@ -61,6 +61,7 @@ pub mod mem;
pub mod opts;
pub mod persistent_list;
pub mod prefs;
pub mod print_tree;
pub mod range;
pub mod resource_files;
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);
}
}
}