From 61eadbe7f113a620464444298b4902d859fe6aef Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 12 Dec 2016 15:36:41 -0800 Subject: [PATCH] Bug 1322945 - Improve ergonomics and share more code for style crate DOM tree logging. r=heycam MozReview-Commit-ID: 4Fy3ujpI4n2 --- components/layout_thread/lib.rs | 8 +-- components/script/layout_wrapper.rs | 63 ++------------------ components/style/dom.rs | 91 +++++++++++++++++++++++++++-- components/style/gecko/wrapper.rs | 29 ++++----- ports/geckolib/glue.rs | 5 +- 5 files changed, 113 insertions(+), 83 deletions(-) diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 9994eb54bdc..ea834095e6e 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -106,7 +106,7 @@ use std::sync::mpsc::{Receiver, Sender, channel}; use style::animation::Animation; use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext}; use style::data::StoredRestyleHint; -use style::dom::{TElement, TNode}; +use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode}; use style::error_reporting::{ParseErrorReporter, StdoutErrorReporter}; use style::logical_geometry::LogicalPoint; use style::media_queries::{Device, MediaType}; @@ -1035,9 +1035,7 @@ impl LayoutThread { debug!("layout: processing reflow request for: {:?} ({}) (query={:?})", element, self.url, data.query_type); - if log_enabled!(log::LogLevel::Debug) { - element.as_node().dump(); - } + debug!("{:?}", ShowSubtree(element.as_node())); let initial_viewport = data.window_size.initial_viewport; let old_viewport_size = self.viewport_size; @@ -1181,7 +1179,7 @@ impl LayoutThread { } if opts::get().dump_style_tree { - element.as_node().dump_style(); + println!("{:?}", ShowSubtreeDataAndPrimaryValues(element.as_node())); } if opts::get().dump_rule_tree { diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index ab69e8f2cab..0fa54e6fe75 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -86,7 +86,11 @@ impl<'ln> Debug for ServoLayoutNode<'ln> { if let Some(el) = self.as_element() { el.fmt(f) } else { - write!(f, "{:?} ({:#x})", self.type_id(), self.opaque().0) + if self.is_text_node() { + write!(f, " ({:#x})", self.opaque().0) + } else { + write!(f, " ({:#x})", self.opaque().0) + } } } } @@ -156,15 +160,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { transmute(node) } - fn dump(self) { - self.dump_indent(0); - } - - fn dump_style(self) { - println!("\nDOM with computed styles:"); - self.dump_style_indent(0); - } - fn children(self) -> LayoutIterator> { LayoutIterator(ServoChildrenIterator { current: self.first_child(), @@ -290,54 +285,6 @@ impl<'le> GetLayoutData for ServoThreadSafeLayoutElement<'le> { } impl<'ln> ServoLayoutNode<'ln> { - fn dump_indent(self, indent: u32) { - let mut s = String::new(); - for _ in 0..indent { - s.push_str(" "); - } - - s.push_str(&self.debug_str()); - println!("{}", s); - - for kid in self.children() { - kid.dump_indent(indent + 1); - } - } - - fn dump_style_indent(self, indent: u32) { - if self.is_element() { - let mut s = String::new(); - for _ in 0..indent { - s.push_str(" "); - } - s.push_str(&self.debug_style_str()); - println!("{}", s); - } - - for kid in self.children() { - kid.dump_style_indent(indent + 1); - } - } - - fn debug_str(self) -> String { - format!("{:?}: dirty_descendants={}", - self.script_type_id(), - self.as_element().map_or(false, |el| el.has_dirty_descendants())) - } - - fn debug_style_str(self) -> String { - let maybe_element = self.as_element(); - let maybe_data = match maybe_element { - Some(ref el) => el.borrow_data(), - None => None, - }; - if let Some(data) = maybe_data { - format!("{:?}: {:?}", self.script_type_id(), &*data) - } else { - format!("{:?}: style_data=None", self.script_type_id()) - } - } - /// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to /// call and as such is marked `unsafe`. pub unsafe fn get_jsmanaged(&self) -> &LayoutJS { diff --git a/components/style/dom.rs b/components/style/dom.rs index f32f5e8361e..75069ce9305 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -14,6 +14,7 @@ use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement}; use sink::Push; +use std::fmt; use std::fmt::Debug; use std::sync::Arc; use stylist::ApplicableDeclarationBlock; @@ -67,17 +68,13 @@ impl Iterator for LayoutIterator where T: Iterator, I: NodeInfo } } -pub trait TNode : Sized + Copy + Clone + NodeInfo { +pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo { type ConcreteElement: TElement; type ConcreteChildrenIterator: Iterator; fn to_unsafe(&self) -> UnsafeNode; unsafe fn from_unsafe(n: &UnsafeNode) -> Self; - fn dump(self); - - fn dump_style(self); - /// Returns an iterator over this node's children. fn children(self) -> LayoutIterator; @@ -103,6 +100,90 @@ pub trait TNode : Sized + Copy + Clone + NodeInfo { fn parent_node(&self) -> Option; } +/// Wrapper to output the ElementData along with the node when formatting for +/// Debug. +pub struct ShowData(pub N); +impl Debug for ShowData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt_with_data(f, self.0) + } +} + +/// Wrapper to output the primary computed values along with the node when +/// formatting for Debug. This is very verbose. +pub struct ShowDataAndPrimaryValues(pub N); +impl Debug for ShowDataAndPrimaryValues { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt_with_data_and_primary_values(f, self.0) + } +} + +/// Wrapper to output the subtree rather than the single node when formatting +/// for Debug. +pub struct ShowSubtree(pub N); +impl Debug for ShowSubtree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(writeln!(f, "DOM Subtree:")); + fmt_subtree(f, &|f, n| write!(f, "{:?}", n), self.0, 1) + } +} + +/// Wrapper to output the subtree along with the ElementData when formatting +/// for Debug. +pub struct ShowSubtreeData(pub N); +impl Debug for ShowSubtreeData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(writeln!(f, "DOM Subtree:")); + fmt_subtree(f, &|f, n| fmt_with_data(f, n), self.0, 1) + } +} + +/// Wrapper to output the subtree along with the ElementData and primary +/// ComputedValues when formatting for Debug. This is extremely verbose. +pub struct ShowSubtreeDataAndPrimaryValues(pub N); +impl Debug for ShowSubtreeDataAndPrimaryValues { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(writeln!(f, "DOM Subtree:")); + fmt_subtree(f, &|f, n| fmt_with_data_and_primary_values(f, n), self.0, 1) + } +} + +fn fmt_with_data(f: &mut fmt::Formatter, n: N) -> fmt::Result { + if let Some(el) = n.as_element() { + write!(f, "{:?} dd={} data={:?}", el, el.has_dirty_descendants(), el.borrow_data()) + } else { + write!(f, "{:?}", n) + } +} + +fn fmt_with_data_and_primary_values(f: &mut fmt::Formatter, n: N) -> fmt::Result { + if let Some(el) = n.as_element() { + let dd = el.has_dirty_descendants(); + let data = el.borrow_data(); + let styles = data.as_ref().and_then(|d| d.get_styles()); + let values = styles.map(|s| &s.primary.values); + write!(f, "{:?} dd={} data={:?} values={:?}", el, dd, &data, values) + } else { + write!(f, "{:?}", n) + } +} + +fn fmt_subtree(f: &mut fmt::Formatter, stringify: &F, n: N, indent: u32) + -> fmt::Result + where F: Fn(&mut fmt::Formatter, N) -> fmt::Result +{ + for _ in 0..indent { + try!(write!(f, " ")); + } + try!(stringify(f, n)); + for kid in n.children() { + try!(writeln!(f, "")); + try!(fmt_subtree(f, stringify, kid, indent + 1)); + } + + Ok(()) +} + pub trait PresentationalHintsSynthetizer { fn synthesize_presentational_hints_for_legacy_attributes(&self, hints: &mut V) where V: Push; diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index f8629a24fe3..4f9ef32305a 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -50,6 +50,20 @@ use stylist::ApplicableDeclarationBlock; #[derive(Clone, Copy)] pub struct GeckoNode<'ln>(pub &'ln RawGeckoNode); +impl<'ln> fmt::Debug for GeckoNode<'ln> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(el) = self.as_element() { + el.fmt(f) + } else { + if self.is_text_node() { + write!(f, " ({:#x})", self.opaque().0) + } else { + write!(f, " ({:#x})", self.opaque().0) + } + } + } +} + impl<'ln> GeckoNode<'ln> { fn from_content(content: &'ln nsIContent) -> Self { GeckoNode(&content._base) @@ -102,19 +116,6 @@ impl<'ln> TNode for GeckoNode<'ln> { GeckoNode(&*(n.0 as *mut RawGeckoNode)) } - fn dump(self) { - if self.is_text_node() { - println!("Text ({:?})", &self.0 as *const _); - } else { - let el = self.as_element().unwrap(); - println!("Element {} ({:?})", el.get_local_name(), &el.0 as *const _); - } - } - - fn dump_style(self) { - unimplemented!() - } - fn children(self) -> LayoutIterator> { let maybe_iter = unsafe { Gecko_MaybeCreateStyleChildrenIterator(self.0) }; if let Some(iter) = maybe_iter.into_owned_opt() { @@ -211,7 +212,7 @@ impl<'le> fmt::Debug for GeckoElement<'le> { if let Some(id) = self.get_id() { try!(write!(f, " id={}", id)); } - write!(f, "> ({:?})", self.0 as *const _) + write!(f, "> ({:#x})", self.as_node().opaque().0) } } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 8d832d393a9..63016b1a50a 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -18,7 +18,7 @@ use style::arc_ptr_eq; use style::atomic_refcell::AtomicRefMut; use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext}; use style::data::{ElementData, RestyleData}; -use style::dom::{TElement, TNode}; +use style::dom::{ShowSubtreeData, TElement, TNode}; use style::error_reporting::StdoutErrorReporter; use style::gecko::context::StandaloneStyleContext; use style::gecko::context::clear_local_context; @@ -145,6 +145,9 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed, return; } + debug!("Traversing subtree:"); + debug!("{:?}", ShowSubtreeData(element.as_node())); + let shared_style_context = create_shared_context(&mut per_doc_data); let known_depth = None;