Bug 1066531 - Delay tab switching until content is ready in e10s mode r=mconley,mstange
authorGeorge Wright <george@mozilla.com>
Mon, 16 Mar 2015 14:30:41 -0400
changeset 236221 8194018355f69c709cc4a7f9a2a4eb9894a1245d
parent 236220 8c02abfe5360fa4bf00c5c59ea1640f1e2e7c14a
child 236222 7c2073c5cc7e3a1133937afd65b54d80aea424b2
push id12056
push userkwierso@gmail.com
push dateSat, 28 Mar 2015 00:20:05 +0000
treeherderfx-team@9511efa9a8eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley, mstange
bugs1066531
milestone39.0a1
Bug 1066531 - Delay tab switching until content is ready in e10s mode r=mconley,mstange
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/themes/linux/browser-lightweightTheme.css
browser/themes/linux/browser.css
browser/themes/osx/browser-lightweightTheme.css
browser/themes/osx/browser.css
browser/themes/osx/devedition.css
browser/themes/shared/devedition.inc.css
browser/themes/shared/tabs.inc.css
browser/themes/windows/browser-aero.css
browser/themes/windows/browser-lightweightTheme.css
browser/themes/windows/browser.css
browser/themes/windows/devedition.css
dom/base/nsGkAtomList.h
toolkit/content/widgets/tabbox.xml
toolkit/themes/faststripe/global/tabbox.css
toolkit/themes/linux/global/in-content/common.css
toolkit/themes/linux/global/tabbox.css
toolkit/themes/osx/global/in-content/common.css
toolkit/themes/osx/global/tabbox.css
toolkit/themes/windows/global/tabbox.css
widget/cocoa/nsNativeThemeCocoa.mm
widget/gtk/nsNativeThemeGTK.cpp
widget/nsNativeTheme.h
widget/windows/nsNativeThemeWin.cpp
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -656,17 +656,17 @@
 
       <tabs id="tabbrowser-tabs"
             class="tabbrowser-tabs"
             tabbrowser="content"
             flex="1"
             setfocus="false"
             tooltip="tabbrowser-tab-tooltip"
             stopwatchid="FX_TAB_CLICK_MS">
-        <tab class="tabbrowser-tab" selected="true" fadein="true"/>
+        <tab class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
       </tabs>
 
       <toolbarbutton id="new-tab-button"
                      class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&tabCmd.label;"
                      command="cmd_newNavigatorTab"
                      onclick="checkForMiddleClick(this, event);"
                      tooltip="dynamic-shortcut-tooltip"
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2763,31 +2763,34 @@
           this._lastRelatedTab = null;
 
           this.mTabFilters.splice(aIndex, 0, this.mTabFilters.splice(aTab._tPos, 1)[0]);
           this.mTabListeners.splice(aIndex, 0, this.mTabListeners.splice(aTab._tPos, 1)[0]);
 
           let wasFocused = (document.activeElement == this.mCurrentTab);
 
           aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
-          this.mCurrentTab._selected = false;
+          this.mCurrentTab._logicallySelected = false;
+          this.mCurrentTab._visuallySelected = false;
 
           // invalidate caches
           this._browsers = null;
           this._visibleTabs = null;
 
           // use .item() instead of [] because dragging to the end of the strip goes out of
           // bounds: .item() returns null (so it acts like appendChild), but [] throws
           this.tabContainer.insertBefore(aTab, this.tabs.item(aIndex));
 
           for (let i = 0; i < this.tabs.length; i++) {
             this.tabs[i]._tPos = i;
-            this.tabs[i]._selected = false;
+            this.tabs[i]._logicallySelected = false;
+            this.tabs[i]._visuallySelected = false;
           }
-          this.mCurrentTab._selected = true;
+          this.mCurrentTab._logicallySelected = true;
+          this.mCurrentTab._visuallySelected = true;
 
           if (wasFocused)
             this.mCurrentTab.focus();
 
           this.tabContainer._handleTabSelect(false);
 
           if (aTab.pinned)
             this.tabContainer._positionPinnedTabs();
@@ -3116,19 +3119,26 @@
                 let index = Array.indexOf(tabPanel.childNodes, showPanel);
                 if (index != -1) {
                   this.log(`Switch to tab ${index} - ${this.tinfo(showTab)}`);
                   tabPanel.setAttribute("selectedIndex", index);
                   if (showTab === this.requestedTab) {
                     this.tabbrowser._adjustFocusAfterTabSwitch(showTab);
                   }
                 }
+
+                // This doesn't necessarily exist if we're a new window and haven't switched tabs yet
+                if (this.lastVisibleTab)
+                  this.lastVisibleTab._visuallySelected = false;
+
+                this.visibleTab._visuallySelected = true;
               }
 
               this.lastVisibleTab = this.visibleTab;
+
             },
 
             assert: function(cond) {
               if (!cond) {
                 dump("Assertion failure\n" + Error().stack);
                 throw new Error("Assertion failure");
               }
             },
@@ -5406,52 +5416,71 @@
   <binding id="tabbrowser-tab" display="xul:hbox"
            extends="chrome://global/content/bindings/tabbox.xml#tab">
     <resources>
       <stylesheet src="chrome://browser/content/tabbrowser.css"/>
     </resources>
 
     <content context="tabContextMenu" closetabtext="&closeTab.label;">
       <xul:stack class="tab-stack" flex="1">
-        <xul:hbox xbl:inherits="pinned,selected,titlechanged,fadein"
+        <xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged,fadein"
                   class="tab-background">
-          <xul:hbox xbl:inherits="pinned,selected,titlechanged"
+          <xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
                     class="tab-background-start"/>
-          <xul:hbox xbl:inherits="pinned,selected,titlechanged"
+          <xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
                     class="tab-background-middle"/>
-          <xul:hbox xbl:inherits="pinned,selected,titlechanged"
+          <xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
                     class="tab-background-end"/>
         </xul:hbox>
-        <xul:hbox xbl:inherits="pinned,selected,titlechanged"
+        <xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
                   class="tab-content" align="center">
-          <xul:image xbl:inherits="fadein,pinned,busy,progress,selected"
+          <xul:image xbl:inherits="fadein,pinned,busy,progress,selected,visuallyselected"
                      class="tab-throbber"
                      role="presentation"
                      layer="true" />
-          <xul:image xbl:inherits="src=image,fadein,pinned,selected,busy,crashed"
+          <xul:image xbl:inherits="src=image,fadein,pinned,selected,visuallyselected,busy,crashed"
                      anonid="tab-icon-image"
                      class="tab-icon-image"
                      validate="never"
                      role="presentation"/>
           <xul:image xbl:inherits="crashed,busy"
                      class="tab-icon-overlay"
                      role="presentation"/>
           <xul:label flex="1"
                      anonid="tab-label"
-                     xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected"
+                     xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected,visuallyselected"
                      class="tab-text tab-label"
                      role="presentation"/>
           <xul:toolbarbutton anonid="close-button"
-                             xbl:inherits="fadein,pinned,selected"
+                             xbl:inherits="fadein,pinned,selected,visuallyselected"
                              class="tab-close-button close-icon"/>
         </xul:hbox>
       </xul:stack>
     </content>
 
     <implementation>
+
+      <property name="_selected">
+        <setter>
+          <![CDATA[
+          // in e10s we want to only pseudo-select a tab before its rendering is done, so that
+          // the rest of the system knows that the tab is selected, but we don't want to update its
+          // visual status to selected until after we receive confirmation that its content has painted.
+          this._logicallySelected = val;
+
+          // If we're non-e10s we should update the visual selection as well at the same time
+          if (!gMultiProcessBrowser) {
+            this._visuallySelected = val;
+          }
+
+          return val;
+        ]]>
+        </setter>
+      </property>
+
       <property name="label">
         <getter>
           return this.getAttribute("label");
         </getter>
         <setter>
           this.setAttribute("label", val);
           let event = new CustomEvent("TabLabelModified", {
             bubbles: true,
--- a/browser/themes/linux/browser-lightweightTheme.css
+++ b/browser/themes/linux/browser-lightweightTheme.css
@@ -6,26 +6,26 @@
 %filter substitution
 
 /*
  * LightweightThemeListener will append the current lightweight theme's header
  * image to the background-image for each of the following rulesets.
  */
 
 /* Lightweight theme on tabs */
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
   background-position: 0 0, right top;
   background-repeat: repeat-x, no-repeat;
 }
 
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
   background-attachment: scroll, scroll, fixed;
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   background-position: 0 0, 0 0, right top;
   background-repeat: repeat-x, repeat-x, no-repeat;
 }
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1836,25 +1836,25 @@ richlistitem[type~="action"][actiontype=
 /* Tab drag and drop */
 .tab-drop-indicator {
   list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png);
   margin-bottom: -9px;
   z-index: 3;
 }
 
 /* Tab close button */
-.tab-close-button:not([selected]):not(:hover) {
+.tab-close-button:not([visuallyselected]):not(:hover) {
   background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 64, 16, 48);
 }
 
-#TabsToolbar[brighttext] .tab-close-button:not([selected]):not(:hover) {
+#TabsToolbar[brighttext] .tab-close-button:not([visuallyselected]):not(:hover) {
   background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
 }
 
-.tab-close-button:not([selected]):not(:hover):-moz-lwtheme-darktext {
+.tab-close-button:not([visuallyselected]):not(:hover):-moz-lwtheme-darktext {
   background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 96, 16, 80);
 }
 
 /* Tabstrip new tab button */
 .tabs-newtab-button,
 #TabsToolbar > #new-tab-button ,
 #TabsToolbar > #wrapper-new-tab-button > #new-tab-button {
   list-style-image: url("moz-icon://stock/gtk-add?size=menu");
@@ -1919,17 +1919,17 @@ richlistitem[type~="action"][actiontype=
   display: none;
 }
 
 /* All tabs menupopup */
 .alltabs-item > .menu-iconic-left > .menu-iconic-icon {
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
-.alltabs-item[selected="true"] {
+.alltabs-item[visuallyselected="true"] {
   font-weight: bold;
 }
 
 .alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
 }
 
 .alltabs-item[tabIsVisible] {
--- a/browser/themes/osx/browser-lightweightTheme.css
+++ b/browser/themes/osx/browser-lightweightTheme.css
@@ -5,34 +5,34 @@
 %include shared.inc
 
 /*
  * LightweightThemeListener will append the current lightweight theme's header
  * image to the background-image for each of the following rulesets.
  */
 
 /* Lightweight theme on tabs */
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
   background-position: 0 0, right top;
   background-repeat: repeat-x, no-repeat;
 }
 
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
   background-attachment: scroll, scroll, fixed;
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   background-position: 0 0, 0 0, right top;
   background-repeat: repeat-x, repeat-x, no-repeat;
 }
 
 @media (min-resolution: 2dppx) {
-  #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+  #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
     background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
                       @fgTabTextureLWT@;/*,
                       lwtHeader;*/
   }
 }
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -3040,36 +3040,36 @@ toolbarbutton.chevron > .toolbarbutton-m
   /* image preloading hack from shared/tabs.inc.css */
   #tabbrowser-tabs::before {
     background-image:
       url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png),
       url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
       url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png);
   }
 
-  .tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
+  .tabbrowser-tab:hover > .tab-stack > .tab-background:not([visuallyselected=true]),
   .tabs-newtab-button:hover {
     background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png),
                       url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
                       url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png);
   }
 
-  .tab-background-middle[selected=true] {
+  .tab-background-middle[visuallyselected=true] {
     background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
                       @fgTabTexture@,
                       none;
   }
 
-  .tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
-  .tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
+  .tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr)::after,
+  .tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl)::after {
     background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start@2x.png);
   }
 
-  .tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
-  .tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
+  .tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr)::after,
+  .tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl)::after {
     background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end@2x.png);
   }
 
   .tab-icon-image {
     list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
   }
 
   .tab-throbber[busy] {
@@ -3077,50 +3077,50 @@ toolbarbutton.chevron > .toolbarbutton-m
   }
 
   .tab-throbber[progress] {
     list-style-image: url("chrome://browser/skin/tabbrowser/loading@2x.png");
   }
 
   /* Background tab separators */
   #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
-  .tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
-  #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+  .tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
+  #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
     background-image: url(chrome://browser/skin/tabbrowser/tab-separator@2x.png);
   }
 }
 
-.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) {
+.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([visuallyselected="true"]) {
   opacity: .9;
 }
 
 /*
  * 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:not([visuallyselected="true"]) {
   opacity: .7;
 }
 
 .tabbrowser-tab,
 .tabs-newtab-button {
   font: message-box;
   border: none;
 }
 
-.tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
+.tabbrowser-tab[visuallyselected=true]:not(:-moz-lwtheme) {
   /* overriding tabbox.css */
   color: inherit;
 }
 
-.tabbrowser-tab[selected=true] {
+.tabbrowser-tab[visuallyselected=true] {
   /* overriding tabbox.css */
   text-shadow: inherit;
 }
 
 .tabs-newtab-button > .toolbarbutton-icon {
   -moz-box-align: center;
   border: solid transparent;
   border-width: 0 11px;
@@ -3160,17 +3160,17 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 /* Background tabs:
  *
  * Decrease the height of the hoverable region of background tabs whenever the tabs are at the top
  * of the window (e.g. no menubar, tabs in titlebar, etc.) to make it easier to drag the window by
  * the titlebar. We don't need this in fullscreen since window dragging is not an issue there.
  */
-#main-window[tabsintitlebar]:not([inFullscreen]) .tab-background-middle:not([selected=true]) {
+#main-window[tabsintitlebar]:not([inFullscreen]) .tab-background-middle:not([visuallyselected=true]) {
   clip-path: url(chrome://browser/content/browser.xul#tab-hover-clip-path);
 }
 
 /**
  * Tab Drag and Drop
  */
 
 .tab-drop-indicator {
@@ -3196,22 +3196,22 @@ toolbarbutton.chevron > .toolbarbutton-m
 
 .tab-close-button {
   -moz-appearance: none;
   border: none !important;
   background: none;
   cursor: default;
 }
 
-#TabsToolbar[brighttext] .tab-close-button.close-icon:not([selected=true]):not(:hover) {
+#TabsToolbar[brighttext] .tab-close-button.close-icon:not([visuallyselected=true]):not(:hover) {
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 
 @media (min-resolution: 2dppx) {
-  #TabsToolbar[brighttext] .tab-close-button.close-icon:not([selected=true]):not(:hover) {
+  #TabsToolbar[brighttext] .tab-close-button.close-icon:not([visuallyselected=true]):not(:hover) {
     -moz-image-region: rect(0, 128px, 32px, 96px);
   }
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-image-region: rect(0, 13px, 20px, 0);
   margin: 0 0 var(--tab-toolbar-navbar-overlap);
--- a/browser/themes/osx/devedition.css
+++ b/browser/themes/osx/devedition.css
@@ -80,16 +80,16 @@
 
 /* Don't use the default background for tabs toolbar */
 #TabsToolbar {
   -moz-appearance: none !important;
 }
 
 /* Tab styling - make sure to use an inverted icon for the selected tab
    (brighttext only covers the unselected tabs) */
-.tab-close-button[selected=true]:not(:hover) {
+.tab-close-button[visuallyselected=true]:not(:hover) {
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 @media (min-resolution: 2dppx) {
-  .tab-close-button[selected=true]:not(:hover) {
+  .tab-close-button[visuallyselected=true]:not(:hover) {
     -moz-image-region: rect(0, 128px, 32px, 96px);
   }
 }
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -136,27 +136,27 @@
   -moz-margin-start: 0;
 }
 
 .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox {
   -moz-padding-end: 0;
   -moz-padding-start: 0;
 }
 
-.tab-background-start[selected=true]::after,
-.tab-background-start[selected=true]::before,
+.tab-background-start[visuallyselected=true]::after,
+.tab-background-start[visuallyselected=true]::before,
 .tab-background-start,
 .tab-background-end,
-.tab-background-end[selected=true]::after,
-.tab-background-end[selected=true]::before {
+.tab-background-end[visuallyselected=true]::after,
+.tab-background-end[visuallyselected=true]::before {
   width: 0;
 }
 
-.tab-background-start[selected=true]::after,
-.tab-background-end[selected=true]::after {
+.tab-background-start[visuallyselected=true]::after,
+.tab-background-end[visuallyselected=true]::after {
   -moz-margin-start: 0;
 }
 /* End override @tabCurveHalfWidth@ and @tabCurveWidth@ */
 
 #urlbar ::-moz-selection,
 #navigator-toolbox .searchbar-textbox ::-moz-selection,
 .browserContainer > findbar ::-moz-selection {
   background-color: var(--chrome-selection-background-color);
@@ -265,29 +265,29 @@ searchbar:not([oneoffui]) .search-go-but
 }
 
 .tab-background {
   visibility: hidden;
 }
 
 /* Make the tab splitter 1px wide with a solid background. */
 #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
-.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
-#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+.tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
+#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
   background: var(--tab-separator-color);
   width: 1px;
   -moz-margin-start: 0;
   -moz-margin-end: -1px;
 }
 
 /* For the last tab separator, use margin-start of -1px to prevent jittering
    due to the ::after element causing the width of the tab to extend, which
    causes an overflow and makes it disappear, which removes the overflow and
    causes it to reappear, etc, etc. */
-#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
   -moz-margin-start: -1px;
   -moz-margin-end: 0;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down,
 .tabbrowser-arrowscrollbox > .scrollbutton-up {
   background-color: var(--tab-background-color);
   border-color: transparent;
@@ -299,29 +299,29 @@ searchbar:not([oneoffui]) .search-go-but
 }
 
 .tabbrowser-tab {
   /* We normally rely on other tab elements for pointer events, but this
      theme hides those so we need it set here instead */
   pointer-events: auto;
 }
 
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
+.tabbrowser-tab[pinned][titlechanged]:not([visuallyselected="true"]) > .tab-stack > .tab-content {
   background-image: var(--pinned-tab-glow);
   background-position: center;
   background-size: 100%;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):hover,
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover,
 .tabbrowser-tab:hover {
   background-color: var(--tab-hover-background-color);
 }
 
-.tabbrowser-tab[selected] {
+.tabbrowser-tab[visuallyselected] {
   color: var(--tab-selection-color) !important; /* Override color: inherit */
   background-color: var(--tab-selection-background-color);
   box-shadow: var(--tab-selection-box-shadow);
 }
 
 /* Don't need space for the tab curves (66px - 30px) */
 .tabs-newtab-button {
   width: 36px;
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -42,17 +42,17 @@
   -moz-box-align: stretch;
 }
 
 .tabbrowser-tab[remote] {
   text-decoration: underline;
 }
 
 /* The selected tab should appear above adjacent tabs, .tabs-newtab-button and the highlight of #nav-bar */
-.tabbrowser-tab[selected=true] {
+.tabbrowser-tab[visuallyselected=true] {
   position: relative;
   z-index: 2;
 }
 
 .tab-background-middle {
   -moz-box-flex: 1;
   background-clip: padding-box;
   border-left: @tabCurveHalfWidth@ solid transparent;
@@ -162,132 +162,132 @@
   opacity: 0;
 }
 
 .tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-start-indicator,
 .tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-end-indicator {
   transition: opacity 150ms ease;
 }
 
-.tab-background-start[selected=true]::after,
-.tab-background-start[selected=true]::before,
+.tab-background-start[visuallyselected=true]::after,
+.tab-background-start[visuallyselected=true]::before,
 .tab-background-start,
 .tab-background-end,
-.tab-background-end[selected=true]::after,
-.tab-background-end[selected=true]::before {
+.tab-background-end[visuallyselected=true]::after,
+.tab-background-end[visuallyselected=true]::before {
   min-height: var(--tab-min-height);
   width: @tabCurveWidth@;
 }
 
-.tabbrowser-tab:not([selected=true]),
+.tabbrowser-tab:not([visuallyselected=true]),
 .tabbrowser-tab:-moz-lwtheme {
   color: inherit;
 }
 
 /* Selected tab */
 
 /*
  Tab background pseudo-elements which are positioned above .tab-background-start/end:
    - ::before - provides the fill of the tab curve and is clipped to the tab shape. This is where
                 pointer events go for the curve.
    - ::after  - provides the border/stroke of the tab curve and is overlayed above ::before.  Pointer
                 events go through to ::before to get the proper shape.
  */
 
 
-.tab-background-start[selected=true]::after,
-.tab-background-end[selected=true]::after {
+.tab-background-start[visuallyselected=true]::after,
+.tab-background-end[visuallyselected=true]::after {
   /* position ::after on top of its parent */
   -moz-margin-start: -@tabCurveWidth@;
   background-size: 100% 100%;
   content: "";
   display: -moz-box;
   position: relative;
 }
 
-.tab-background-start[selected=true]::before,
-.tab-background-end[selected=true]::before {
+.tab-background-start[visuallyselected=true]::before,
+.tab-background-end[visuallyselected=true]::before {
   /* all ::before pseudo elements */
   content: "";
   display: -moz-box;
 }
 
-.tab-background-start[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
-.tab-background-end[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
+.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
+.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
   background-image: url(chrome://browser/skin/tabbrowser/tab-selected-start.svg);
   background-size: 100% 100%;
 }
 
-.tab-background-end[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
-.tab-background-start[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
+.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
+.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
   background-image: url(chrome://browser/skin/tabbrowser/tab-selected-end.svg);
   background-size: 100% 100%;
 }
 
 /* For lightweight themes, clip the header image on start, middle, and end. */
-.tab-background-start[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
-.tab-background-end[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
+.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
+.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
   clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-start);
 }
 
-.tab-background-end[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
-.tab-background-start[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
+.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
+.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
   clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-end);
 }
 
-.tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
-.tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
+.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr)::after,
+.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl)::after {
   background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start.png);
 }
 
-.tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
-.tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
+.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr)::after,
+.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl)::after {
   background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end.png);
 }
 
-.tab-background-middle[selected=true] {
+.tab-background-middle[visuallyselected=true] {
   background-clip: padding-box, padding-box, content-box;
   background-color: @fgTabBackgroundColor@;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTexture@,
                     none;
   background-repeat: repeat-x;
   background-size: auto 100%;
   /* The padding-top combined with background-clip: content-box (the bottom-most) ensure the
      background-color doesn't extend above the top border. */
   padding-top: 2px;
 }
 
 /* Selected tab lightweight theme styles.
    See browser-lightweightTheme.css for information about run-time changes to LWT styles. */
-.tab-background-middle[selected=true]:-moz-lwtheme {
+.tab-background-middle[visuallyselected=true]:-moz-lwtheme {
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   /* Don't stretch the LWT header images */
   background-size: auto 100%, auto 100%, auto auto;
 }
 
 /* These LWT styles are normally overridden by browser-lightweightTheme.css */
-.tab-background-start[selected=true]:-moz-lwtheme::before,
-.tab-background-end[selected=true]:-moz-lwtheme::before {
+.tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
+.tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
   background-image: @fgTabTextureLWT@;
 }
 
-.tab-background-start[selected=true]:-moz-lwtheme::before,
-.tab-background-end[selected=true]:-moz-lwtheme::before,
-.tab-background-middle[selected=true]:-moz-lwtheme {
+.tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
+.tab-background-end[visuallyselected=true]:-moz-lwtheme::before,
+.tab-background-middle[visuallyselected=true]:-moz-lwtheme {
   background-color: transparent;
 }
 
 /* End selected tab */
 
 /* new tab button border and gradient on hover */
-.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
+.tabbrowser-tab:hover > .tab-stack > .tab-background:not([visuallyselected=true]),
 .tabs-newtab-button:hover {
   background-image: url(chrome://browser/skin/tabbrowser/tab-background-start.png),
                     url(chrome://browser/skin/tabbrowser/tab-background-middle.png),
                     url(chrome://browser/skin/tabbrowser/tab-background-end.png);
   background-position: left bottom, @tabCurveWidth@ bottom, right bottom;
   background-repeat: no-repeat;
   background-size: @tabCurveWidth@ 100%, calc(100% - (2 * @tabCurveWidth@)) 100%, @tabCurveWidth@ 100%;
 }
@@ -306,28 +306,28 @@
 /* Pinned tabs */
 
 /* Pinned tab separators need position: absolute when positioned (during overflow). */
 #tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned]::before {
   height: 100%;
   position: absolute;
 }
 
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
+.tabbrowser-tab[pinned][titlechanged]:not([visuallyselected="true"]) > .tab-stack > .tab-content {
   background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, transparent 70%);
   background-position: center bottom var(--tab-toolbar-navbar-overlap);
   background-repeat: no-repeat;
   background-size: 85% 100%;
 }
 
 /* Background tab separators (3px wide).
    Also show separators beside the selected tab when dragging it. */
 #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
-.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
-#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+.tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
+#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
   -moz-margin-start: -1.5px;
   -moz-margin-end: -1.5px;
   background-image: url(chrome://browser/skin/tabbrowser/tab-separator.png);
   background-position: left bottom var(--tab-toolbar-navbar-overlap);
   background-repeat: no-repeat;
   background-size: 3px 100%;
   content: "";
   display: -moz-box;
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -78,17 +78,17 @@
   @media (-moz-os-version: windows-vista),
          (-moz-os-version: windows-win7) {
     #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(:-moz-lwtheme),
     #browser-bottombox:not(:-moz-lwtheme),
     .browserContainer > findbar {
       background-color: @customToolbarColor@;
     }
 
-    .tab-background-middle[selected=true]:not(:-moz-lwtheme) {
+    .tab-background-middle[visuallyselected=true]:not(:-moz-lwtheme) {
       background-color: @customToolbarColor@;
     }
 
     #navigator-toolbox:not(:-moz-lwtheme)::after {
       background-color: #aabccf;
     }
 
     #urlbar:not(:-moz-lwtheme):not([focused]):hover,
--- a/browser/themes/windows/browser-lightweightTheme.css
+++ b/browser/themes/windows/browser-lightweightTheme.css
@@ -6,34 +6,34 @@
 %filter substitution
 
 /*
  * LightweightThemeListener will append the current lightweight theme's header
  * image to the background-image for each of the following rulesets.
  */
 
 /* Lightweight theme on tabs */
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
   background-position: 0 0, right top;
   background-repeat: repeat-x, no-repeat;
 }
 
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
   background-attachment: scroll, scroll, fixed;
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   background-position: 0 0, 0 0, right top;
   background-repeat: repeat-x, repeat-x, no-repeat;
 }
 
 @media (min-resolution: 1.25dppx) {
-  #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+  #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
     background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
                       @fgTabTextureLWT@;/*,
                       lwtHeader;*/
   }
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1823,67 +1823,67 @@ toolbarbutton[type="socialmark"] > .tool
   /* image preloading hack from shared/tabs.inc.css */
   #tabbrowser-tabs::before {
     background-image:
       url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png),
       url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
       url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png);
   }
 
-  .tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
+  .tabbrowser-tab:hover > .tab-stack > .tab-background:not([visuallyselected=true]),
   .tabs-newtab-button:hover {
     background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png),
                       url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
                       url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png);
   }
 
-  .tab-background-middle[selected=true] {
+  .tab-background-middle[visuallyselected=true] {
     background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
                       @fgTabTexture@,
                       none;
   }
 
-  .tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
-  .tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
+  .tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr)::after,
+  .tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl)::after {
     background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start@2x.png);
   }
 
-  .tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
-  .tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
+  .tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr)::after,
+  .tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl)::after {
     background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end@2x.png);
   }
 }
 
 %ifndef WINDOWS_AERO
 /* Use lighter colors of buttons and text in the titlebar on luna-blue */
 @media (-moz-windows-theme: luna-blue) {
   #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
-  .tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
-  #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+  .tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
+  #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
     background-image: url("chrome://browser/skin/tabbrowser/tab-separator-luna-blue.png");
   }
 }
 %endif
 
-#TabsToolbar[brighttext] .tab-close-button:not(:hover):not([selected="true"]) {
+#TabsToolbar[brighttext] .tab-close-button:not(:hover):not([visuallyselected="true"]) {
   -moz-image-region: rect(0, 64px, 16px, 48px) !important;
 }
 
 /* tabbrowser-tab focus ring */
 .tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label {
   outline: 1px dotted;
 }
 
 /* Background tabs:
  *
  * Decrease the height of the hoverable region of background tabs whenever the tabs are at the top
  * of the window (e.g. no menubar, tabs in titlebar, etc.) to make it easier to drag the window by
  * the titlebar. We don't need this in fullscreen since window dragging is not an issue there.
  */
-#main-window[tabsintitlebar][sizemode=normal] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar .tab-background-middle:not([selected=true]) {
+#main-window[tabsintitlebar][sizemode=normal] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar .tab-background-middle:not([visuallyselected=true]) {
   clip-path: url(chrome://browser/content/browser.xul#tab-hover-clip-path);
 }
 
 /* Tab DnD indicator */
 .tab-drop-indicator {
   list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png);
   margin-bottom: -9px;
   z-index: 3;
--- a/browser/themes/windows/devedition.css
+++ b/browser/themes/windows/devedition.css
@@ -153,11 +153,11 @@
   /* Reset image-region from the windows theme */
   -moz-image-region: auto !important;
   /* Add margin otherwise it looks weird */
   -moz-margin-start: 2px;
 }
 
 /* Tab styling - make sure to use an inverted icon for the selected tab
    (brighttext only covers the unselected tabs) */
-.tab-close-button[selected=true]:not(:hover) {
+.tab-close-button[visuallyselected=true]:not(:hover) {
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1234,16 +1234,17 @@ GK_ATOM(videocontrols, "videocontrols")
 GK_ATOM(viewport, "viewport")
 GK_ATOM(viewport_height, "viewport-height")
 GK_ATOM(viewport_initial_scale, "viewport-initial-scale")
 GK_ATOM(viewport_maximum_scale, "viewport-maximum-scale")
 GK_ATOM(viewport_minimum_scale, "viewport-minimum-scale")
 GK_ATOM(viewport_user_scalable, "viewport-user-scalable")
 GK_ATOM(viewport_width, "viewport-width")
 GK_ATOM(visibility, "visibility")
+GK_ATOM(visuallyselected, "visuallyselected")
 GK_ATOM(vlink, "vlink")
 GK_ATOM(vspace, "vspace")
 GK_ATOM(wbr, "wbr")
 GK_ATOM(when, "when")
 GK_ATOM(where, "where")
 GK_ATOM(widget, "widget")
 GK_ATOM(width, "width")
 GK_ATOM(window, "window")
--- a/toolkit/content/widgets/tabbox.xml
+++ b/toolkit/content/widgets/tabbox.xml
@@ -696,17 +696,17 @@
 
   <binding id="tab" display="xul:button" role="xul:tab"
            extends="chrome://global/content/bindings/general.xml#control-item">
     <resources>
       <stylesheet src="chrome://global/skin/tabbox.css"/>
     </resources>
 
     <content>
-      <xul:hbox class="tab-middle box-inherit" xbl:inherits="align,dir,pack,orient,selected" flex="1">
+      <xul:hbox class="tab-middle box-inherit" xbl:inherits="align,dir,pack,orient,selected,visuallyselected" flex="1">
         <xul:image class="tab-icon"
                    xbl:inherits="validate,src=image"
                    role="presentation"/>
         <xul:label class="tab-text"
                    xbl:inherits="value=label,accesskey,crop,disabled"
                    flex="1"
                    role="presentation"/>
       </xul:hbox>
@@ -722,23 +722,23 @@
             return null;
           ]]>
         </getter>
       </property>
 
       <property name="selected" readonly="true"
                 onget="return this.getAttribute('selected') == 'true';"/>
 
-      <property name="_selected">
+      <property name="_visuallySelected">
         <setter>
           <![CDATA[
           if (val)
-            this.setAttribute("selected", "true");
+            this.setAttribute("visuallyselected", "true");
           else
-            this.removeAttribute("selected");
+            this.removeAttribute("visuallyselected");
 
           if (this.previousSibling && this.previousSibling.localName == "tab") {
             if (val)
               this.previousSibling.setAttribute("beforeselected", "true");
             else
               this.previousSibling.removeAttribute("beforeselected");
             this.removeAttribute("first-tab");
           }
@@ -754,16 +754,40 @@
           }
           else
             this.setAttribute("last-tab", "true");
           return val;
         ]]>
         </setter>
       </property>
 
+      <property name="_logicallySelected">
+        <setter>
+          <![CDATA[
+          if (val)
+            this.setAttribute("selected", "true");
+          else
+            this.removeAttribute("selected");
+
+          return val;
+          ]]>
+        </setter>
+      </property>
+
+      <property name="_selected">
+        <setter>
+          <![CDATA[
+          // If our tab switching is synchronous, then logical selection = visual selection
+          this._logicallySelected = val;
+          this._visuallySelected = val;
+          return val;
+          ]]>
+        </setter>
+      </property>
+
       <property name="linkedPanel" onget="return this.getAttribute('linkedpanel')"
                                    onset="this.setAttribute('linkedpanel', val); return val;"/>
 
       <field name="arrowKeysShouldWrap" readonly="true">
 #ifdef XP_MACOSX
         true
 #else
         false
--- a/toolkit/themes/faststripe/global/tabbox.css
+++ b/toolkit/themes/faststripe/global/tabbox.css
@@ -46,40 +46,40 @@ tab:-moz-locale-dir(rtl) {
   border-bottom-left-radius: 1px;
   border-bottom-right-radius: 0px;
 }
 
 .tab-text {
   margin: 0 !important;
 }
 
-tab[selected="true"] {
+tab[visuallyselected="true"] {
   margin-top: 0;
   border-bottom-color: transparent;
   padding: 1px 6px 4px 6px;
 }
 
 tab:focus > .tab-middle {
   /* Don't specify the outline-color, we should always use initial value. */
   outline: 1px dotted;
 }
 
 tab[beforeselected="true"]:not(:-moz-locale-dir(rtl)),
-tab[selected="true"]:-moz-locale-dir(rtl) + tab {
+tab[visuallyselected="true"]:-moz-locale-dir(rtl) + tab {
   border-right: none;
   border-top-right-radius: 0;
 }
 
-tab[selected="true"]:not(:-moz-locale-dir(rtl)) + tab,
+tab[visuallyselected="true"]:not(:-moz-locale-dir(rtl)) + tab,
 tab[beforeselected="true"]:-moz-locale-dir(rtl) {
   border-left: none;
   border-top-left-radius: 0;
 }
 
-tab:first-of-type[selected="true"] {
+tab:first-of-type[visuallyselected="true"] {
   padding-right: 5px;
   padding-left: 5px;
 }
 
 /* ::::: tab-bottom ::::::::::
    :: Tabs that are attached to the bottom of a panel, but not necessarily
    :: a tabpanels.
    ::::: */
@@ -91,28 +91,28 @@ tab:first-of-type[selected="true"] {
   border-bottom: 1px solid #555555;
   border-top-left-radius: 0;
   border-top-right-radius: 0;
   border-bottom-right-radius: 2px;
   border-bottom-left-radius: 2px;
   padding: 2px 4px 1px 4px;
 }
 
-.tab-bottom[selected="true"] {
+.tab-bottom[visuallyselected="true"] {
   margin-bottom: 0;
   -moz-border-top-colors: -moz-Dialog;
   padding: 4px 6px 1px 6px;
 }
 
 .tab-bottom[beforeselected="true"]:not(:-moz-locale-dir(rtl)),
-.tab-bottom[selected="true"]:-moz-locale-dir(rtl) + .tab-bottom {
+.tab-bottom[visuallyselected="true"]:-moz-locale-dir(rtl) + .tab-bottom {
   border-bottom-right-radius: 0;
 }
 
-.tab-bottom[selected="true"]:not(:-moz-locale-dir(rtl)) + .tab-bottom,
+.tab-bottom[visuallyselected="true"]:not(:-moz-locale-dir(rtl)) + .tab-bottom,
 .tab-bottom[beforeselected="true"]:-moz-locale-dir(rtl) {
   border-bottom-left-radius: 0;
 }
 
 /* ::::: tabs-bottom ::::: */
 
 .tabs-bottom > .tabs-left,
 .tabs-bottom > .tabs-right {
--- a/toolkit/themes/linux/global/in-content/common.css
+++ b/toolkit/themes/linux/global/in-content/common.css
@@ -1,15 +1,15 @@
 /* - This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %include ../../../shared/in-content/common.inc.css
 
-xul|tab[selected] {
+xul|tab[visuallyselected] {
   /* Override styles for tab[selected] from
      toolkit/themes/linux/global/tabbox.css */
   margin-bottom: 0;
   border-bottom-left-radius: 0;
   border-bottom-right-radius: 0;
 }
 
 xul|button,
--- a/toolkit/themes/linux/global/tabbox.css
+++ b/toolkit/themes/linux/global/tabbox.css
@@ -43,17 +43,17 @@ tab {
   -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow;
   border-top-left-radius: 2px;
   border-top-right-radius: 2px;
   padding: 3px 4px;
   background-color: -moz-Dialog;
   color: -moz-DialogText;
 }
 
-tab[selected="true"] {
+tab[visuallyselected="true"] {
   z-index: 1;
   margin-top: 0;
   margin-bottom: -2px;
   border-bottom-left-radius: 3px;
   border-bottom-right-radius: 3px;
   padding-top: 4px;
   padding-bottom: 6px;
 }
@@ -78,14 +78,14 @@ tab + tab {
   border-bottom: 2px solid;
   -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow;
   border-top-left-radius: 0;
   border-top-right-radius: 0;
   border-bottom-right-radius: 2px;
   border-bottom-left-radius: 2px;
 }
 
-.tab-bottom[selected="true"] {
+.tab-bottom[visuallyselected="true"] {
   margin-bottom: 0;
   margin-top: -2px;
   padding-top: 6px;
   padding-bottom: 4px;
 }
--- a/toolkit/themes/osx/global/in-content/common.css
+++ b/toolkit/themes/osx/global/in-content/common.css
@@ -5,17 +5,17 @@
 %include ../shared.inc
 %include ../../../shared/in-content/common.inc.css
 
 xul|tabs {
   padding-right: 0;
   padding-left: 0;
 }
 
-xul|tab[selected] {
+xul|tab[visuallyselected] {
   text-shadow: none;
 }
 
 xul|button,
 html|button,
 xul|colorpicker[type="button"],
 xul|menulist {
   margin-top: 3px;
@@ -90,9 +90,9 @@ xul|radio[focused="true"] > .radio-check
 xul|tab:-moz-focusring > .tab-middle > .tab-text {
 	outline: 2px solid rgba(0,149,221,0.5);
 	outline-offset: 1px;
 	-moz-outline-radius: 2px;
 }
 
 xul|radio[focused="true"] > .radio-check {
 	-moz-outline-radius: 100%;
-}
\ No newline at end of file
+}
--- a/toolkit/themes/osx/global/tabbox.css
+++ b/toolkit/themes/osx/global/tabbox.css
@@ -46,17 +46,17 @@ tab:first-of-type {
   -moz-padding-start: 2px;
 }
 
 tab:last-of-type {
   -moz-padding-end: 2px;
 }
 
 @media (-moz-mac-lion-theme) {
-  tab[selected="true"] {
+  tab[visuallyselected="true"] {
     color: #FFF;
     text-shadow: rgba(0, 0, 0, 0.4) 0 1px;
   }
 }
 
 .tab-middle {
   padding: 1px 6px 2px;
 }
@@ -99,24 +99,24 @@ tabs.tabs-bottom > tab {
   -moz-border-end: 1px solid rgba(0, 0, 0, 0.19);
 }
 
 tabbox.tabs-bottom > tabs > tab > .tab-middle,
 tabs.tabs-bottom > tab > .tab-middle {
   padding: 1px 2px 0 2px;
 }
 
-tabbox.tabs-bottom > tabs > tab:not([selected=true]):hover,
-tabs.tabs-bottom > tab:not([selected=true]):hover {
+tabbox.tabs-bottom > tabs > tab:not([visuallyselected=true]):hover,
+tabs.tabs-bottom > tab:not([visuallyselected=true]):hover {
   background-color: rgba(0, 0, 0, 0.1);
   -moz-border-end-color: rgba(0, 0, 0, 0.1);
 }
 
-tabbox.tabs-bottom > tabs > tab[selected=true],
-tabs.tabs-bottom > tab[selected=true] {
+tabbox.tabs-bottom > tabs > tab[visuallyselected=true],
+tabs.tabs-bottom > tab[visuallyselected=true] {
   color: #000;
   text-shadow: none;
   border: solid #888;
   border-width: 0 2px 2px;
   border-radius: 2px;
   -moz-border-left-colors: rgba(0, 0, 0, 0.08) #888;
   -moz-border-right-colors: rgba(0, 0, 0, 0.08) #888;
   -moz-border-bottom-colors: rgba(0, 0, 0, 0.08) #888;
@@ -127,24 +127,24 @@ tabs.tabs-bottom > tab[selected=true] {
 }
 
 tabbox.tabs-bottom > tabs > tab[beforeselected=true],
 tabs.tabs-bottom > tab[beforeselected=true] {
   -moz-border-end-color: transparent;
   -moz-margin-end: -2px;
 }
 
-tabbox.tabs-bottom > tabs > tab:first-of-type:not([selected=true]),
-tabs.tabs-bottom > tab:first-of-type:not([selected=true]) {
+tabbox.tabs-bottom > tabs > tab:first-of-type:not([visuallyselected=true]),
+tabs.tabs-bottom > tab:first-of-type:not([visuallyselected=true]) {
   -moz-border-start: 4px solid transparent;
 }
 
-tabbox.tabs-bottom > tabs > tab:first-of-type[selected=true],
-tabs.tabs-bottom > tab:first-of-type[selected=true] {
+tabbox.tabs-bottom > tabs > tab:first-of-type[visuallyselected=true],
+tabs.tabs-bottom > tab:first-of-type[visuallyselected=true] {
   -moz-margin-start: 2px;
 }
 
 tabbox.tabs-bottom,
 tabbox.tabs-bottom > tabpanels,
-tabbox.tabs-bottom > tabs > tab[selected=true] > .tab-middle,
-tabs.tabs-bottom > tab[selected=true] > .tab-middle {
+tabbox.tabs-bottom > tabs > tab[visuallyselected=true] > .tab-middle,
+tabs.tabs-bottom > tab[visuallyselected=true] > .tab-middle {
   -moz-appearance: dialog;
 }
--- a/toolkit/themes/windows/global/tabbox.css
+++ b/toolkit/themes/windows/global/tabbox.css
@@ -55,40 +55,40 @@ tab:-moz-locale-dir(rtl) {
   border-bottom-left-radius: 1px;
   border-bottom-right-radius: 0px;
 }
 
 .tab-text {
   margin: 0 !important;
 }
 
-tab[selected="true"] {
+tab[visuallyselected="true"] {
   margin-top: 0;
   border-bottom-color: transparent;
   padding: 1px 6px 4px 6px;
 }
 
 tab:-moz-focusring > .tab-middle {
   /* Don't specify the outline-color, we should always use initial value. */
   outline: 1px dotted;
 }
 
 tab[beforeselected="true"]:-moz-locale-dir(ltr),
-tab[selected="true"]:-moz-locale-dir(rtl) + tab {
+tab[visuallyselected="true"]:-moz-locale-dir(rtl) + tab {
   border-right: none;
   border-top-right-radius: 0;
 }
 
-tab[selected="true"]:-moz-locale-dir(ltr) + tab,
+tab[visuallyselected="true"]:-moz-locale-dir(ltr) + tab,
 tab[beforeselected="true"]:-moz-locale-dir(rtl) {
   border-left: none;
   border-top-left-radius: 0;
 }
 
-tab:first-of-type[selected="true"] {
+tab:first-of-type[visuallyselected="true"] {
   padding-right: 5px;
   padding-left: 5px;
 }
 
 /* ::::: tab-bottom ::::::::::
    :: Tabs that are attached to the bottom of a panel, but not necessarily
    :: a tabpanels.
    ::::: */
@@ -102,28 +102,28 @@ tab:first-of-type[selected="true"] {
   -moz-border-bottom-colors: ThreeDShadow ThreeDLightShadow;
   border-top-left-radius: 0;
   border-top-right-radius: 0;
   border-bottom-right-radius: 2px;
   border-bottom-left-radius: 2px;
   padding: 2px 4px 1px 4px;
 }
 
-.tab-bottom[selected="true"] {
+.tab-bottom[visuallyselected="true"] {
   margin-bottom: 0;
   -moz-border-top-colors: -moz-Dialog;
   padding: 4px 6px 1px 6px;
 }
 
 .tab-bottom[beforeselected="true"]:-moz-locale-dir(ltr),
-.tab-bottom[selected="true"]:-moz-locale-dir(rtl) + .tab-bottom {
+.tab-bottom[visuallyselected="true"]:-moz-locale-dir(rtl) + .tab-bottom {
   border-bottom-right-radius: 0;
 }
 
-.tab-bottom[selected="true"]:-moz-locale-dir(ltr) + .tab-bottom,
+.tab-bottom[visuallyselected="true"]:-moz-locale-dir(ltr) + .tab-bottom,
 .tab-bottom[beforeselected="true"]:-moz-locale-dir(rtl) {
   border-bottom-left-radius: 0;
 }
 
 /* ::::: tabs-bottom ::::: */
 
 .tabs-bottom > .tabs-left,
 .tabs-bottom > .tabs-right {
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -3522,16 +3522,17 @@ nsNativeThemeCocoa::WidgetStateChanged(n
     *aShouldRepaint = true;
   } else {
     // Check the attribute to see if it's relevant.  
     // disabled, checked, dlgtype, default, etc.
     *aShouldRepaint = false;
     if (aAttribute == nsGkAtoms::disabled ||
         aAttribute == nsGkAtoms::checked ||
         aAttribute == nsGkAtoms::selected ||
+        aAttribute == nsGkAtoms::visuallyselected ||
         aAttribute == nsGkAtoms::menuactive ||
         aAttribute == nsGkAtoms::sortDirection ||
         aAttribute == nsGkAtoms::focused ||
         aAttribute == nsGkAtoms::_default ||
         aAttribute == nsGkAtoms::open ||
         aAttribute == nsGkAtoms::hover)
       *aShouldRepaint = true;
 
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -1349,16 +1349,17 @@ nsNativeThemeGTK::WidgetStateChanged(nsI
   }
   else {
     // Check the attribute to see if it's relevant.  
     // disabled, checked, dlgtype, default, etc.
     *aShouldRepaint = false;
     if (aAttribute == nsGkAtoms::disabled ||
         aAttribute == nsGkAtoms::checked ||
         aAttribute == nsGkAtoms::selected ||
+        aAttribute == nsGkAtoms::visuallyselected ||
         aAttribute == nsGkAtoms::focused ||
         aAttribute == nsGkAtoms::readonly ||
         aAttribute == nsGkAtoms::_default ||
         aAttribute == nsGkAtoms::menuactive ||
         aAttribute == nsGkAtoms::open ||
         aAttribute == nsGkAtoms::parentfocused)
       *aShouldRepaint = true;
   }
--- a/widget/nsNativeTheme.h
+++ b/widget/nsNativeTheme.h
@@ -85,17 +85,17 @@ class nsNativeTheme : public nsITimerCal
     return CheckBooleanAttr(aFrame, nsGkAtoms::focused);
   }
 
   // scrollbar button:
   int32_t GetScrollbarButtonType(nsIFrame* aFrame);
 
   // tab:
   bool IsSelectedTab(nsIFrame* aFrame) {
-    return CheckBooleanAttr(aFrame, nsGkAtoms::selected);
+    return CheckBooleanAttr(aFrame, nsGkAtoms::visuallyselected);
   }
   
   bool IsNextToSelectedTab(nsIFrame* aFrame, int32_t aOffset);
   
   bool IsBeforeSelectedTab(nsIFrame* aFrame) {
     return IsNextToSelectedTab(aFrame, -1);
   }
   
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -2568,16 +2568,17 @@ nsNativeThemeWin::WidgetStateChanged(nsI
   }
   else {
     // Check the attribute to see if it's relevant.  
     // disabled, checked, dlgtype, default, etc.
     *aShouldRepaint = false;
     if (aAttribute == nsGkAtoms::disabled ||
         aAttribute == nsGkAtoms::checked ||
         aAttribute == nsGkAtoms::selected ||
+        aAttribute == nsGkAtoms::visuallyselected ||
         aAttribute == nsGkAtoms::readonly ||
         aAttribute == nsGkAtoms::open ||
         aAttribute == nsGkAtoms::menuactive ||
         aAttribute == nsGkAtoms::focused)
       *aShouldRepaint = true;
   }
 
   return NS_OK;