Bug 757299 (part 9) - Build tree lines in a better way in aboutMemory.js. r=jlebar.
authorNicholas Nethercote <nnethercote@mozilla.com>
Sun, 27 May 2012 18:22:25 -0700
changeset 99158 a9a778e471d1f9706de4bd9b149d2acfb1b91d4c
parent 99157 cd59583cf7d4fc9c20662181659026398c3c3818
child 99159 5859f7d3fb2595b10e47353a96560c442691f488
push idunknown
push userunknown
push dateunknown
reviewersjlebar
bugs757299
milestone15.0a1
Bug 757299 (part 9) - Build tree lines in a better way in aboutMemory.js. r=jlebar.
toolkit/components/aboutmemory/content/aboutMemory.css
toolkit/components/aboutmemory/content/aboutMemory.js
--- a/toolkit/components/aboutmemory/content/aboutMemory.css
+++ b/toolkit/components/aboutmemory/content/aboutMemory.css
@@ -18,17 +18,17 @@ h2 {
   background: #ddd;
   padding-left: .1em;
 }
 
 .accuracyWarning {
   color: #f00;
 }
 
-.treeLine {
+.treeline {
   color: #888;
 }
 
 .mrValue {
   font-weight: bold;
   color: #400;
 }
 
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -1033,28 +1033,31 @@ function pad(aS, aN, aC)
   let padding = "";
   let n2 = aN - aS.length;
   for (let i = 0; i < n2; i++) {
     padding += aC;
   }
   return padding + aS;
 }
 
-// There's a subset of the Unicode "light" box-drawing chars that are widely
+// There's a subset of the Unicode "light" box-drawing chars that is widely
 // implemented in terminals, and this code sticks to that subset to maximize
 // the chance that cutting and pasting about:memory output to a terminal will
-// work correctly:
-const kHorizontal       = "\u2500",
-      kVertical         = "\u2502",
-      kUpAndRight       = "\u2514",
-      kVerticalAndRight = "\u251c",
-      kNoKidsSep        = " \u2500\u2500 ",
-      kHideKidsSep      = " ++ ",
-      kShowKidsSep      = " -- ";
+// work correctly.
+const kHorizontal                   = "\u2500",
+      kVertical                     = "\u2502",
+      kUpAndRight                   = "\u2514",
+      kUpAndRight_Right_Right       = "\u2514\u2500\u2500",
+      kVerticalAndRight             = "\u251c",
+      kVerticalAndRight_Right_Right = "\u251c\u2500\u2500",
+      kVertical_Space_Space         = "\u2502  ";
 
+const kNoKidsSep                    = " \u2500\u2500 ",
+      kHideKidsSep                  = " ++ ",
+      kShowKidsSep                  = " -- ";
 
 function appendMrValueSpan(aP, aValue, aIsInvalid)
 {
   appendElementWithText(aP, "span", "mrValue" + (aIsInvalid ? " invalid" : ""),
                         aValue);
 }
 
 function kindToString(aKind)
@@ -1190,52 +1193,50 @@ function appendTreeElements(aPOuter, aT,
    * Appends the elements for a particular tree, without a heading.
    *
    * @param aP
    *        The parent DOM node.
    * @param aUnsafeNames
    *        An array of the names forming the path to aT.
    * @param aT
    *        The tree.
-   * @param aBaseIndentText
-   *        The base text of the indent, which may be augmented within the
-   *        function.
-   * @param aIndentGuide
-   *        Records what indentation is required for this tree.  It has one
-   *        entry per level of indentation.  For each entry, ._isLastKid
-   *        records whether the node in question is the last child, and
-   *        ._depth records how many chars of indentation are required.
+   * @param aTreelineText1
+   *        The first part of the treeline for this entry and this entry's
+   *        children.
+   * @param aTreelineText2a
+   *        The second part of the treeline for this entry.
+   * @param aTreelineText2b
+   *        The second part of the treeline for this entry's children.
    * @param aParentStringLength
    *        The length of the formatted byte count of the top node in the tree.
    */
-  function appendTreeElements2(aP, aUnsafeNames, aT, aIndentGuide,
-                               aBaseIndentText, aParentStringLength)
+  function appendTreeElements2(aP, aUnsafeNames, aT, aTreelineText1,
+                               aTreelineText2a, aTreelineText2b,
+                               aParentStringLength)
   {
-    function repeatStr(aA, aC, aN)
+    function appendN(aS, aC, aN)
     {
       for (let i = 0; i < aN; i++) {
-        aA.push(aC);
+        aS += aC;
       }
+      return aS;
     }
 
-    // Indent more if this entry is narrower than its parent, and update
-    // aIndentGuide accordingly.
-    let tString = aT.toString();
-    let extraIndentLength = Math.max(aParentStringLength - tString.length, 0);
-    let indentText;
-    if (extraIndentLength > 0) {
-      let extraIndentArray = [];
-      repeatStr(extraIndentArray, kHorizontal, extraIndentLength);
-      aIndentGuide[aIndentGuide.length - 1]._depth += extraIndentLength;
-      indentText = aBaseIndentText + extraIndentArray.join("");
+    // Indent more if this entry is narrower than its parent.
+    let valueText = aT.toString();
+    let extraTreelineLength =
+      Math.max(aParentStringLength - valueText.length, 0);
+    if (extraTreelineLength > 0) {
+      aTreelineText2a =
+        appendN(aTreelineText2a, kHorizontal, extraTreelineLength);
+      aTreelineText2b =
+        appendN(aTreelineText2b, " ",         extraTreelineLength);
     }
-    else {
-      indentText = aBaseIndentText;
-    }
-    appendElementWithText(aP, "span", "treeLine", indentText);
+    let treelineText = aTreelineText1 + aTreelineText2a;
+    appendElementWithText(aP, "span", "treeline", treelineText);
 
     // Generate the percentage;  detect and record invalid values at the same
     // time.
     let percText;
     let tIsInvalid = false;
     if (aT._amount === treeBytes) {
       percText = " (100.0%)";
     } else {
@@ -1270,64 +1271,56 @@ function appendTreeElements(aPOuter, aT,
       d.onclick = toggle;
       sep = showSubtrees ? kShowKidsSep : kHideKidsSep;
     } else {
       assert(!aT._hideKids, "leaf node with _hideKids set")
       sep = kNoKidsSep;
       d = aP;
     }
 
-    appendMrValueSpan(d, tString, tIsInvalid);
+    appendMrValueSpan(d, valueText, tIsInvalid);
     appendElementWithText(d, "span", "mrPerc", percText);
     appendElementWithText(d, "span", "mrSep", sep);
 
     appendMrNameSpan(d, aT._description, aT._unsafeName,
                      tIsInvalid, aT._nMerged);
 
     // In non-verbose mode, invalid nodes can be hidden in collapsed sub-trees.
     // But it's good to always see them, so force this.
     if (!gVerbose && tIsInvalid) {
       expandPathToThisElement(d);
     }
 
     if (aT._kids) {
       // The 'kids' class is just used for sanity checking in toggle().
       d = appendElement(aP, "span", showSubtrees ? "kids" : "kids hidden");
 
+      let kidTreelineText1 = aTreelineText1 + aTreelineText2b;
       for (let i = 0; i < aT._kids.length; i++) {
-        // 3 is the standard depth, the callee adjusts it if necessary.
-        aIndentGuide.push({ _isLastKid: (i === aT._kids.length - 1), _depth: 3 });
-
-        // Generate the base indent.
-        let baseIndentArray = [];
-        if (aIndentGuide.length > 0) {
-          let j;
-          for (j = 0; j < aIndentGuide.length - 1; j++) {
-            baseIndentArray.push(aIndentGuide[j]._isLastKid ? " " : kVertical);
-            repeatStr(baseIndentArray, " ", aIndentGuide[j]._depth - 1);
-          }
-          baseIndentArray.push(aIndentGuide[j]._isLastKid ?
-                               kUpAndRight : kVerticalAndRight);
-          repeatStr(baseIndentArray, kHorizontal, aIndentGuide[j]._depth - 1);
+        let kidTreelineText2a, kidTreelineText2b;
+        if (i < aT._kids.length - 1) {
+          kidTreelineText2a = kVerticalAndRight_Right_Right;
+          kidTreelineText2b = kVertical_Space_Space;
+        } else {
+          kidTreelineText2a = kUpAndRight_Right_Right;
+          kidTreelineText2b = "   ";
         }
-
-        let baseIndentText = baseIndentArray.join("");
         aUnsafeNames.push(aT._kids[i]._unsafeName);
-        appendTreeElements2(d, aUnsafeNames, aT._kids[i], aIndentGuide,
-                            baseIndentText, tString.length);
+        appendTreeElements2(d, aUnsafeNames, aT._kids[i], kidTreelineText1,
+                            kidTreelineText2a, kidTreelineText2b,
+                            valueText.length);
         aUnsafeNames.pop();
-        aIndentGuide.pop();
       }
     }
   }
 
   appendSectionHeader(aPOuter, kSectionNames[aT._unsafeName]);
  
   let pre = appendElement(aPOuter, "pre", "entries");
-  appendTreeElements2(pre, [aT._unsafeName], aT, [], "", rootStringLength);
+  appendTreeElements2(pre, [aT._unsafeName], aT, "", "", "", rootStringLength);
   appendTextNode(aPOuter, "\n");  // gives nice spacing when we cut and paste
 }
 
 //---------------------------------------------------------------------------
 
 function OtherReport(aUnsafePath, aUnits, aAmount, aDescription, aNMerged)
 {
   this._unsafePath = aUnsafePath;