Bug 1443849 - Part 2: Don't touch gBrowser before gBrowserInit. r=Gijs draft
authorDão Gottwald <dao@mozilla.com>
Tue, 13 Mar 2018 15:21:22 +0100
changeset 766891 50efff0e595e9aefcde76a126d5680609d94996a
parent 766890 2e89a40550cef5864b316fc46e717b3bbb267f97
child 766892 9b88797f191dbefa4e52749c28e326e341ca833c
push id102434
push userdgottwald@mozilla.com
push dateTue, 13 Mar 2018 15:21:11 +0000
reviewersGijs
bugs1443849
milestone61.0a1
Bug 1443849 - Part 2: Don't touch gBrowser before gBrowserInit. r=Gijs MozReview-Commit-ID: 5p0FoxNYGJh
browser/base/content/tabbrowser.xml
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -299,23 +299,33 @@
       </method>
 
       <property name="_isCustomizing" readonly="true">
         <getter><![CDATA[
           return document.documentElement.getAttribute("customizing") == "true";
         ]]></getter>
       </property>
 
+      <method name="_getVisibleTabs">
+        <body><![CDATA[
+          // Cannot access gBrowser before it's initialized.
+          if (!gBrowser) {
+            return [ this.firstChild ];
+          }
+
+          return gBrowser.visibleTabs;
+        ]]></body>
+      </method>
+
       <method name="_setPositionalAttributes">
         <body><![CDATA[
-          let visibleTabs = this.tabbrowser.visibleTabs;
-
-          if (!visibleTabs.length)
+          let visibleTabs = this._getVisibleTabs();
+          if (!visibleTabs.length) {
             return;
-
+          }
           let selectedIndex = visibleTabs.indexOf(this.selectedItem);
 
           if (this._beforeSelectedTab) {
             this._beforeSelectedTab.removeAttribute("beforeselected-visible");
           }
 
           if (this.selectedItem.closing || selectedIndex == 0) {
             this._beforeSelectedTab = null;
@@ -432,17 +442,17 @@
               // Check if tab widths are below the threshold where we want to
               // remove close buttons from background tabs so that people don't
               // accidentally close tabs by selecting them.
               let rect = ele => {
                 return window.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIDOMWindowUtils)
                              .getBoundsWithoutFlushing(ele);
               };
-              let tab = this.tabbrowser.visibleTabs[this.tabbrowser._numPinnedTabs];
+              let tab = this._getVisibleTabs()[gBrowser._numPinnedTabs];
               if (tab && rect(tab).width <= this._tabClipWidth) {
                 this.setAttribute("closebuttons", "activetab");
               } else {
                 this.removeAttribute("closebuttons");
               }
             });
           });
         ]]></body>
@@ -465,19 +475,20 @@
       <field name="_tabDefaultMaxWidth">NaN</field>
       <field name="_lastTabClosedByMouse">false</field>
       <field name="_hasTabTempMaxWidth">false</field>
 
       <!-- Try to keep the active tab's close button under the mouse cursor -->
       <method name="_lockTabSizing">
         <parameter name="aTab"/>
         <body><![CDATA[
-          var tabs = this.tabbrowser.visibleTabs;
-          if (!tabs.length)
+          let tabs = this._getVisibleTabs();
+          if (!tabs.length) {
             return;
+          }
 
           var isEndTab = (aTab._tPos > tabs[tabs.length - 1]._tPos);
           var tabWidth = aTab.getBoundingClientRect().width;
 
           if (!this._tabDefaultMaxWidth)
             this._tabDefaultMaxWidth =
               parseFloat(window.getComputedStyle(aTab).maxWidth);
           this._lastTabClosedByMouse = true;
@@ -540,19 +551,20 @@
 
       <method name="_unlockTabSizing">
         <body><![CDATA[
           this.tabbrowser.removeEventListener("mousemove", this);
           window.removeEventListener("mouseout", this);
 
           if (this._hasTabTempMaxWidth) {
             this._hasTabTempMaxWidth = false;
-            let tabs = this.tabbrowser.visibleTabs;
-            for (let i = 0; i < tabs.length; i++)
+            let tabs = this._getVisibleTabs();
+            for (let i = 0; i < tabs.length; i++) {
               tabs[i].style.maxWidth = "";
+            }
           }
 
           if (this.hasAttribute("using-closing-tabs-spacer")) {
             this.removeAttribute("using-closing-tabs-spacer");
             this._closingTabsSpacer.style.width = 0;
           }
         ]]></body>
       </method>
@@ -564,19 +576,19 @@
           this._handleTabSelect(true);
         ]]></body>
       </method>
 
       <field name="_lastNumPinned">0</field>
       <field name="_pinnedTabsLayoutCache">null</field>
       <method name="_positionPinnedTabs">
         <body><![CDATA[
-          var numPinned = this.tabbrowser._numPinnedTabs;
-          var doPosition = this.getAttribute("overflow") == "true" &&
-                           this.tabbrowser.visibleTabs.length > numPinned &&
+          let numPinned = gBrowser._numPinnedTabs;
+          let doPosition = this.getAttribute("overflow") == "true" &&
+                           this._getVisibleTabs().length > numPinned &&
                            numPinned > 0;
 
           if (doPosition) {
             this.setAttribute("positionpinnedtabs", "true");
 
             let layoutData = this._pinnedTabsLayoutCache;
             let uiDensity = document.documentElement.getAttribute("uidensity");
             if (!layoutData ||
@@ -633,33 +645,35 @@
           let screenX = event.screenX;
           if (screenX == draggedTab._dragData.animLastScreenX)
             return;
 
           draggedTab._dragData.animLastScreenX = screenX;
 
           let rtl = (window.getComputedStyle(this).direction == "rtl");
           let pinned = draggedTab.pinned;
-          let numPinned = this.tabbrowser._numPinnedTabs;
-          let tabs = this.tabbrowser.visibleTabs
-                                    .slice(pinned ? 0 : numPinned,
-                                           pinned ? numPinned : undefined);
-          if (rtl)
+          let numPinned = gBrowser._numPinnedTabs;
+          let tabs = this._getVisibleTabs()
+                         .slice(pinned ? 0 : numPinned,
+                                pinned ? numPinned : undefined);
+          if (rtl) {
             tabs.reverse();
+          }
           let tabWidth = draggedTab.getBoundingClientRect().width;
           draggedTab._dragData.tabWidth = tabWidth;
 
           // Move the dragged tab based on the mouse position.
 
           let leftTab = tabs[0];
           let rightTab = tabs[tabs.length - 1];
           let tabScreenX = draggedTab.boxObject.screenX;
           let translateX = screenX - draggedTab._dragData.screenX;
-          if (!pinned)
+          if (!pinned) {
             translateX += this.arrowScrollbox._scrollbox.scrollLeft - draggedTab._dragData.scrollX;
+          }
           let leftBound = leftTab.boxObject.screenX - tabScreenX;
           let rightBound = (rightTab.boxObject.screenX + rightTab.boxObject.width) -
                            (tabScreenX + tabWidth);
           translateX = Math.max(translateX, leftBound);
           translateX = Math.min(translateX, rightBound);
           draggedTab.style.transform = "translateX(" + translateX + "px)";
           draggedTab._dragData.translateX = translateX;
 
@@ -715,21 +729,23 @@
               return rtl ? tabWidth : -tabWidth;
             return 0;
           }
         ]]></body>
       </method>
 
       <method name="_finishAnimateTabMove">
         <body><![CDATA[
-          if (this.getAttribute("movingtab") != "true")
+          if (this.getAttribute("movingtab") != "true") {
             return;
+          }
 
-          for (let tab of this.tabbrowser.visibleTabs)
+          for (let tab of this._getVisibleTabs()) {
             tab.style.transform = "";
+          }
 
           this.removeAttribute("movingtab");
           this.parentNode.removeAttribute("movingtab");
 
           this._handleTabSelect();
         ]]></body>
       </method>
 
@@ -916,22 +932,29 @@
         ]]>
         </body>
       </method>
 
       <method name="getRelatedElement">
         <parameter name="aTab"/>
         <body>
         <![CDATA[
-          if (!aTab)
+          if (!aTab) {
             return null;
+          }
+
+          // Cannot access gBrowser before it's initialized.
+          if (!gBrowser) {
+            return this.tabbox.tabpanels.firstChild;
+          }
+
           // If the tab's browser is lazy, we need to `_insertBrowser` in order
           // to have a linkedPanel.  This will also serve to bind the browser
           // and make it ready to use when the tab is selected.
-          this.tabbrowser._insertBrowser(aTab);
+          gBrowser._insertBrowser(aTab);
           return document.getElementById(aTab.linkedPanel);
         ]]>
         </body>
       </method>
 
       <method name="_updateNewTabVisibility">
         <body><![CDATA[
           // Helper functions to help deal with customize mode wrapping some items
@@ -1085,17 +1108,17 @@
           // The user middleclicked an open space on the tabstrip. This could
           // be because they intend to open a new tab, but it could also be
           // because they just removed a tab and they now middleclicked on the
           // resulting space while that tab is closing. In that case, we don't
           // want to open a tab. So if we're removing one or more tabs, and
           // the tab click is before the end of the last visible tab, we do
           // nothing.
           if (this.tabbrowser._removingTabs.length) {
-            let visibleTabs = this.tabbrowser.visibleTabs;
+            let visibleTabs = this._getVisibleTabs();
             let ltr = (window.getComputedStyle(this).direction == "ltr");
             let lastTab = visibleTabs[visibleTabs.length - 1];
             let endOfTab = lastTab.getBoundingClientRect()[ltr ? "right" : "left"];
             if ((ltr && event.clientX > endOfTab) ||
                 (!ltr && event.clientX < endOfTab)) {
               BrowserOpenTab();
             }
           } else {
@@ -1740,21 +1763,22 @@
       While it would make sense to track this in a field, the field will get nuked
       once the node is gone from the DOM, which causes us to think the tab is not
       closed, which causes us to make wrong decisions. So we use an expando instead.
       <field name="closing">false</field>
       -->
 
       <method name="_mouseenter">
         <body><![CDATA[
-          if (this.hidden || this.closing)
+          if (this.hidden || this.closing) {
             return;
+          }
 
           let tabContainer = this.parentNode;
-          let visibleTabs = tabContainer.tabbrowser.visibleTabs;
+          let visibleTabs = tabContainer._getVisibleTabs();
           let tabIndex = visibleTabs.indexOf(this);
 
           if (this.selected)
             tabContainer._handleTabSelect();
 
           if (tabIndex == 0) {
             tabContainer._beforeHoveredTab = null;
           } else {