Merge fx-team to m-c on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 14 Nov 2013 22:19:19 -0500
changeset 169413 b2fab608772f4d8cc243be416638f54e38e4eb00
parent 169408 1e1b514a0f4b4c3193999302e22cebbf950c26f8 (current diff)
parent 169412 e8dbe7aabcc898f3b8da44a8da692414c276bf0a (diff)
child 169415 1700e4435553ac17ac56da22a3ae6ec5840723b9
child 169478 c3d8ec0e53c776ba316f27f55a30e977fe4d4cdb
child 177500 1e18bf475edb08f1ef365caacdd84b063981cc5f
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
b2fab608772f / 28.0a1 / 20131115030203 / files
nightly linux64
b2fab608772f / 28.0a1 / 20131115030203 / files
nightly mac
b2fab608772f / 28.0a1 / 20131115030203 / files
nightly win32
b2fab608772f / 28.0a1 / 20131115030203 / files
nightly win64
b2fab608772f / 28.0a1 / 20131115030203 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge fx-team to m-c on a CLOSED TREE.
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -399,17 +399,18 @@ SourcesView.prototype = Heritage.extend(
     if (gThreadClient.source(source).isPrettyPrinted) {
       this._prettyPrintButton.removeAttribute("checked");
     } else {
       this._prettyPrintButton.setAttribute("checked", true);
     }
 
     DebuggerController.SourceScripts.togglePrettyPrint(source)
       .then(resetEditor, printError)
-      .then(DebuggerView.showEditor);
+      .then(DebuggerView.showEditor)
+      .then(this.updateToolbarButtonsState);
   },
 
   /**
    * Marks a breakpoint as selected in this sources container.
    *
    * @param object aItem
    *        The breakpoint item to select.
    */
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -123,16 +123,17 @@ skip-if = true
 [browser_dbg_pretty-print-04.js]
 [browser_dbg_pretty-print-05.js]
 [browser_dbg_pretty-print-06.js]
 [browser_dbg_pretty-print-07.js]
 [browser_dbg_pretty-print-08.js]
 [browser_dbg_pretty-print-09.js]
 [browser_dbg_pretty-print-10.js]
 [browser_dbg_pretty-print-11.js]
+[browser_dbg_pretty-print-12.js]
 [browser_dbg_progress-listener-bug.js]
 [browser_dbg_reload-preferred-script-01.js]
 [browser_dbg_reload-preferred-script-02.js]
 [browser_dbg_reload-preferred-script-03.js]
 [browser_dbg_reload-same-script.js]
 [browser_dbg_scripts-switching-01.js]
 [browser_dbg_scripts-switching-02.js]
 [browser_dbg_scripts-switching-03.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-12.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that we don't leave the pretty print button checked when we fail to
+ * pretty print a source (because it isn't a JS file, for example).
+ */
+
+const TAB_URL = EXAMPLE_URL + "doc_blackboxing.html";
+
+let gTab, gDebuggee, gPanel, gDebugger;
+let gEditor, gSources;
+
+function test() {
+  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPanel = aPanel;
+    gDebugger = gPanel.panelWin;
+    gEditor = gDebugger.DebuggerView.editor;
+    gSources = gDebugger.DebuggerView.Sources;
+
+    waitForSourceShown(gPanel, "")
+      .then(() => {
+        let shown = ensureSourceIs(gPanel, TAB_URL, true)
+        gSources.selectedValue = TAB_URL;
+        return shown;
+      })
+      .then(clickPrettyPrintButton)
+      .then(testButtonIsntChecked)
+      .then(() => closeDebuggerAndFinish(gPanel))
+      .then(null, aError => {
+        ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
+      });
+  });
+}
+
+function clickPrettyPrintButton() {
+  gDebugger.document.getElementById("pretty-print").click();
+}
+
+function testButtonIsntChecked() {
+  is(gDebugger.document.getElementById("pretty-print").checked, false,
+     "The button shouldn't be checked after trying to pretty print a non-js file.");
+}
+
+registerCleanupFunction(function() {
+  gTab = null;
+  gDebuggee = null;
+  gPanel = null;
+  gDebugger = null;
+  gEditor = null;
+  gSources = null;
+});
--- a/browser/metro/base/content/ContextCommands.js
+++ b/browser/metro/base/content/ContextCommands.js
@@ -165,19 +165,18 @@ var ContextCommands = {
     aRichListItem.childNodes[0].setAttribute("value", "");
     aRichListItem.setAttribute("searchString", "");
     BrowserUI.addAndShowTab(defaultURI, Browser.selectedTab);
   },
 
   // Link specific
 
   openLinkInNewTab: function cc_openLinkInNewTab() {
-    let tab = Browser.addTab(ContextMenuUI.popupState.linkURL, false, Browser.selectedTab);
-    ContextUI.peekTabs(kOpenInNewTabAnimationDelayMsec);
-    Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab);
+    let url = ContextMenuUI.popupState.linkURL;
+    BrowserUI.openLinkInNewTab(url, false, Browser.selectedTab);
   },
 
   copyLink: function cc_copyLink() {
     this.clipboard.copyString(ContextMenuUI.popupState.linkURL,
                               this.docRef);
   },
 
   bookmarkLink: function cc_bookmarkLink() {
--- a/browser/metro/base/content/ContextUI.js
+++ b/browser/metro/base/content/ContextUI.js
@@ -156,17 +156,17 @@ var ContextUI = {
 
     ContextUI.dismissTabsWithDelay(aDelay);
   },
 
   /*
    * Dismiss tab bar after a delay. Fires context ui events.
    */
   dismissTabsWithDelay: function (aDelay) {
-    aDelay = aDelay || kNewTabAnimationDelayMsec;
+    aDelay = aDelay || kForegroundTabAnimationDelay;
     this._clearDelayedTimeout();
     this._hidingId = setTimeout(function () {
         ContextUI.dismissTabs();
       }, aDelay);
   },
 
   // Display the nav bar
   displayNavbar: function () {
--- a/browser/metro/base/content/apzc.js
+++ b/browser/metro/base/content/apzc.js
@@ -34,16 +34,19 @@ var APZCObserver = {
     Elements.tabList.addEventListener("TabSelect", this, true);
     Elements.tabList.addEventListener("TabOpen", this, true);
     Elements.tabList.addEventListener("TabClose", this, true);
   },
 
   handleEvent: function APZC_handleEvent(aEvent) {
     switch (aEvent.type) {
       case 'pageshow':
+        if (aEvent.target != Browser.selectedBrowser.contentDocument)
+          break;
+        // fall through to TabSelect:
       case 'TabSelect':
         // ROOT_ID doesn't really identify the view we want. When we call
         // this on a content document (tab),  findElementWithViewId will
         // always return the root content document associated with the
         // scrollable frame.
         const ROOT_ID = 1;
         let windowUtils = Browser.selectedBrowser.contentWindow.
                           QueryInterface(Ci.nsIInterfaceRequestor).
--- a/browser/metro/base/content/browser-scripts.js
+++ b/browser/metro/base/content/browser-scripts.js
@@ -61,16 +61,19 @@ XPCOMUtils.defineLazyServiceGetter(windo
                                    "@mozilla.org/docshell/urifixup;1",
                                    "nsIURIFixup");
 XPCOMUtils.defineLazyServiceGetter(window, "gFaviconService",
                                    "@mozilla.org/browser/favicon-service;1",
                                    "nsIFaviconService");
 XPCOMUtils.defineLazyServiceGetter(window, "gFocusManager",
                                    "@mozilla.org/focus-manager;1",
                                    "nsIFocusManager");
+XPCOMUtils.defineLazyServiceGetter(window, "gEventListenerService",
+                                   "@mozilla.org/eventlistenerservice;1",
+                                   "nsIEventListenerService");
 #ifdef MOZ_CRASHREPORTER
 XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
                                    "@mozilla.org/xre/app-info;1",
                                    "nsICrashReporter");
 #endif
 
 /*
  * window.Rect is used by
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -9,22 +9,22 @@ Cu.import("resource://gre/modules/devtoo
 /**
  * Constants
  */
 
 // Devtools Messages
 const debugServerStateChanged = "devtools.debugger.remote-enabled";
 const debugServerPortChanged = "devtools.debugger.remote-port";
 
-// delay when showing the tab bar briefly after a new (empty) tab opens
-const kNewTabAnimationDelayMsec = 1000;
-// delay when showing the tab bar after opening a link on a new tab
-const kOpenInNewTabAnimationDelayMsec = 3000;
-// delay before closing tab bar after selecting another tab
-const kSelectTabAnimationDelayMsec = 500;
+// delay when showing the tab bar briefly after a new foreground tab opens
+const kForegroundTabAnimationDelay = 1000;
+// delay when showing the tab bar after opening a new background tab opens
+const kBackgroundTabAnimationDelay = 3000;
+// delay before closing tab bar after closing or selecting a tab
+const kChangeTabAnimationDelay = 500;
 
 /**
  * Cache of commonly used elements.
  */
 
 let Elements = {};
 [
   ["contentShowing",     "bcast_contentShowing"],
@@ -168,24 +168,31 @@ var BrowserUI = {
         if (name != "process")
           Services.console.logStringMessage("[timing] " + name + ": " + (startup[name] - startup.process) + "ms");
       }
     }, 3000);
 #endif
   },
 
   uninit: function() {
+    messageManager.removeMessageListener("DOMTitleChanged", this);
+    messageManager.removeMessageListener("DOMWillOpenModalDialog", this);
+    messageManager.removeMessageListener("DOMWindowClose", this);
+
+    messageManager.removeMessageListener("Browser:OpenURI", this);
+    messageManager.removeMessageListener("Browser:SaveAs:Return", this);
+    messageManager.removeMessageListener("Content:StateChange", this);
+
     messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps);
     Services.obs.removeObserver(this, "handle-xul-text-link");
 
     PanelUI.uninit();
     FlyoutPanelsUI.uninit();
     MetroDownloadsView.uninit();
     SettingsCharm.uninit();
-    messageManager.removeMessageListener("Content:StateChange", this);
     PageThumbs.uninit();
     this.stopDebugServer();
   },
 
   /************************************
    * Devtools Debugger
    */
   runDebugServer: function runDebugServer(aPort) {
@@ -431,20 +438,35 @@ var BrowserUI = {
    * Tab management
    */
 
   /**
    * Open a new tab in the foreground in response to a user action.
    * See Browser.addTab for more documentation.
    */
   addAndShowTab: function (aURI, aOwner) {
-    ContextUI.peekTabs(kNewTabAnimationDelayMsec);
+    ContextUI.peekTabs(kForegroundTabAnimationDelay);
     return Browser.addTab(aURI || kStartURI, true, aOwner);
   },
 
+  /**
+   * Open a new tab in response to clicking a link in an existing tab.
+   * See Browser.addTab for more documentation.
+   */
+  openLinkInNewTab: function (aURI, aBringFront, aOwner) {
+    ContextUI.peekTabs(aBringFront ? kForegroundTabAnimationDelay
+                                   : kBackgroundTabAnimationDelay);
+    let tab = Browser.addTab(aURI, aBringFront, aOwner, {
+      referrerURI: aOwner.browser.documentURI,
+      charset: aOwner.browser.characterSet,
+    });
+    Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab);
+    return tab;
+  },
+
   setOnTabAnimationEnd: function setOnTabAnimationEnd(aCallback) {
     Elements.tabs.addEventListener("animationend", function onAnimationEnd() {
       Elements.tabs.removeEventListener("animationend", onAnimationEnd);
       aCallback();
     });
   },
 
   closeTab: function closeTab(aTab) {
@@ -459,17 +481,17 @@ var BrowserUI = {
     let wasCollapsed = !ContextUI.tabbarVisible;
     if (wasCollapsed) {
       ContextUI.displayTabs();
     }
 
     this.setOnTabAnimationEnd(function() {
       Browser.closeTab(tabToClose, { forceClose: true } );
       if (wasCollapsed)
-        ContextUI.dismissTabsWithDelay(kNewTabAnimationDelayMsec);
+        ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
     });
   },
 
   /**
     * Re-open a closed tab.
     * @param aIndex
     *        The index of the tab (via nsSessionStore.getClosedTabData)
     * @returns a reference to the reopened tab.
@@ -501,17 +523,17 @@ var BrowserUI = {
   },
 
   selectTab: function selectTab(aTab) {
     Browser.selectedTab = aTab;
   },
 
   selectTabAndDismiss: function selectTabAndDismiss(aTab) {
     this.selectTab(aTab);
-    ContextUI.dismissTabsWithDelay(kSelectTabAnimationDelayMsec);
+    ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
   },
 
   selectTabAtIndex: function selectTabAtIndex(aIndex) {
     // count backwards for aIndex < 0
     if (aIndex < 0)
       aIndex += Browser._tabs.length;
 
     if (aIndex >= 0 && aIndex < Browser._tabs.length)
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -74,16 +74,17 @@ var Browser = {
     Elements.browsers.customDragger = new Browser.MainDragger();
 
     /* handles web progress management for open browsers */
     Elements.browsers.webProgress = WebProgress.init();
 
     // Call InputSourceHelper first so global listeners get called before
     // we start processing input in TouchModule.
     InputSourceHelper.init();
+    ClickEventHandler.init();
 
     TouchModule.init();
     GestureModule.init();
     BrowserTouchHandler.init();
     PopupBlockerObserver.init();
     APZCObserver.init();
 
     // Init the touch scrollbox
@@ -208,16 +209,17 @@ var Browser = {
       event.initEvent("UIReady", true, false);
       window.dispatchEvent(event);
     }.bind(this));
   },
 
   shutdown: function shutdown() {
     APZCObserver.shutdown();
     BrowserUI.uninit();
+    ClickEventHandler.uninit();
     ContentAreaObserver.shutdown();
     Appbar.shutdown();
 
     messageManager.removeMessageListener("Browser:FormSubmit", this);
     messageManager.removeMessageListener("scroll", this);
     messageManager.removeMessageListener("Browser:CertException", this);
     messageManager.removeMessageListener("Browser:BlockedSite", this);
     messageManager.removeMessageListener("Browser:TapOnSelection", this);
@@ -480,17 +482,17 @@ var Browser = {
       this._tabs.splice(params.index, 0, newTab);
     } else {
       this._tabs.push(newTab);
     }
 
     if (aBringFront)
       this.selectedTab = newTab;
 
-    this._announceNewTab(newTab, params, aBringFront);
+    this._announceNewTab(newTab);
     return newTab;
   },
 
   closeTab: function closeTab(aTab, aOptions) {
     let tab = aTab instanceof XULElement ? this.getTabFromChrome(aTab) : aTab;
     if (!tab) {
       return;
     }
@@ -506,17 +508,17 @@ var Browser = {
   savePage: function() {
     ContentAreaUtils.saveDocument(this.selectedBrowser.contentWindow.document);
   },
 
   /*
    * helper for addTab related methods. Fires events related to
    * new tab creation.
    */
-  _announceNewTab: function _announceNewTab(aTab, aParams, aBringFront) {
+  _announceNewTab: function (aTab) {
     let event = document.createEvent("UIEvents");
     event.initUIEvent("TabOpen", true, false, window, 0);
     aTab.chromeTab.dispatchEvent(event);
     aTab.browser.messageManager.sendAsyncMessage("Browser:TabOpen");
   },
 
   _doCloseTab: function _doCloseTab(aTab) {
     if (this._tabs.length === 1) {
@@ -1069,22 +1071,17 @@ nsBrowserAccess.prototype = {
     let browser;
     let loadflags = isExternal ?
                       Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
                       Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
     let openAction = this._getOpenAction(aURI, aOpener, aWhere, aContext);
 
     if (openAction == Ci.nsIBrowserDOMWindow.OPEN_NEWTAB) {
       let owner = isExternal ? null : Browser.selectedTab;
-      let tab = Browser.addTab("about:blank", true, owner);
-      // Link clicks in content need to trigger peek tab functionality
-      ContextUI.peekTabs(kOpenInNewTabAnimationDelayMsec);
-      if (isExternal) {
-        tab.closeOnExit = true;
-      }
+      let tab = BrowserUI.openLinkInNewTab("about:blank", true, owner);
       browser = tab.browser;
     } else {
       browser = Browser.selectedBrowser;
     }
 
     try {
       let referrer;
       if (aURI && browser) {
@@ -1575,8 +1572,73 @@ function rendererFactory(aBrowser, aCanv
     };
     wrapper.drawContent = function(callback) {
       callback(ctx, draw);
     };
   }
 
   return wrapper;
 };
+
+// Based on ClickEventHandler from /browser/base/content/content.js
+let ClickEventHandler = {
+  init: function () {
+    gEventListenerService.addSystemEventListener(Elements.browsers, "click", this, true);
+  },
+
+  uninit: function () {
+    gEventListenerService.removeSystemEventListener(Elements.browsers, "click", this, true);
+  },
+
+  handleEvent: function (aEvent) {
+    if (!aEvent.isTrusted || aEvent.defaultPrevented) {
+      return;
+    }
+    let [href, node] = this._hrefAndLinkNodeForClickEvent(aEvent);
+    if (href && (aEvent.button == 1 || aEvent.ctrlKey)) {
+      // Open link in a new tab for middle-click or ctrl-click
+      BrowserUI.openLinkInNewTab(href, aEvent.shiftKey, Browser.selectedTab);
+    }
+  },
+
+  /**
+   * Extracts linkNode and href for the current click target.
+   *
+   * @param event
+   *        The click event.
+   * @return [href, linkNode].
+   *
+   * @note linkNode will be null if the click wasn't on an anchor
+   *       element (or XLink).
+   */
+  _hrefAndLinkNodeForClickEvent: function(event) {
+    function isHTMLLink(aNode) {
+      return ((aNode instanceof content.HTMLAnchorElement && aNode.href) ||
+              (aNode instanceof content.HTMLAreaElement && aNode.href) ||
+              aNode instanceof content.HTMLLinkElement);
+    }
+
+    let node = event.target;
+    while (node && !isHTMLLink(node)) {
+      node = node.parentNode;
+    }
+
+    if (node)
+      return [node.href, node];
+
+    // If there is no linkNode, try simple XLink.
+    let href, baseURI;
+    node = event.target;
+    while (node && !href) {
+      if (node.nodeType == content.Node.ELEMENT_NODE) {
+        href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
+        if (href)
+          baseURI = node.ownerDocument.baseURIObject;
+      }
+      node = node.parentNode;
+    }
+
+    // In case of XLink, we don't return the node we got href from since
+    // callers expect <a>-like elements.
+    // Note: makeURI() will throw if aUri is not a valid URI.
+    return [href ? Services.io.newURI(href, null, baseURI).spec : null, null];
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/mochitest/browser_link_click.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>link click test</title>
+  </head>
+  <body>
+    <a id="link" href="about:blank">link</a>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/mochitest/browser_link_click.js
@@ -0,0 +1,97 @@
+/* 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/. */
+"use strict";
+
+function test() {
+  waitForExplicitFinish();
+  runTests();
+}
+
+gTests.push({
+  desc: "regular link click",
+  run: function () {
+    let tab = yield addTab(chromeRoot + "browser_link_click.html");
+    let tabCount = Browser.tabs.length;
+
+    EventUtils.sendMouseEvent({type: "click"}, "link", tab.browser.contentWindow);
+    yield waitForCondition(() => tab.browser.currentURI.spec == "about:blank");
+    is(Browser.tabs.length, tabCount, "link loaded in the same tab");
+  }
+});
+
+gTests.push({
+  desc: "middle-click opens link in background tab",
+  run: function () {
+    let tab = yield addTab(chromeRoot + "browser_link_click.html");
+
+    let tabOpen = waitForEvent(window, "TabOpen");
+    EventUtils.sendMouseEvent({type: "click", button: 1}, "link", tab.browser.contentWindow);
+    let event = yield tabOpen;
+
+    let newTab = Browser.getTabFromChrome(event.originalTarget);
+    yield waitForEvent(newTab.browser, "pageshow");
+
+    is(newTab.browser.currentURI.spec, "about:blank");
+    ok(newTab != Browser.selectedTab, "new tab is in the background");
+
+    Browser.closeTab(newTab, { forceClose: true });
+  }
+});
+
+gTests.push({
+  desc: "shift-middle-click opens link in background tab",
+  run: function () {
+    let tab = yield addTab(chromeRoot + "browser_link_click.html");
+
+    let tabOpen = waitForEvent(window, "TabOpen");
+    EventUtils.sendMouseEvent({type: "click", button: 1, shiftKey: true}, "link", tab.browser.contentWindow);
+    let event = yield tabOpen;
+
+    let newTab = Browser.getTabFromChrome(event.originalTarget);
+    yield waitForEvent(newTab.browser, "pageshow");
+
+    is(newTab.browser.currentURI.spec, "about:blank");
+    ok(newTab == Browser.selectedTab, "new tab is in the foreground");
+
+    Browser.closeTab(newTab, { forceClose: true });
+  }
+});
+
+gTests.push({
+  desc: "ctrl-click opens link in background tab",
+  run: function () {
+    let tab = yield addTab(chromeRoot + "browser_link_click.html");
+
+    let tabOpen = waitForEvent(window, "TabOpen");
+    EventUtils.sendMouseEvent({type: "click", ctrlKey: true}, "link", tab.browser.contentWindow);
+    let event = yield tabOpen;
+
+    let newTab = Browser.getTabFromChrome(event.originalTarget);
+    yield waitForEvent(newTab.browser, "pageshow");
+
+    is(newTab.browser.currentURI.spec, "about:blank");
+    ok(newTab != Browser.selectedTab, "new tab is in the background");
+
+    Browser.closeTab(newTab, { forceClose: true });
+  }
+});
+
+gTests.push({
+  desc: "shift-ctrl-click opens link in background tab",
+  run: function () {
+    let tab = yield addTab(chromeRoot + "browser_link_click.html");
+
+    let tabOpen = waitForEvent(window, "TabOpen");
+    EventUtils.sendMouseEvent({type: "click", ctrlKey: true, shiftKey: true}, "link", tab.browser.contentWindow);
+    let event = yield tabOpen;
+
+    let newTab = Browser.getTabFromChrome(event.originalTarget);
+    yield waitForEvent(newTab.browser, "pageshow");
+
+    is(newTab.browser.currentURI.spec, "about:blank");
+    ok(newTab == Browser.selectedTab, "new tab is in the foreground");
+
+    Browser.closeTab(newTab, { forceClose: true });
+  }
+});
--- a/browser/metro/base/tests/mochitest/metro.ini
+++ b/browser/metro/base/tests/mochitest/metro.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 support-files =
   browser_context_menu_tests_01.html
   browser_context_menu_tests_02.html
   browser_context_menu_tests_03.html
   browser_context_menu_tests_04.html
   browser_findbar.html
   browser_form_auto_complete.html
+  browser_link_click.html
   browser_onscreen_keyboard.html
   browser_progress_indicator.xul
   browser_selection_basic.html
   browser_selection_caretfocus.html
   browser_selection_contenteditable.html
   browser_selection_frame_content.html
   browser_selection_frame_inputs.html
   browser_selection_frame_textarea.html
@@ -37,16 +38,17 @@ support-files =
 [browser_crashprompt.js]
 [browser_context_menu_tests.js]
 [browser_context_ui.js]
 [browser_downloads.js]
 [browser_findbar.js]
 [browser_form_auto_complete.js]
 [browser_history.js]
 [browser_inputsource.js]
+[browser_link_click.js]
 [browser_onscreen_keyboard.js]
 [browser_prefs_ui.js]
 [browser_remotetabs.js]
 [browser_snappedState.js]
 [browser_tabs.js]
 [browser_test.js]
 [browser_tiles.js]
 [browser_topsites.js]
--- a/mobile/android/themes/core/content.css
+++ b/mobile/android/themes/core/content.css
@@ -301,10 +301,10 @@ select[disabled] > button {
 *[role=button]:active,
 button:not([disabled]):active,
 input:not([disabled]):active,
 select:not([disabled]):active,
 textarea:not([disabled]):active,
 option:active,
 label:active,
 xul|menulist:active {
-  background-color: @color_background_highlight_overlay@ !important;
+  background-color: @color_background_highlight_overlay@;
 }