servo: Merge #12831 - Add a flag to dump the computed style values (from notriddle:master); r=Manishearth
authorMichael Howell <michael@notriddle.com>
Fri, 12 Aug 2016 20:55:27 -0500
changeset 339486 c867e0247b066cb67a48ad4fbfcb1fbaf06a5abf
parent 339485 14f16d3626e039515989bb5b69d38f0403b822c7
child 339487 b9860b026ee43a1cfd859c43d271b6ef477b566f
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth
servo: Merge #12831 - Add a flag to dump the computed style values (from notriddle:master); r=Manishearth I used this to trace #11818 to a style bug, rather than a layout bug. --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes do not fix any issues - [X] These changes do not require tests because debugging Source-Repo: https://github.com/servo/servo Source-Revision: 7b1f75b605c1b1abf87f084362126db60109bb65
servo/components/layout_thread/lib.rs
servo/components/script/layout_wrapper.rs
servo/components/style/dom.rs
servo/components/util/opts.rs
servo/ports/geckolib/wrapper.rs
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -1182,16 +1182,20 @@ impl LayoutThread {
                                     text_shaping_time,
                                     0,
                                     0);
 
             // Retrieve the (possibly rebuilt) root flow.
             self.root_flow = self.try_get_layout_root(node);
         }
 
+        if opts::get().dump_style_tree {
+            node.dump_style();
+        }
+
         // Perform post-style recalculation layout passes.
         self.perform_post_style_recalc_layout_passes(&data.reflow_info,
                                                      &mut rw_data,
                                                      &mut shared_layout_context);
 
         if let Some(mut root_flow) = self.root_flow.clone() {
             match data.query_type {
                 ReflowQueryType::ContentBoxQuery(node) => {
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -135,16 +135,21 @@ impl<'ln> TNode for ServoLayoutNode<'ln>
             self.node.is_element_for_layout()
         }
     }
 
     fn dump(self) {
         self.dump_indent(0);
     }
 
+    fn dump_style(self) {
+        println!("\nDOM with computed styles:");
+        self.dump_style_indent(0);
+    }
+
     fn opaque(&self) -> OpaqueNode {
         unsafe { self.get_jsmanaged().opaque() }
     }
 
     fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<ServoLayoutNode<'ln>> {
         if self.opaque() == reflow_root {
             None
         } else {
@@ -315,21 +320,48 @@ impl<'ln> ServoLayoutNode<'ln> {
         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!("{:?}: changed={} dirty={} dirty_descendants={}",
                 self.script_type_id(), self.has_changed(), self.is_dirty(), self.has_dirty_descendants())
     }
 
+    fn debug_style_str(self) -> String {
+        if let Some(data) = self.borrow_data() {
+            if let Some(data) = data.style.as_ref() {
+                format!("{:?}: {:?}", self.script_type_id(), data)
+            } else {
+                format!("{:?}: style=None", self.script_type_id())
+            }
+        } 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`.
     unsafe fn get_jsmanaged(&self) -> &LayoutJS<Node> {
         &self.node
     }
 }
 
 // A wrapper around documents that ensures ayout can only ever access safe properties.
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -76,16 +76,18 @@ pub trait TNode : Sized + Copy + Clone {
     /// about, and thus obviates the need to compute the full type id, which would be expensive in
     /// Gecko.
     fn is_text_node(&self) -> bool;
 
     fn is_element(&self) -> bool;
 
     fn dump(self);
 
+    fn dump_style(self);
+
     fn traverse_preorder(self) -> TreeIterator<Self> {
         TreeIterator::new(self)
     }
 
     /// Returns an iterator over this node's children.
     fn children(self) -> ChildrenIterator<Self> {
         ChildrenIterator {
             current: self.first_child(),
--- a/servo/components/util/opts.rs
+++ b/servo/components/util/opts.rs
@@ -150,16 +150,19 @@ pub struct Opts {
     /// Probability of randomly closing a pipeline,
     /// used for testing the hardening of the constellation.
     pub random_pipeline_closure_probability: Option<f32>,
 
     /// The seed for the RNG used to randomly close pipelines,
     /// used for testing the hardening of the constellation.
     pub random_pipeline_closure_seed: Option<usize>,
 
+    /// Dumps the DOM after restyle.
+    pub dump_style_tree: bool,
+
     /// Dumps the flow tree after a layout.
     pub dump_flow_tree: bool,
 
     /// Dumps the display list after a layout.
     pub dump_display_list: bool,
 
     /// Dumps the display list in JSON form after a layout.
     pub dump_display_list_json: bool,
@@ -226,16 +229,19 @@ pub struct DebugOptions {
     pub bubble_widths: bool,
 
     /// Disable antialiasing of rendered text.
     pub disable_text_aa: bool,
 
     /// Disable antialiasing of rendered text on the HTML canvas element.
     pub disable_canvas_aa: bool,
 
+    /// Print the DOM after each restyle.
+    pub dump_style_tree: bool,
+
     /// Print the flow tree after each layout.
     pub dump_flow_tree: bool,
 
     /// Print the display list after each layout.
     pub dump_display_list: bool,
 
     /// Print the display list in JSON form.
     pub dump_display_list_json: bool,
@@ -309,16 +315,17 @@ impl DebugOptions {
         let mut debug_options = DebugOptions::default();
 
         for option in debug_string.split(',') {
             match option {
                 "help" => debug_options.help = true,
                 "bubble-widths" => debug_options.bubble_widths = true,
                 "disable-text-aa" => debug_options.disable_text_aa = true,
                 "disable-canvas-aa" => debug_options.disable_text_aa = true,
+                "dump-style-tree" => debug_options.dump_style_tree = true,
                 "dump-flow-tree" => debug_options.dump_flow_tree = true,
                 "dump-display-list" => debug_options.dump_display_list = true,
                 "dump-display-list-json" => debug_options.dump_display_list_json = true,
                 "dump-layer-tree" => debug_options.dump_layer_tree = true,
                 "relayout-event" => debug_options.relayout_event = true,
                 "profile-script-events" => debug_options.profile_script_events = true,
                 "profile-heartbeats" => debug_options.profile_heartbeats = true,
                 "show-compositor-borders" => debug_options.show_compositor_borders = true,
@@ -352,16 +359,17 @@ pub fn print_debug_usage(app: &str) -> !
         println!("\t{:<35} {}", name, description);
     }
 
     println!("Usage: {} debug option,[options,...]\n\twhere options include\n\nOptions:", app);
 
     print_option("bubble-widths", "Bubble intrinsic widths separately like other engines.");
     print_option("disable-text-aa", "Disable antialiasing of rendered text.");
     print_option("disable-canvas-aa", "Disable antialiasing on the HTML canvas element.");
+    print_option("dump-style-tree", "Print the DOM with computed styles after each restyle.");
     print_option("dump-flow-tree", "Print the flow tree after each layout.");
     print_option("dump-display-list", "Print the display list after each layout.");
     print_option("dump-display-list-json", "Print the display list in JSON form.");
     print_option("dump-layer-tree", "Print the layer tree whenever it changes.");
     print_option("relayout-event", "Print notifications when there is a relayout.");
     print_option("profile-script-events", "Enable profiling of script-related events.");
     print_option("profile-heartbeats", "Enable heartbeats for all thread categories.");
     print_option("show-compositor-borders", "Paint borders along layer and tile boundaries.");
@@ -495,16 +503,17 @@ pub fn default_opts() -> Opts {
         devtools_port: None,
         webdriver_port: None,
         initial_window_size: TypedSize2D::new(1024, 740),
         user_agent: default_user_agent_string(DEFAULT_USER_AGENT),
         multiprocess: false,
         random_pipeline_closure_probability: None,
         random_pipeline_closure_seed: None,
         sandbox: false,
+        dump_style_tree: false,
         dump_flow_tree: false,
         dump_display_list: false,
         dump_display_list_json: false,
         dump_layer_tree: false,
         relayout_event: false,
         profile_script_events: false,
         profile_heartbeats: false,
         disable_share_style_cache: false,
@@ -802,16 +811,17 @@ pub fn from_cmdline_args(args: &[String]
         render_api: render_api,
         show_debug_borders: debug_options.show_compositor_borders,
         show_debug_fragment_borders: debug_options.show_fragment_borders,
         show_debug_parallel_paint: debug_options.show_parallel_paint,
         show_debug_parallel_layout: debug_options.show_parallel_layout,
         paint_flashing: debug_options.paint_flashing,
         enable_text_antialiasing: !debug_options.disable_text_aa,
         enable_canvas_antialiasing: !debug_options.disable_canvas_aa,
+        dump_style_tree: debug_options.dump_style_tree,
         dump_flow_tree: debug_options.dump_flow_tree,
         dump_display_list: debug_options.dump_display_list,
         dump_display_list_json: debug_options.dump_display_list_json,
         dump_layer_tree: debug_options.dump_layer_tree,
         relayout_event: debug_options.relayout_event,
         disable_share_style_cache: debug_options.disable_share_style_cache,
         convert_mouse_to_touch: debug_options.convert_mouse_to_touch,
         exit_after_load: opt_match.opt_present("x"),
--- a/servo/ports/geckolib/wrapper.rs
+++ b/servo/ports/geckolib/wrapper.rs
@@ -157,16 +157,20 @@ impl<'ln> TNode for GeckoNode<'ln> {
             Gecko_NodeIsElement(self.node)
         }
     }
 
     fn dump(self) {
         unimplemented!()
     }
 
+    fn dump_style(self) {
+        unimplemented!()
+    }
+
     fn opaque(&self) -> OpaqueNode {
         let ptr: uintptr_t = self.node as uintptr_t;
         OpaqueNode(ptr)
     }
 
     fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option<GeckoNode<'ln>> {
         if self.opaque() == reflow_root {
             None