Bug 602777 - Quit pretending in Items.arrange [r=dolske, a=blocking2.0=betaN+]
authorMichael Yoshitaka Erlewine <mitcho@mitcho.com>
Sat, 06 Nov 2010 20:08:57 -0400
changeset 57166 f11c25226916df9762722c11eba2f3a2ee33f905
parent 57165 09d926c185f6909f070e54f8804fafaed5f2df90
child 57167 7f16577a2671283abd0ed334111c7716ce1cf11d
push id16826
push userian@iangilman.com
push dateTue, 09 Nov 2010 21:09:56 +0000
treeherdermozilla-central@f11c25226916 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdolske, blocking2.0
bugs602777
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 602777 - Quit pretending in Items.arrange [r=dolske, a=blocking2.0=betaN+]
browser/base/content/tabview/groupitems.js
browser/base/content/tabview/items.js
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -1015,74 +1015,72 @@ GroupItem.prototype = Utils.extend(new I
           opacity: .2,
           top: childBB.top + childBB.height - parentBB.top + padding,
           left: parentBB.width/2 - this.$expander.width()/2
         });
   },
 
   // ----------
   // Function: shouldStack
-  // Returns true if the groupItem, given "count", should stack (instead of grid).
+  // Returns true if the groupItem should stack (instead of grid).
   shouldStack: function GroupItem_shouldStack(count) {
     if (count <= 1)
       return false;
 
     var bb = this.getContentBounds();
     var options = {
-      pretend: true,
-      count: count
+      return: 'widthAndColumns',
+      count: count || this._children.length
     };
+    let {childWidth, columns} = Items.arrange(null, bb, options);
 
-    var rects = Items.arrange(null, bb, options);
-    return (rects[0].width < 55);
+    let shouldStack = childWidth < TabItems.minTabWidth * 1.35;
+    this._columns = shouldStack ? null : columns;
+
+    return shouldStack;
   },
 
   // ----------
   // Function: arrange
   // Lays out all of the children.
   //
   // Parameters:
   //   options - passed to <Items.arrange> or <_stackArrange>
   arrange: function GroupItem_arrange(options) {
     if (this.expanded) {
       this.topChild = null;
       var box = new Rect(this.expanded.bounds);
       box.inset(8, 8);
       Items.arrange(this._children, box, Utils.extend({}, options, {z: 99999}));
     } else {
       var bb = this.getContentBounds();
-      var count = this._children.length;
-      if (!this.shouldStack(count)) {
+      if (!this.shouldStack()) {
         if (!options)
           options = {};
 
-        var animate;
-        if (typeof options.animate == 'undefined')
-          animate = true;
-        else
-          animate = options.animate;
-
         this._children.forEach(function(child) {
             child.removeClass("stacked")
         });
 
         this.topChild = null;
 
-        var arrangeOptions = Utils.copy(options);
-        Utils.extend(arrangeOptions, {
-          pretend: true,
-          count: count
-        });
-
-        if (!count) {
+        if (!this._children.length) {
           this.xDensity = 0;
           this.yDensity = 0;
           return;
         }
 
+        var arrangeOptions = Utils.copy(options);
+        Utils.extend(arrangeOptions, {
+          columns: this._columns
+        });
+
+        // Items.arrange will rearrange the children, but also return an array
+        // of the Rect's used.
+
         var rects = Items.arrange(this._children, bb, arrangeOptions);
 
         // yDensity = (the distance of the bottom of the last tab to the top of the content area)
         // / (the total available content height)
         this.yDensity = (rects[rects.length - 1].bottom - bb.top) / (bb.height);
 
         // xDensity = (the distance from the left of the content area to the right of the rightmost
         // tab) / (the total available content width)
@@ -1093,25 +1091,16 @@ GroupItem.prototype = Utils.extend(new I
         for each (var rect in rects) {
           if (rect.right > rightMostRight)
             rightMostRight = rect.right;
           else
             break;
         }
         this.xDensity = (rightMostRight - bb.left) / (bb.width);
 
-        this._children.forEach(function(child, index) {
-          if (!child.locked.bounds) {
-            child.setBounds(rects[index], !animate);
-            child.setRotation(0);
-            if (options.z)
-              child.setZ(options.z);
-          }
-        });
-
         this._isStacked = false;
       } else
         this._stackArrange(bb, options);
     }
 
     if (this._isStacked && !this.expanded) this.showExpandControl();
     else this.hideExpandControl();
   },
--- a/browser/base/content/tabview/items.js
+++ b/browser/base/content/tabview/items.js
@@ -596,17 +596,17 @@ Item.prototype = {
       var startSent;
       var startEvent;
       var droppables;
       var dropTarget;
 
       // ___ mousemove
       var handleMouseMove = function(e) {
         // positioning
-        var mouse = new Point(e.pageX, e.pageY);		
+        var mouse = new Point(e.pageX, e.pageY);
         if (!startSent) {
           if(Math.abs(mouse.x - startMouse.x) > self.dragOptions.minDragDistance ||
              Math.abs(mouse.y - startMouse.y) > self.dragOptions.minDragDistance) {
             if (typeof self.dragOptions.start == "function")
               self.dragOptions.start.apply(self,
                   [startEvent, {position: {left: startPos.x, top: startPos.y}}]);
             startSent = true;
           }
@@ -887,49 +887,51 @@ let Items = {
   },
 
   // ----------
   // Function: arrange
   // Arranges the given items in a grid within the given bounds,
   // maximizing item size but maintaining standard tab aspect ratio for each
   //
   // Parameters:
-  //   items - an array of <Item>s. Can be null if the pretend and count options are set.
+  //   items - an array of <Item>s. Can be null, in which case we won't
+  //     actually move anything.
   //   bounds - a <Rect> defining the space to arrange within
   //   options - an object with various properites (see below)
   //
   // Possible "options" properties:
   //   animate - whether to animate; default: true.
   //   z - the z index to set all the items; default: don't change z.
-  //   pretend - whether to collect and return the rectangle rather than moving the items; default: false
-  //   count - overrides the item count for layout purposes; default: the actual item count
+  //   return - if set to 'widthAndColumns', it'll return an object with the
+  //     width of children and the columns.
+  //   count - overrides the item count for layout purposes;
+  //     default: the actual item count
   //   padding - pixels between each item
+  //   columns - (int) a preset number of columns to use
   //
   // Returns:
-  //   the list of rectangles if the pretend option is set; otherwise null
+  //   an object with the width value of the child items and the number of columns, 
+  //   if the return option is set to 'widthAndColumns'; otherwise the list of <Rect>s
   arrange: function Items_arrange(items, bounds, options) {
-    var animate;
-    if (!options || typeof options.animate == 'undefined')
-      animate = true;
-    else
-      animate = options.animate;
-
     if (typeof options == 'undefined')
       options = {};
 
-    var rects = null;
-    if (options.pretend)
-      rects = [];
+    var animate = true;
+    if (typeof options.animate != 'undefined')
+      animate = options.animate;
+    var immediately = !animate;
+
+    var rects = [];
 
     var tabAspect = TabItems.tabHeight / TabItems.tabWidth;
     var count = options.count || (items ? items.length : 0);
     if (!count)
       return rects;
 
-    var columns = 1;
+    var columns = options.columns || 1;
     // We'll assume for the time being that all the items have the same styling
     // and that the margin is the same width around.
     var itemMargin = items && items.length ?
                        parseInt(iQ(items[0].container).css('margin-left')) : 0;
     var padding = itemMargin * 2;
     var yScale = 1.1; // to allow for titles
     var rows;
     var tabWidth;
@@ -949,45 +951,41 @@ let Items = {
       columns++;
       figure();
     }
 
     if (rows == 1) {
       tabWidth = Math.min(tabWidth, (bounds.height - 2 * itemMargin) / tabAspect);
       tabHeight = tabWidth * tabAspect;
     }
+    
+    if (options.return == 'widthAndColumns')
+      return {childWidth: tabWidth, columns: columns};
 
     var box = new Rect(bounds.left, bounds.top, tabWidth, tabHeight);
-    var row = 0;
     var column = 0;
-    var immediately;
 
-    var a;
-    for (a = 0; a < count; a++) {
-      immediately = !animate;
-
-      if (rects)
-        rects.push(new Rect(box));
-      else if (items && a < items.length) {
-        var item = items[a];
+    for (let a = 0; a < count; a++) {
+      rects.push(new Rect(box));
+      if (items && a < items.length) {
+        let item = items[a];
         if (!item.locked.bounds) {
           item.setBounds(box, immediately);
           item.setRotation(0);
           if (options.z)
             item.setZ(options.z);
         }
       }
 
       box.left += box.width + padding;
       column++;
       if (column == columns) {
         box.left = bounds.left;
         box.top += (box.height * yScale) + padding;
         column = 0;
-        row++;
       }
     }
 
     return rects;
   },
 
   // ----------
   // Function: unsquish