Bug 658467 - Fade out tab label on overflow instead of ellipsis. r=jaws ui-r=shorlander
authorDão Gottwald <dao@mozilla.com>
Thu, 08 Dec 2016 17:17:41 +0100
changeset 370398 6fddc51e9d1530484e7875ea6b67141497db784d
parent 370397 a3945af43157bf892bb9415086406774cb380a56
child 370399 dffe4787171445ea01f99a41514d262f7882d120
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws, shorlander
bugs658467
milestone53.0a1
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 658467 - Fade out tab label on overflow instead of ellipsis. r=jaws ui-r=shorlander
accessible/tests/mochitest/tree/test_tabbrowser.xul
browser/base/content/tabbrowser.css
browser/base/content/tabbrowser.xml
browser/base/content/test/general/browser_overflowScroll.js
browser/themes/osx/browser.css
browser/themes/shared/tabs.inc.css
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -103,27 +103,37 @@
           // NB: The (3) buttons are not visible, unless manually hovered,
           //     probably due to size reduction in this test.
           tabsAccTree.children.splice(0, 0,
             {
               // xul:tab ("about:")
               role: ROLE_PAGETAB,
               children: [
                 {
+                  // xul:text, i.e. the tab label text
+                  role: ROLE_TEXT_LEAF,
+                  children: []
+                },
+                {
                   // xul:toolbarbutton ("Close Tab")
                   role: ROLE_PUSHBUTTON,
                   children: []
                 }
               ]
             },
             {
               // tab ("about:mozilla")
               role: ROLE_PAGETAB,
               children: [
                 {
+                  // xul:text, i.e. the tab label text
+                  role: ROLE_TEXT_LEAF,
+                  children: []
+                },
+                {
                   // xul:toolbarbutton ("Close Tab")
                   role: ROLE_PUSHBUTTON,
                   children: []
                 }
               ]
             },
             {
               // xul:toolbarbutton ("Open a new tab")
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -34,22 +34,34 @@
 .tab-sharing-icon-overlay[sharing]:not([selected]),
 .tab-icon-overlay[soundplaying][pinned],
 .tab-icon-overlay[muted][pinned],
 .tab-icon-overlay[blocked][pinned],
 .tab-icon-overlay[crashed] {
   display: -moz-box;
 }
 
-.tab-label[pinned] {
+.tab-label {
+  white-space: nowrap;
+}
+
+.tab-label-container {
+  overflow: hidden;
+}
+
+.tab-label-container[pinned] {
   width: 0;
-  margin-left: 0 !important;
-  margin-right: 0 !important;
-  padding-left: 0 !important;
-  padding-right: 0 !important;
+}
+
+.tab-label-container[textoverflow]:not([pinned]) {
+  mask-image: linear-gradient(to left, transparent, black 1em);
+}
+
+.tab-label-container[textoverflow]:not([pinned]):-moz-locale-dir(rtl) {
+  mask-image: linear-gradient(to right, transparent, black 1em);
 }
 
 .tab-stack {
   vertical-align: top; /* for pinned tabs */
 }
 
 tabpanels {
   background-color: transparent;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1433,28 +1433,26 @@
       </method>
 
 
       <method name="setTabTitleLoading">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             aTab.label = this.mStringBundle.getString("tabs.connecting");
-            aTab.crop = "end";
-            this._tabAttrModified(aTab, ["label", "crop"]);
+            this._tabAttrModified(aTab, ["label"]);
           ]]>
         </body>
       </method>
 
       <method name="setTabTitle">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             var browser = this.getBrowserForTab(aTab);
-            var crop = "end";
             var title = browser.contentTitle;
 
             if (!title) {
               if (browser.currentURI.spec) {
                 try {
                   title = this.mURIFixup.createExposableURI(browser.currentURI).spec;
                 } catch (ex) {
                   title = browser.currentURI.spec;
@@ -1466,35 +1464,30 @@
                 // Let's try to unescape it using a character set
                 // in case the URI is not ASCII.
                 try {
                   var characterSet = browser.characterSet;
                   const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
                                                  .getService(Components.interfaces.nsITextToSubURI);
                   title = textToSubURI.unEscapeNonAsciiURI(characterSet, title);
                 } catch (ex) { /* Do nothing. */ }
-
-                crop = "center";
-
               } else if (aTab.hasAttribute("customizemode")) {
                 let brandBundle = document.getElementById("bundle_brand");
                 let brandShortName = brandBundle.getString("brandShortName");
                 title = gNavigatorBundle.getFormattedString("customizeMode.tabTitle",
                                                             [ brandShortName ]);
               } else // Still no title?  Fall back to our untitled string.
                 title = this.mStringBundle.getString("tabs.emptyTabTitle");
             }
 
-            if (aTab.label == title &&
-                aTab.crop == crop)
+            if (aTab.label == title)
               return false;
 
             aTab.label = title;
-            aTab.crop = crop;
-            this._tabAttrModified(aTab, ["label", "crop"]);
+            this._tabAttrModified(aTab, ["label"]);
 
             if (aTab.selected)
               this.updateTitlebar();
 
             return true;
           ]]>
         </body>
       </method>
@@ -2192,17 +2185,16 @@
               t.setAttribute("label", aURI);
             }
 
             if (aUserContextId) {
               t.setAttribute("usercontextid", aUserContextId);
               ContextualIdentityService.setTabStyle(t);
             }
 
-            t.setAttribute("crop", "end");
             t.setAttribute("onerror", "this.removeAttribute('image');");
             t.className = "tabbrowser-tab";
 
             this.tabContainer._unlockTabSizing();
 
             // When overflowing, new tabs are scrolled into view smoothly, which
             // doesn't go well together with the width transition. So we skip the
             // transition in that case.
@@ -5282,31 +5274,37 @@
           }
           return [tabStart, tabEnd];
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="underflow" phase="capturing"><![CDATA[
+        if (event.target != this)
+          return;
+
         if (event.detail == 0)
           return; // Ignore vertical events
 
         var tabs = document.getBindingParent(this);
         tabs.removeAttribute("overflow");
 
         if (tabs._lastTabClosedByMouse)
           tabs._expandSpacerBy(this._scrollButtonDown.clientWidth);
 
         for (let tab of Array.from(tabs.tabbrowser._removingTabs))
           tabs.tabbrowser.removeTab(tab);
 
         tabs._positionPinnedTabs();
       ]]></handler>
       <handler event="overflow"><![CDATA[
+        if (event.target != this)
+          return;
+
         if (event.detail == 0)
           return; // Ignore vertical events
 
         var tabs = document.getBindingParent(this);
         tabs.setAttribute("overflow", "true");
         tabs._positionPinnedTabs();
         tabs._handleTabSelect(false);
       ]]></handler>
@@ -5350,17 +5348,16 @@
 
     <implementation implements="nsIDOMEventListener, nsIObserver">
       <constructor>
         <![CDATA[
           this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
 
           var tab = this.firstChild;
           tab.label = this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle");
-          tab.setAttribute("crop", "end");
           tab.setAttribute("onerror", "this.removeAttribute('image');");
 
           window.addEventListener("resize", this, false);
           window.addEventListener("load", this, false);
 
           try {
             this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled");
           } catch (ex) {
@@ -6725,20 +6722,25 @@
           <xul:image xbl:inherits="sharing,selected=visuallyselected"
                      anonid="sharing-icon"
                      class="tab-sharing-icon-overlay"
                      role="presentation"/>
           <xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
                      anonid="overlay-icon"
                      class="tab-icon-overlay"
                      role="presentation"/>
-          <xul:label flex="1"
-                     xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected=visuallyselected,attention"
-                     class="tab-text tab-label"
-                     role="presentation"/>
+          <xul:hbox class="tab-label-container"
+                    xbl:inherits="pinned,selected=visuallyselected"
+                    onoverflow="this.setAttribute('textoverflow', 'true');"
+                    onunderflow="this.removeAttribute('textoverflow');"
+                    flex="1">
+            <xul:label class="tab-text tab-label"
+                       xbl:inherits="xbl:text=label,accesskey,fadein,pinned,selected=visuallyselected,attention"
+                       role="presentation"/>
+          </xul:hbox>
           <xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
                      anonid="soundplaying-icon"
                      class="tab-icon-sound"
                      role="presentation"/>
           <xul:toolbarbutton anonid="close-button"
                              xbl:inherits="fadein,pinned,selected=visuallyselected"
                              class="tab-close-button close-icon"/>
         </xul:hbox>
@@ -7107,17 +7109,17 @@
         ]]></body>
       </method>
 
       <method name="_setMenuitemAttributes">
         <parameter name="aMenuitem"/>
         <parameter name="aTab"/>
         <body><![CDATA[
           aMenuitem.setAttribute("label", aTab.label);
-          aMenuitem.setAttribute("crop", aTab.getAttribute("crop"));
+          aMenuitem.setAttribute("crop", "end");
 
           if (aTab.hasAttribute("busy")) {
             aMenuitem.setAttribute("busy", aTab.getAttribute("busy"));
             aMenuitem.removeAttribute("image");
           } else {
             aMenuitem.setAttribute("image", aTab.getAttribute("image"));
             aMenuitem.removeAttribute("busy");
           }
--- a/browser/base/content/test/general/browser_overflowScroll.js
+++ b/browser/base/content/test/general/browser_overflowScroll.js
@@ -32,17 +32,18 @@ function doTest() {
   while (tabs.length < tabCountForOverflow)
     gBrowser.addTab("about:blank", {skipAnimation: true});
   gBrowser.pinTab(tabs[0]);
 
   tabstrip.addEventListener("overflow", runOverflowTests, false);
 }
 
 function runOverflowTests(aEvent) {
-  if (aEvent.detail != 1)
+  if (aEvent.detail != 1 ||
+      aEvent.target != tabstrip)
     return;
 
   tabstrip.removeEventListener("overflow", runOverflowTests, false);
 
   var upButton = tabstrip._scrollButtonUp;
   var downButton = tabstrip._scrollButtonDown;
   var element;
 
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -2445,16 +2445,17 @@ toolbarbutton.chevron > .toolbarbutton-m
   margin: 0;
 }
 
 %include ../shared/tabs.inc.css
 
 .tab-label {
   margin-top: 1px;
   margin-bottom: 0;
+  -moz-box-flex: 1;
   text-align: center;
 }
 
 @media (-moz-mac-yosemite-theme) {
   /* image preloading hack from shared/tabs.inc.css */
   #tabbrowser-tabs::before {
     background-image:
       url(chrome://browser/skin/yosemite/tab-selected-end-inactive.svg),
@@ -2544,17 +2545,17 @@ toolbarbutton.chevron > .toolbarbutton-m
 /*
  * Force the overlay to create a new stacking context so it always appears on
  * top of the icon.
  */
 .tab-icon-overlay {
   opacity: 0.9999;
 }
 
-.tab-label:not([selected="true"]) {
+.tab-label-container:not([selected="true"]) {
   opacity: .7;
 }
 
 .tabbrowser-tab,
 .tabs-newtab-button {
   font: message-box;
   border: none;
 }
@@ -2570,17 +2571,17 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 .tabs-newtab-button > .toolbarbutton-icon {
   -moz-box-align: center;
   border: solid transparent;
   border-width: 0 11px;
 }
 
-.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label:not([pinned]),
+.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label-container:not([pinned]),
 .tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-icon-image[pinned],
 .tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-throbber[pinned] {
   box-shadow: @focusRingShadow@;
 }
 
 #TabsToolbar {
   -moz-appearance: none;
   /* overlap the nav-bar's top border */
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -186,17 +186,17 @@
 }
 
 .tab-label {
   margin-inline-end: 0;
   margin-inline-start: 0;
 }
 
 .tab-close-button {
-  margin-inline-start: 4px;
+  margin-inline-start: 2px;
   margin-inline-end: -2px;
   padding: 0;
 }
 
 .tab-icon-sound {
   margin-inline-start: 4px;
   width: 16px;
   height: 16px;