servo: Merge #14124 - Flexbox trace (from shinglyu:flexbox-trace); r=glennw
authorShing Lyu <shing.lyu@gmail.com>
Wed, 28 Dec 2016 00:33:31 -0800
changeset 340433 46534af8c2a99c22b42221e4f133dbace63ba3e2
parent 340432 4af226cf8caa446a7a68b37484fab465d26f9f90
child 340434 77f675794490dd0d93991975510b385fab061b93
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)
reviewersglennw
servo: Merge #14124 - Flexbox trace (from shinglyu:flexbox-trace); r=glennw <!-- Please describe your changes on the following line: --> This is a follow up for #13740, so r? @jdm The first patch enables JSON serialization for flexbox flows, the second one fixed format incompatibilities for the layout viewer. The 3rd and 4th patches are just layout viewer UI enhancements, we could split that to a spearate PR if you prefer. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #13846 (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because it's a trivial debug tool <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 58fec2f05a21eb69899c8ec21e4b95000cfed2f2
servo/components/layout/flex.rs
servo/components/layout/flow_list.rs
servo/components/layout/model.rs
servo/components/style/logical_geometry.rs
servo/etc/layout_viewer/css/main.css
servo/etc/layout_viewer/viewer.html
--- a/servo/components/layout/flex.rs
+++ b/servo/components/layout/flex.rs
@@ -30,17 +30,17 @@ use style::context::SharedStyleContext;
 use style::logical_geometry::{Direction, LogicalSize};
 use style::properties::ServoComputedValues;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
 use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::computed::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone};
 
 /// The size of an axis. May be a specified size, a min/max
 /// constraint, or an unlimited size
-#[derive(Debug)]
+#[derive(Debug, Serialize)]
 enum AxisSize {
     Definite(Au),
     MinMax(SizeConstraint),
     Infinite,
 }
 
 impl AxisSize {
     /// Generate a new available cross or main axis size from the specified size of the container,
@@ -97,17 +97,17 @@ fn from_flex_basis(flex_basis: LengthOrP
                 MaybeAuto::Auto
             }
         }
     }
 }
 
 /// Represents a child in a flex container. Most fields here are used in
 /// flex size resolving, and items are sorted by the 'order' property.
-#[derive(Debug)]
+#[derive(Debug, Serialize)]
 struct FlexItem {
     /// Main size of a flex item, used to store results of flexible length calcuation.
     pub main_size: Au,
     /// Used flex base size.
     pub base_size: Au,
     /// The minimal size in main direction.
     pub min_size: Au,
     /// The maximal main size. If this property is not actually set by style
@@ -235,17 +235,17 @@ impl FlexItem {
             }
         }
         margin_count
     }
 }
 
 /// A line in a flex container.
 // TODO(stshine): More fields are required to handle collapsed items and baseline alignment.
-#[derive(Debug)]
+#[derive(Debug, Serialize)]
 struct FlexLine {
     /// Range of items belong to this line in 'self.items'.
     pub range: Range<usize>,
     /// Remaining free space of this line, items will grow or shrink based on it being positive or negative.
     pub free_space: Au,
     /// The number of auto margins of items.
     pub auto_margin_count: i32,
     /// Line size in the block direction.
@@ -325,17 +325,17 @@ impl FlexLine {
                 }
             }
             self.free_space -= total_variation;
         }
     }
 }
 
 /// A block with the CSS `display` property equal to `flex`.
-#[derive(Debug)]
+#[derive(Debug, Serialize)]
 pub struct FlexFlow {
     /// Data common to all block flows.
     block_flow: BlockFlow,
     /// The logical axis which the main axis will be parallel with.
     /// The cross axis will be parallel with the opposite logical axis.
     main_mode: Direction,
     /// The available main axis size
     available_main_size: AxisSize,
@@ -491,17 +491,17 @@ impl FlexFlow {
     // Currently, this is the core of BlockFlow::propagate_assigned_inline_size_to_children() with
     // all float and table logic stripped out.
     fn block_mode_assign_inline_sizes(&mut self,
                                       _shared_context: &SharedStyleContext,
                                       inline_start_content_edge: Au,
                                       inline_end_content_edge: Au,
                                       content_inline_size: Au) {
         let _scope = layout_debug_scope!("flex::block_mode_assign_inline_sizes");
-        debug!("block_mode_assign_inline_sizes");
+        debug!("flex::block_mode_assign_inline_sizes");
 
         // FIXME (mbrubeck): Get correct mode for absolute containing block
         let containing_block_mode = self.block_flow.base.writing_mode;
 
         let container_block_size = match self.available_main_size {
             AxisSize::Definite(length) => Some(length),
             _ => None
         };
--- a/servo/components/layout/flow_list.rs
+++ b/servo/components/layout/flow_list.rs
@@ -32,18 +32,19 @@ impl Serialize for FlowList {
                 .insert("data", match f.class() {
                     FlowClass::Block => to_value(f.as_block()),
                     FlowClass::Inline => to_value(f.as_inline()),
                     FlowClass::Table => to_value(f.as_table()),
                     FlowClass::TableWrapper => to_value(f.as_table_wrapper()),
                     FlowClass::TableRowGroup => to_value(f.as_table_rowgroup()),
                     FlowClass::TableRow => to_value(f.as_table_row()),
                     FlowClass::TableCell => to_value(f.as_table_cell()),
+                    FlowClass::Flex => to_value(f.as_flex()),
                     FlowClass::ListItem | FlowClass::TableColGroup | FlowClass::TableCaption |
-                    FlowClass::Multicol | FlowClass::MulticolColumn | FlowClass::Flex => {
+                    FlowClass::Multicol | FlowClass::MulticolColumn => {
                         Value::Null // Not implemented yet
                     }
                 })
                 .build();
 
             try!(serializer.serialize_seq_elt(&mut state, flow_val));
         }
         serializer.serialize_seq_end(state)
--- a/servo/components/layout/model.rs
+++ b/servo/components/layout/model.rs
@@ -518,17 +518,17 @@ impl ToGfxMatrix for ComputedMatrix {
             self.m41 as f32, self.m42 as f32, self.m43 as f32, self.m44 as f32)
     }
 }
 
 /// A min-size and max-size constraint. The constructor has a optional `border`
 /// parameter, and when it is present the constraint will be subtracted. This is
 /// used to adjust the constraint for `box-sizing: border-box`, and when you do so
 /// make sure the size you want to clamp is intended to be used for content box.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Serialize)]
 pub struct SizeConstraint {
     min_size: Au,
     max_size: Option<Au>,
 }
 
 impl SizeConstraint {
     /// Create a `SizeConstraint` for an axis.
     pub fn new(container_size: Option<Au>,
--- a/servo/components/style/logical_geometry.rs
+++ b/servo/components/style/logical_geometry.rs
@@ -210,16 +210,17 @@ impl Debug for DebugWritingMode {
     fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
         write!(formatter, "{}", self.mode)
     }
 }
 
 
 // Used to specify the logical direction.
 #[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "servo", derive(Serialize))]
 pub enum Direction {
     Inline,
     Block
 }
 
 /// A 2D size in flow-relative dimensions
 #[derive(PartialEq, Eq, Clone, Copy)]
 #[cfg_attr(feature = "servo", derive(Serialize))]
--- a/servo/etc/layout_viewer/css/main.css
+++ b/servo/etc/layout_viewer/css/main.css
@@ -10,8 +10,20 @@
 #trace-tree {
   max-height: 80vh;
   overflow-y: auto;
 }
 
 .hidden-glyphicon {
   visibility:hidden;
 }
+
+#toolbar {
+  background: rgba(255,255,255,0.5);
+  box-shadow: 0.5em 0.5em 2em lightgrey;
+  position: fixed;
+  top: 1em;
+  right: 1em;
+  padding: 1em;
+  border-radius: 1em;
+  font-weight: bold;
+  text-align: right;
+}
--- a/servo/etc/layout_viewer/viewer.html
+++ b/servo/etc/layout_viewer/viewer.html
@@ -62,57 +62,79 @@
                             </div>
                         </div>
                         <div class="col-sm-12">
                             <div id="flow-diffs"></div>
                         </div>
                     </div>
                 </div>
             </div>
+            <div id="toolbar">
+              <a href="#" id="prev_trace">< Prev step</a>
+              |
+              <a href="#" id="next_trace">Next step ></a>
+              <br>
+              <input type="checkbox" name="show_unchanged" id="show_unchanged" />
+              <label for="show_unchanged">Show unchanged code</label>
+              <br>
+              <a href="#top">Back to top</a>
+            </div>
         </div>
 
         <!-- jQuery -->
         <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
         <!-- Bootstrap -->
         <script src="js/bootstrap.min.js"></script>
         <!-- Treeview -->
         <script src="js/bootstrap-treeview.min.js"></script>
         <!-- JSDiffPatch -->
         <script src="js/bundle.min.js"></script>
         <script src="js/formatters.min.js"></script>
 
         <script>
+            function get_base(trace_node) {
+                if (typeof(trace_node.data.base) == "undefined" && typeof(trace_node.data.block_flow) != "undefined") {
+                  return trace_node.data.block_flow.base;
+                }
+                else {
+                  return trace_node.data.base;
+                }
+            }
+
             function create_flow_tree(trace_node) {
+                var base = get_base(trace_node);
+
                 var node = {
-                    text: trace_node.class + " (" + trace_node.data.base.id + ")",
-                    id: trace_node.data.base.id,
+                    text: trace_node.class + " (" + base.id + ")",
+                    id: base.id,
                     icon: "dummy",
-                    href: "#diff-" + trace_node.data.base.id
+                    href: "#diff-" + base.id
                 };
 
                 var children = [];
-                for (var i=0 ; i < trace_node.data.base.children.length ; ++i) {
-                    children.push(create_flow_tree(trace_node.data.base.children[i]));
+                for (var i=0 ; i < base.children.length ; ++i) {
+                    children.push(create_flow_tree(base.children[i]));
                 }
 
                 if (children.length > 0) {
                     node.nodes = children;
                 }
 
                 return node;
             }
 
             function create_flow_hash(trace_node, flow_hash) {
-                flow_hash[trace_node.data.base.id] = trace_node;
+                var base = get_base(trace_node);
+                flow_hash[base.id] = trace_node;
 
-                for (var i=0 ; i < trace_node.data.base.children.length ; ++i) {
-                    create_flow_hash(trace_node.data.base.children[i], flow_hash);
+                for (var i=0 ; i < base.children.length ; ++i) {
+                    create_flow_hash(base.children[i], flow_hash);
                 }
 
-                delete trace_node.data.base.children;
+                delete base.children;
             }
 
             function flatten_trace(trace_node) {
                 var flow_tree = create_flow_tree(trace_node.children[0]);
 
                 var flow_hash = {};
                 create_flow_hash(trace_node.children[0], flow_hash);
 
@@ -159,29 +181,34 @@
             function new_data_loaded(data) {
                 jsondiffpatch.formatters.html.hideUnchanged();
 
                 var node_color_hash = {};
                 var tree = [ create_tree_node(data) ];
                 $('#trace-tree').treeview({data: tree, levels: 3});
                 $('#trace-tree').on('nodeSelected', function(event, node) {
                     $("#flow-diffs").empty();
+                    $('#trace-tree').treeview(true).revealNode(node);
 
                     for (var key in node.pre) {
                         var flow_left = node.pre[key];
                         var flow_right = node.post[key];
 
                         var delta = jsondiffpatch.create({
                             objectHash: function(obj) {
                                 if (obj.data !== undefined && obj.data.base !== undefined) {
                                     return obj.data.base.id;
                                 }
                                 if (obj.id !== undefined) {
                                     return obj.id;
                                 }
+                                if (obj.index !== undefined) {
+                                    // FlexItem and FlexLine
+                                    return obj.index;
+                                }
                                 return JSON.stringify(obj);
                             }
                         }).diff(flow_left, flow_right);
 
                         if (delta !== undefined) {
                             var diff_id = "diff-" + key;
                             $("#flow-diffs").append(
                               "<div class='panel panel-default' id='" +
@@ -196,28 +223,54 @@
                         } else {
                             node_color_hash[key] = "rgb(212, 248, 212)";
                         }
                     }
 
                     update_flow_tree_bgcolor(node.flow_tree, node_color_hash);
                     $('#flow-tree').treeview({data: [node.flow_tree], levels: 100, enableLinks: true, emptyIcon: "glyphicon glyphicon-unchecked hidden-glyphicon"});
                 });
+
+                $('#trace-tree').treeview(true).selectNode(0);
+            }
+
+            function register_toggle_unchanaged_code_handler() {
+              var show_unchange_box = document.getElementById("show_unchanged");
+              show_unchange_box.addEventListener("change", function(evt){
+                  jsondiffpatch.formatters.html.showUnchanged(show_unchange_box.checked, null, 800);
+              });
+            }
+
+            function register_prev_next_trace_node() {
+              var prev_btn = document.getElementById("prev_trace");
+              var next_btn = document.getElementById("next_trace");
+              prev_btn.addEventListener("click", function(evt){
+                var node_id = $("#trace-tree").treeview(true).getSelected()[0].nodeId;
+                // We deliberatly choose to ignore the node_id out of bound case,
+                // since it won't break the UI usability
+                $("#trace-tree").treeview(true).selectNode(node_id - 1);
+              });
+              next_btn.addEventListener("click", function(evt){
+                var node_id = $("#trace-tree").treeview(true).getSelected()[0].nodeId;
+                $("#trace-tree").treeview(true).selectNode(node_id + 1);
+              });
             }
 
             $( document ).ready(function() {
                 var upload = document.getElementsByTagName('input')[0];
                 upload.onchange = function (e) {
                     e.preventDefault();
 
                     var file = upload.files[0],
                     reader = new FileReader();
                     reader.onload = function (event) {
                         new_data_loaded(JSON.parse(event.target.result));
                     };
 
                     reader.readAsText(file);
                     return false;
                 };
+                register_toggle_unchanaged_code_handler();
+                register_prev_next_trace_node();
             });
         </script>
     </body>
 </html>