Merge m-c to b-i
authorPhil Ringnalda <philringnalda@gmail.com>
Thu, 27 Nov 2014 22:36:36 -0800
changeset 217955 d9fb4a6a3c5a3ca84d65aa770c3f23a3b3fc929f
parent 217954 71da97c6ca1d429f59e3905f0b8dfbfa1251fc1a (current diff)
parent 217926 1162e4a4d7a2ba784392f7812b4aeb1e23a1d5ba (diff)
child 217956 a54773075295edbe6d9b562c1a484320a4f8a750
push id27900
push usercbook@mozilla.com
push dateFri, 28 Nov 2014 12:44:44 +0000
treeherderautoland@ca89fe557170 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone36.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
Merge m-c to b-i
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -424,16 +424,19 @@ pref("browser.search.suggest.enabled", t
 
 pref("browser.search.showOneOffButtons", true);
 
 #ifdef MOZ_OFFICIAL_BRANDING
 // {moz:official} expands to "official"
 pref("browser.search.official", true);
 #endif
 
+// How many times to show the new search highlight
+pref("browser.search.highlightCount", 5);
+
 pref("browser.sessionhistory.max_entries", 50);
 
 // handle links targeting new windows
 // 1=current window/tab, 2=new window, 3=new tab in most recent window
 pref("browser.link.open_newwindow", 3);
 
 // handle external links (i.e. links opened from a different application)
 // default: use browser.link.open_newwindow
--- a/browser/base/content/browser-doctype.inc
+++ b/browser/base/content/browser-doctype.inc
@@ -14,10 +14,12 @@
 <!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
 %placesDTD;
 #ifdef MOZ_SAFE_BROWSING
 <!ENTITY % safebrowsingDTD SYSTEM "chrome://browser/locale/safebrowsing/phishing-afterload-warning-message.dtd">
 %safebrowsingDTD;
 #endif
 <!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
 %aboutHomeDTD;
+<!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd">
+%searchBarDTD;
 ]>
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1392,16 +1392,17 @@ var gBrowserInit = {
         return;
       }
 
       // Enable the Restore Last Session command if needed
       RestoreLastSessionObserver.init();
 
       SocialUI.init();
       TabView.init();
+      SearchHighlight.init();
 
       // Telemetry for master-password - we do this after 5 seconds as it
       // can cause IO if NSS/PSM has not already initialized.
       setTimeout(() => {
         if (window.closed) {
           return;
         }
         let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
@@ -3553,16 +3554,148 @@ const BrowserSearch = {
 
     let countId = this._getSearchEngineId(engine) + "." + source;
 
     let count = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
     count.add(countId);
   },
 };
 
+const SearchHighlight = {
+  eventsReady: false,
+  // The pref that controls how many times to show the highlight.
+  countPref: "browser.search.highlightCount",
+  // The current highlight to show.
+  currentPos: 0,
+  // Tracks if the popup closed very recently.
+  hideTimer: null,
+
+  // The list of highlights and the items in the panel to anchor them to.
+  highlights: [{
+    id: "SearchHighlight1",
+    anchor: "search-panel-one-offs"
+  }, {
+    id: "SearchHighlight2",
+    anchor: "searchbar-engine",
+  }],
+
+  init: function() {
+    this.panel = document.getElementById("PopupSearchAutoComplete");
+    this.panel.addEventListener("popupshowing", this.searchPanelShown.bind(this), false);
+  },
+
+  initEvents: function() {
+    if (this.eventsReady) {
+      return;
+    }
+
+    this.panel.addEventListener("popuphidden", this.searchPanelHidden.bind(this), false);
+
+    for (let highlight of this.highlights) {
+      highlight.panel = document.getElementById(highlight.id);
+      highlight.panel.addEventListener("popupshowing", this.disablePanelHiding.bind(this), false);
+      highlight.panel.addEventListener("popuphiding", this.enablePanelHiding.bind(this), false);
+
+      highlight.panel.querySelector("button").addEventListener("command", this.highlightButtonClicked.bind(this), false);
+    }
+
+    this.eventsReady = true;
+  },
+
+  get highlightPanel() {
+    return this.highlights[this.currentPos].panel;
+  },
+
+  showHighlight: function() {
+    // Check that all the events are setup.
+    this.initEvents();
+
+    // If a highlight is already showing then do nothing.
+    if (this.highlightPanel.state != "closed") {
+      return;
+    }
+
+    // Show the first highlight.
+    this.currentPos = 0;
+    this.showCurrentHighlight();
+  },
+
+  showCurrentHighlight: function() {
+    let highlight = this.highlights[this.currentPos];
+    let anchor = document.getAnonymousElementByAttribute(this.panel, "anonid", highlight.anchor);
+    highlight.panel.hidden = false;
+    highlight.panel.openPopup(anchor, "leftcenter topright");
+  },
+
+  searchPanelShown: function() {
+    let placement = CustomizableUI.getPlacementOfWidget("search-container");
+    if (placement.area == CustomizableUI.AREA_PANEL) {
+      // Opening a panel anchored to a panel anchored to a panel anchored to the
+      // window doesn't work very well
+      return;
+    }
+
+    if (!BrowserSearch.searchBar.value) {
+      // Don't show the panels when there is no text in the search box
+      return;
+    }
+
+    // If the panel was only very recently closed re-show the last highlight.
+    if (this.hideTimer) {
+      clearTimeout(this.hideTimer);
+      this.hideTimer = null;
+      this.showCurrentHighlight();
+      return;
+    }
+
+    // If the highlight has already been show the appropriate number of times
+    // do nothing.
+    let count = Services.prefs.getIntPref(this.countPref);
+    if (count <= 0)
+      return;
+
+    this.showHighlight();
+    Services.prefs.setIntPref(this.countPref, count - 1);
+  },
+
+  searchPanelHidden: function() {
+    if (this.highlightPanel.state == "closed") {
+      return;
+    }
+
+    this.highlightPanel.hidePopup();
+
+    // Set a flag when the panel was closed in the last short time.
+    this.hideTimer = setTimeout(() => {
+      this.hideTimer = null;
+    }, 500);
+  },
+
+  highlightButtonClicked: function() {
+    // When the button is clicked close the current highlight and open the next
+    // one.
+    this.highlightPanel.hidePopup();
+    this.currentPos++;
+    if (this.currentPos < this.highlights.length) {
+      this.showCurrentHighlight();
+    } else {
+      Services.prefs.setIntPref(this.countPref, 0);
+      this.currentPos = 0;
+    }
+  },
+
+  disablePanelHiding: function() {
+    this.panel.setAttribute("noautohide", "true");
+  },
+
+  enablePanelHiding: function() {
+    this.panel.setAttribute("noautohide", "false");
+  },
+};
+
 function FillHistoryMenu(aParent) {
   // Lazily add the hover listeners on first showing and never remove them
   if (!aParent.hasStatusListener) {
     // Show history item's uri in the status bar when hovering, and clear on exit
     aParent.addEventListener("DOMMenuItemActive", function(aEvent) {
       // Only the current page should have the checked attribute, so skip it
       if (!aEvent.target.hasAttribute("checked"))
         XULBrowserWindow.setOverLink(aEvent.target.getAttribute("uri"));
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -235,16 +235,51 @@
            hidden="true"
            noautofocus="true"
            noautohide="true"
            flip="none"
            consumeoutsideclicks="false"
            mousethrough="always">
       <box id="UITourHighlight"></box>
     </panel>
+    <!-- Used to highlight the new search experience -->
+    <panel id="SearchHighlight1"
+           class="SearchHighlight"
+           type="arrow"
+           hidden="true"
+           noautofocus="true"
+           noautohide="true"
+           orient="vertical"
+           align="stretch">
+      <label class="SearchHighlightTitle">&SearchHighlight1.title;</label>
+      <description class="SearchHighlightText" flex="1">&SearchHighlight1.text;</description>
+      <hbox class="SearchHighlightFooter" align="center">
+        <spacer class="dot filled"/>
+        <spacer class="dot"/>
+        <spacer flex="1"/>
+        <button label="&SearchHighlightNext;"/>
+      </hbox>
+    </panel>
+    <panel id="SearchHighlight2"
+           class="SearchHighlight"
+           type="arrow"
+           hidden="true"
+           noautofocus="true"
+           noautohide="true"
+           orient="vertical"
+           align="stretch">
+      <label class="SearchHighlightTitle">&SearchHighlight2.title;</label>
+      <description class="SearchHighlightText" flex="1">&SearchHighlight2.text;</description>
+      <hbox class="SearchHighlightFooter" align="center">
+        <spacer class="dot"/>
+        <spacer class="dot filled"/>
+        <spacer flex="1"/>
+        <button label="&SearchHighlightClose;"/>
+      </hbox>
+    </panel>
 
     <panel id="social-share-panel"
            class="social-panel"
            type="arrow"
            orient="horizontal"
            onpopupshowing="SocialShare.onShowing()"
            onpopuphidden="SocialShare.onHidden()"
            hidden="true">
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -395,16 +395,18 @@ skip-if = true  # disabled until the tre
 [browser_save_link-perwindowpb.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
 [browser_save_private_link_perwindowpb.js]
 skip-if = buildapp == 'mulet' || e10s # e10s: Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
 [browser_save_video.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 1100698 - test uses synthesizeMouse and then does a load of other stuff that breaks in e10s
 [browser_save_video_frame.js]
 [browser_scope.js]
+[browser_searchHighlight.js]
+skip-if = true
 [browser_searchSuggestionUI.js]
 skip-if = e10s
 support-files =
   searchSuggestionUI.html
   searchSuggestionUI.js
 [browser_selectTabAtIndex.js]
 [browser_star_hsts.js]
 [browser_subframe_favicons_not_used.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_searchHighlight.js
@@ -0,0 +1,260 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+const PREF = "browser.search.highlightCount";
+
+const searchBar = BrowserSearch.searchBar;
+const popup = document.getElementById("PopupSearchAutoComplete");
+const panel1 = document.getElementById("SearchHighlight1");
+const panel2 = document.getElementById("SearchHighlight2");
+
+let current = Services.prefs.getIntPref(PREF);
+registerCleanupFunction(() => {
+  Services.prefs.setIntPref(PREF, current);
+});
+
+// The highlight panel should be displayed a set number of times
+add_task(function* firstrun() {
+  yield promiseNewEngine(TEST_ENGINE_BASENAME);
+
+  ok(searchBar, "got search bar");
+  if (!searchBar.getAttribute("oneoffui"))
+    return; // This tests the one-off UI
+  searchBar.value = "foo";
+  searchBar.focus();
+
+  Services.prefs.setIntPref(PREF, 2);
+
+  let promise = promiseWaitForEvent(panel1, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise
+  ok(true, "Saw panel 1 show");
+
+  is(Services.prefs.getIntPref(PREF), 1, "Should have counted this show");
+
+  promise = promiseWaitForEvent(panel1, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw panel 1 hide");
+
+  clearTimer();
+
+  promise = promiseWaitForEvent(panel1, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise
+  ok(true, "Saw panel 1 show");
+
+  is(Services.prefs.getIntPref(PREF), 0, "Should have counted this show");
+
+  promise = promiseWaitForEvent(panel1, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw panel 1 hide");
+
+  clearTimer();
+
+  function listener() {
+    ok(false, "Should not have seen the pane show");
+  }
+  panel1.addEventListener("popupshowing", listener, false);
+
+  promise = promiseWaitForEvent(popup, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise;
+  ok(true, "Saw popup show");
+
+  promise = promiseWaitForEvent(popup, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw popup hide");
+
+  panel1.removeEventListener("popupshowing", listener, false);
+
+  clearTimer();
+});
+
+// Completing the tour should stop the popup from showing again
+add_task(function* dismiss() {
+  ok(searchBar, "got search bar");
+  if (!searchBar.getAttribute("oneoffui"))
+    return; // This tests the one-off UI
+  searchBar.value = "foo";
+  searchBar.focus();
+
+  Services.prefs.setIntPref(PREF, 200);
+
+  let promise = promiseWaitForEvent(panel1, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise
+  ok(true, "Saw panel 1 show");
+
+  promise = promiseWaitForEvent(panel2, "popupshown");
+  EventUtils.synthesizeMouseAtCenter(panel1.querySelector("button"), {});
+  yield promise;
+  ok(true, "Saw panel 2 show");
+
+  promise = promiseWaitForEvent(panel2, "popuphidden");
+  EventUtils.synthesizeMouseAtCenter(panel2.querySelector("button"), {});
+  yield promise;
+  ok(true, "Saw panel 2 hide");
+
+  is(Services.prefs.getIntPref(PREF), 0, "Should have cleared the counter");
+
+  promise = promiseWaitForEvent(popup, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw popup hide");
+
+  clearTimer();
+
+  function listener() {
+    ok(false, "Should not have seen the pane show");
+  }
+  panel1.addEventListener("popupshowing", listener, false);
+
+  promise = promiseWaitForEvent(popup, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise;
+  ok(true, "Saw popup show");
+
+  promise = promiseWaitForEvent(popup, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw popup hide");
+
+  panel1.removeEventListener("popupshowing", listener, false);
+
+  clearTimer();
+});
+
+// The highlight panel should be re-displayed if the search popup closes and
+// opens quickly
+add_task(function* testRedisplay() {
+  ok(searchBar, "got search bar");
+  if (!searchBar.getAttribute("oneoffui"))
+    return; // This tests the one-off UI
+  searchBar.value = "foo";
+  searchBar.focus();
+
+  Services.prefs.setIntPref(PREF, 2);
+
+  let promise = promiseWaitForEvent(panel1, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise
+  ok(true, "Saw panel 1 show");
+
+  is(Services.prefs.getIntPref(PREF), 1, "Should have counted this show");
+
+  promise = promiseWaitForEvent(panel2, "popupshown");
+  EventUtils.synthesizeMouseAtCenter(panel1.querySelector("button"), {});
+  yield promise;
+  ok(true, "Saw panel 2 show");
+
+  promise = promiseWaitForEvent(panel2, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw panel 2 hide");
+
+  promise = promiseWaitForEvent(panel2, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise;
+  ok(true, "Saw panel 2 show");
+
+  is(Services.prefs.getIntPref(PREF), 1, "Should not have counted this show");
+
+  promise = promiseWaitForEvent(panel2, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw panel 2 hide");
+
+  clearTimer();
+});
+
+// The highlight panel shouldn't be displayed if there is no text in the search
+// box
+add_task(function* testNoText() {
+  ok(searchBar, "got search bar");
+  if (!searchBar.getAttribute("oneoffui"))
+    return; // This tests the one-off UI
+  searchBar.value = "";
+  searchBar.focus();
+
+  Services.prefs.setIntPref(PREF, 2);
+
+  function listener() {
+    ok(false, "Should not have seen the pane show");
+  }
+  panel1.addEventListener("popupshowing", listener, false);
+
+  let button = document.getAnonymousElementByAttribute(searchBar,
+                                                       "anonid",
+                                                       "searchbar-search-button");
+  let promise = promiseWaitForEvent(popup, "popupshown");
+  EventUtils.synthesizeMouseAtCenter(button, {});
+  yield promise;
+  ok(true, "Saw popup show");
+
+  promise = promiseWaitForEvent(popup, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw popup hide");
+
+  clearTimer();
+
+  promise = promiseWaitForEvent(popup, "popupshown");
+  EventUtils.synthesizeKey("VK_DOWN", {});
+  yield promise;
+  ok(true, "Saw popup show");
+
+  promise = promiseWaitForEvent(popup, "popuphidden");
+  EventUtils.synthesizeKey("VK_ESCAPE", {});
+  yield promise;
+  ok(true, "Saw popup hide");
+
+  panel1.removeEventListener("popupshowing", listener, false);
+
+  clearTimer();
+});
+
+function clearTimer() {
+  // Clear the timeout
+  clearTimeout(SearchHighlight.hideTimer);
+  SearchHighlight.hideTimer = null;
+}
+
+function promiseWaitForEvent(node, type, capturing) {
+  return new Promise((resolve) => {
+    node.addEventListener(type, function listener(event) {
+      node.removeEventListener(type, listener, capturing);
+      resolve(event);
+    }, capturing);
+  });
+}
+
+function promiseNewEngine(basename) {
+  return new Promise((resolve, reject) => {
+    info("Waiting for engine to be added: " + basename);
+    Services.search.init({
+      onInitComplete: function() {
+        let url = getRootDirectory(gTestPath) + basename;
+        let current = Services.search.currentEngine;
+        Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, {
+          onSuccess: function (engine) {
+            info("Search engine added: " + basename);
+            Services.search.currentEngine = engine;
+            registerCleanupFunction(() => {
+              Services.search.currentEngine = current;
+              Services.search.removeEngine(engine);
+            });
+            resolve(engine);
+          },
+          onError: function (errCode) {
+            ok(false, "addEngine failed with error code " + errCode);
+            reject();
+          },
+        });
+      }
+    });
+  });
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -952,17 +952,17 @@
   </binding>
 
   <!-- Note: this binding is applied to the autocomplete popup used in the Search bar -->
   <binding id="browser-search-autocomplete-result-popup" extends="chrome://browser/content/urlbarBindings.xml#browser-autocomplete-result-popup">
     <resources>
       <stylesheet src="chrome://browser/skin/searchbar.css"/>
     </resources>
     <content ignorekeys="true" level="top" consumeoutsideclicks="false">
-      <xul:hbox xbl:inherits="collapsed=showonlysettings"
+      <xul:hbox xbl:inherits="collapsed=showonlysettings" anonid="searchbar-engine"
                 class="search-panel-header search-panel-current-engine">
         <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
         <xul:label anonid="searchbar-engine-name" flex="1" crop="end"/>
       </xul:hbox>
       <xul:tree anonid="tree" flex="1"
                 class="autocomplete-tree plain search-panel-tree"
                 hidecolumnpicker="true" seltype="single">
         <xul:treecols anonid="treecols">
--- a/browser/locales/en-US/chrome/browser/searchbar.dtd
+++ b/browser/locales/en-US/chrome/browser/searchbar.dtd
@@ -1,6 +1,17 @@
 <!-- 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/. -->
 
 <!ENTITY cmd_engineManager.label        "Manage Search Engines…">
 <!ENTITY searchEndCap.label             "Search">
+
+<!-- LOCALIZATION NOTE: The SearchHighlight strings are used in the
+   - UITour popups that shows on first use of the new search panel. -->
+<!ENTITY SearchHighlight1.title "One-Click Searches">
+<!ENTITY SearchHighlight1.text "Search any of these sites instantly, without changing your default.">
+
+<!ENTITY SearchHighlight2.title "Smart Suggestions">
+<!ENTITY SearchHighlight2.text "Suggestions from your default search engine appear as you type.">
+
+<!ENTITY SearchHighlightNext "Next">
+<!ENTITY SearchHighlightClose "Thanks!">
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -22,16 +22,18 @@ browser.jar:
 #endif
   skin/classic/browser/aboutTabCrashed.css
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css
 * skin/classic/browser/devedition.css
 * skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
 * skin/classic/browser/content-contextmenu.svg
+  skin/classic/browser/dots.png                             (../shared/dots.png)
+  skin/classic/browser/dots@2x.png                          (../shared/dots@2x.png)
 * skin/classic/browser/engineManager.css
   skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -22,16 +22,18 @@ browser.jar:
   skin/classic/browser/aboutTabCrashed.css
   skin/classic/browser/actionicon-tab.png
   skin/classic/browser/actionicon-tab@2x.png
 * skin/classic/browser/browser.css                          (browser.css)
 * skin/classic/browser/devedition.css
 * skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
 * skin/classic/browser/content-contextmenu.svg
+  skin/classic/browser/dots.png                             (../shared/dots.png)
+  skin/classic/browser/dots@2x.png                          (../shared/dots@2x.png)
 * skin/classic/browser/engineManager.css                    (engineManager.css)
   skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-16@2x.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Geolocation-64@2x.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity@2x.png
--- a/browser/themes/shared/UITour.inc.css
+++ b/browser/themes/shared/UITour.inc.css
@@ -142,8 +142,56 @@
   color: white;
   padding-left: 30px;
   padding-right: 30px;
 }
 
 #UITourTooltipButtons > button.button-primary:not(:active):hover {
   background-color: rgb(105,173,61);
 }
+
+.SearchHighlight {
+  -moz-margin-end: 6px;
+  font-size: 110%;
+  width: 225px;
+}
+
+.SearchHighlight label,
+.SearchHighlight description {
+  color: #535353;
+  margin: 0 0 8px 0;
+  padding: 0;
+}
+
+.SearchHighlightTitle {
+  font-weight: bold;
+}
+
+.SearchHighlight .dot {
+  width: 7px;
+  height: 7px;
+  background-image: -moz-image-rect(url("chrome://browser/skin/dots.png"), 0, 100%, 100%, 9);
+  background-size: 7px;
+  background-position: center center;
+  background-repeat: no-repeat;
+  -moz-margin-end: 2px;
+}
+
+.SearchHighlight .dot.filled {
+  background-image: -moz-image-rect(url("chrome://browser/skin/dots.png"), 0, 7, 100%, 0);
+}
+
+.SearchHighlight button {
+  margin: 0;
+  /* On some platforms clicking the button will steal focus from the search box
+     causing the popup to close. */
+  -moz-user-focus: ignore;
+}
+
+@media not all and (max-resolution: 1dppx) {
+  .SearchHighlight .dot {
+    background-image: -moz-image-rect(url("chrome://browser/skin/dots@2x.png"), 0, 100%, 100%, 18);
+  }
+
+  .SearchHighlight .dot.filled {
+    background-image: -moz-image-rect(url("chrome://browser/skin/dots@2x.png"), 0, 14, 100%, 0);
+  }
+}
new file mode 100644
index 0000000000000000000000000000000000000000..e856fd0ab2e7f4c36a846c678cd9e539a46c92cf
GIT binary patch
literal 496
zc$@+70T2F(P)<h;3K|Lk000e1NJLTq000mG000LF1^@s60U*sn0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzl1W5CRCwAnkxfeiQ51&HIHTgnFq(t2
z5Er&d(;$Nwh%m@sP!Q;{S_B3DfpXVQD(Vk}%M7I4B`qp~n1y4K3peV@g)$QkgX0V;
zc5c+&+|T!U-*Ya-^E{-}X)cjSoP|Q6)n2dn*=#n?OQn)FpU>fcWV6|YWHNb!Z&vWl
zSG``(Rjbu+IueQa5pWrc#ZCl4SY%mtgQjVrR;xV{A;U1>@pvGU$=sn?O4oIn<G5{~
z&$r%gx1Xs(p>Q1zhjXGRg3INC@puf9Btf^^-Elgd4+KI{)G<P?EX(32lZkG(+gZF*
zOw+6|fk0rBltIM9;Si7vWIq~>w!B{NKVWY#7?cs9V>%!+o|RFXVpLUqce~wd#F>c6
ztSAbg;8oK!_ygRN1lSXnBtUo8;c)DtwnD|@aX&WbA{veE697rkYPD{$v;&Oz3qS$n
z^Z5!oiiTmlp<xQeQn6S(q>*YO{l#XpF}OB5olY5l;Z&AoYdW36Y&Ij2Nm)<Wyrp0;
mxZLmeKkyfh8jXhfBftO<-MX_cvj}zo0000<MNUMnLSTa0irY*8
new file mode 100644
index 0000000000000000000000000000000000000000..5b9089bda016397d100545bbb5564c1255e419c7
GIT binary patch
literal 519
zc$@(T0{H!jP)<h;3K|Lk000e1NJLTq001BW000gM1^@s6PTU@{00001b5ch_0Itp)
z=>Px$!AV3xR5%gERJ(2hF%Yy*JUf&w5*3swQqe~!pFx*L0TmSah!jw9MIK$0uZW`b
zR4JgNLrNFXp#uqLXYpE=bB>6F5=(IQ%-rnSw`-;TdFUX%9*@VDTI&nKPb@bz#ys|V
zy$4#GKp$J~?c)*{jYh}ia`}mZxAR;niPtR4I{kkCBaavCw>|~?qL$#5O2sr94PC3%
zm|8BEYCfME3f_i>z;pV=PQv++X0hFFZ`SMe8_iXzR60wN<Q5zBefR|E*sqAZBf_*=
zEnO@Y@s1mt%|=Zo6C|O@^qM}$y(7Je_z<*MtyZUl!Qj)Q)o?gGs#dG-gw@3-fxv!q
z)oeDu1qY9W!1-Ft!y!J{c^Dj8VBjzpEhj*0E;u=M2*TlUQk<a#Yv$zG^8_BpT1g;J
z`zM$rFhw*JTx@t8Ya=@5P;e2Ri_vnd<pj{@08#BIxNrai2VAtF#^+G&D7a7q44ki(
zdqAgY`eIwepy1@2du^z37j(PbAKOrTC`fJ_5?=Rx3N}l$SO@)yexJ=|7IqH~4h<o(
zI{;$mgU!%xpXpw4CM>WQ8njr;31E(~_Z7O6NB<Ay6Af@M;tOsv1wb2UwcP*!002ov
JPDHLkV1g~k;|c%(
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -24,16 +24,18 @@ browser.jar:
 #endif
         skin/classic/browser/aboutTabCrashed.css
         skin/classic/browser/actionicon-tab.png
 *       skin/classic/browser/browser.css
 *       skin/classic/browser/devedition.css
 *       skin/classic/browser/browser-lightweightTheme.css
         skin/classic/browser/click-to-play-warning-stripes.png
 *       skin/classic/browser/content-contextmenu.svg
+        skin/classic/browser/dots.png                                (../shared/dots.png)
+        skin/classic/browser/dots@2x.png                             (../shared/dots@2x.png)
 *       skin/classic/browser/engineManager.css
         skin/classic/browser/fullscreen-darknoise.png
         skin/classic/browser/Geolocation-16.png
         skin/classic/browser/Geolocation-64.png
         skin/classic/browser/Info.png
         skin/classic/browser/identity.png
         skin/classic/browser/identity-icons-generic.png
         skin/classic/browser/identity-icons-https.png
@@ -460,16 +462,18 @@ browser.jar:
         skin/classic/aero/browser/aboutTabCrashed.css
         skin/classic/aero/browser/aboutWelcomeBack.css               (../shared/aboutWelcomeBack.css)
         skin/classic/aero/browser/actionicon-tab.png
 *       skin/classic/aero/browser/browser.css                        (browser-aero.css)
 *       skin/classic/aero/browser/devedition.css                     (devedition-aero.css)
 *       skin/classic/aero/browser/browser-lightweightTheme.css
         skin/classic/aero/browser/click-to-play-warning-stripes.png
 *       skin/classic/aero/browser/content-contextmenu.svg
+        skin/classic/aero/browser/dots.png                           (../shared/dots.png)
+        skin/classic/aero/browser/dots@2x.png                        (../shared/dots@2x.png)
 *       skin/classic/aero/browser/engineManager.css
         skin/classic/aero/browser/fullscreen-darknoise.png
         skin/classic/aero/browser/Geolocation-16.png
         skin/classic/aero/browser/Geolocation-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/identity-icons-generic.png
         skin/classic/aero/browser/identity-icons-https.png
--- a/configure.in
+++ b/configure.in
@@ -3529,20 +3529,16 @@ case "$GRE_MILESTONE" in
 esac
 AC_SUBST(NIGHTLY_BUILD)
 AC_SUBST(RELEASE_BUILD)
 
 dnl ========================================================
 dnl Disable compiling sources in unified mode.
 dnl ========================================================
 
-if test -z "$NIGHTLY_BUILD"; then
-    MOZ_DISABLE_UNIFIED_COMPILATION=1
-fi
-
 MOZ_ARG_DISABLE_BOOL(unified-compilation,
 [  --disable-unified-compilation
                           Disable unified compilation of some C/C++ sources],
     MOZ_DISABLE_UNIFIED_COMPILATION=1,
     MOZ_DISABLE_UNIFIED_COMPILATION=)
 AC_SUBST(MOZ_DISABLE_UNIFIED_COMPILATION)
 
 dnl ========================================================
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -8371,23 +8371,21 @@ nsDocument::WalkRadioGroup(const nsAStri
 uint32_t
 nsDocument::GetRequiredRadioCount(const nsAString& aName) const
 {
   nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
   return radioGroup ? radioGroup->mRequiredRadioCount : 0;
 }
 
 void
-nsDocument::RadioRequiredChanged(const nsAString& aName, nsIFormControl* aRadio)
+nsDocument::RadioRequiredWillChange(const nsAString& aName, bool aRequiredAdded)
 {
   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
 
-  nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
-  NS_ASSERTION(element, "radio controls have to be content elements");
-  if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
+  if (aRequiredAdded) {
     radioGroup->mRequiredRadioCount++;
   } else {
     NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
                  "mRequiredRadioCount about to wrap below 0!");
     radioGroup->mRequiredRadioCount--;
   }
 }
 
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -925,18 +925,18 @@ public:
                        const bool aPrevious,
                        mozilla::dom::HTMLInputElement*  aFocusedRadio,
                        mozilla::dom::HTMLInputElement** aRadioOut) MOZ_OVERRIDE;
   virtual void AddToRadioGroup(const nsAString& aName,
                                nsIFormControl* aRadio) MOZ_OVERRIDE;
   virtual void RemoveFromRadioGroup(const nsAString& aName,
                                     nsIFormControl* aRadio) MOZ_OVERRIDE;
   virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const MOZ_OVERRIDE;
-  virtual void RadioRequiredChanged(const nsAString& aName,
-                                    nsIFormControl* aRadio) MOZ_OVERRIDE;
+  virtual void RadioRequiredWillChange(const nsAString& aName,
+                                       bool aRequiredAdded) MOZ_OVERRIDE;
   virtual bool GetValueMissingState(const nsAString& aName) const MOZ_OVERRIDE;
   virtual void SetValueMissingState(const nsAString& aName, bool aValue) MOZ_OVERRIDE;
 
   // for radio group
   nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
   nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
 
   virtual nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) MOZ_OVERRIDE;
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -2191,23 +2191,20 @@ HTMLFormElement::RemoveFromRadioGroup(co
 
 uint32_t
 HTMLFormElement::GetRequiredRadioCount(const nsAString& aName) const
 {
   return mRequiredRadioButtonCounts.Get(aName);
 }
 
 void
-HTMLFormElement::RadioRequiredChanged(const nsAString& aName,
-                                      nsIFormControl* aRadio)
+HTMLFormElement::RadioRequiredWillChange(const nsAString& aName,
+                                         bool aRequiredAdded)
 {
-  nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
-  NS_ASSERTION(element, "radio controls have to be content elements!");
-
-  if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
+  if (aRequiredAdded) {
     mRequiredRadioButtonCounts.Put(aName,
                                    mRequiredRadioButtonCounts.Get(aName)+1);
   } else {
     uint32_t requiredNb = mRequiredRadioButtonCounts.Get(aName);
     NS_ASSERTION(requiredNb >= 1,
                  "At least one radio button has to be required!");
     if (requiredNb == 1) {
       mRequiredRadioButtonCounts.Remove(aName);
--- a/dom/html/HTMLFormElement.h
+++ b/dom/html/HTMLFormElement.h
@@ -71,18 +71,18 @@ public:
                                 const bool aPrevious,
                                 HTMLInputElement* aFocusedRadio,
                                 HTMLInputElement** aRadioOut) MOZ_OVERRIDE;
   NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
                             bool aFlushContent) MOZ_OVERRIDE;
   void AddToRadioGroup(const nsAString& aName, nsIFormControl* aRadio) MOZ_OVERRIDE;
   void RemoveFromRadioGroup(const nsAString& aName, nsIFormControl* aRadio) MOZ_OVERRIDE;
   virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const MOZ_OVERRIDE;
-  virtual void RadioRequiredChanged(const nsAString& aName,
-                                    nsIFormControl* aRadio) MOZ_OVERRIDE;
+  virtual void RadioRequiredWillChange(const nsAString& aName,
+                                       bool aRequiredAdded) MOZ_OVERRIDE;
   virtual bool GetValueMissingState(const nsAString& aName) const MOZ_OVERRIDE;
   virtual void SetValueMissingState(const nsAString& aName, bool aValue) MOZ_OVERRIDE;
 
   virtual EventStates IntrinsicState() const MOZ_OVERRIDE;
 
   // nsIContent
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1327,16 +1327,26 @@ HTMLInputElement::BeforeSetAttr(int32_t 
         CancelImageRequests(aNotify);
       }
     } else if (aNotify && aName == nsGkAtoms::disabled) {
       mDisabledChanged = true;
     } else if (aName == nsGkAtoms::dir &&
                AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
                            nsGkAtoms::_auto, eIgnoreCase)) {
       SetDirectionIfAuto(false, aNotify);
+    } else if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
+      nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
+
+      if (container &&
+          ((aValue && !HasAttr(aNameSpaceID, aName)) ||
+           (!aValue && HasAttr(aNameSpaceID, aName)))) {
+        nsAutoString name;
+        GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
+        container->RadioRequiredWillChange(name, !!aValue);
+      }
     }
   }
 
   return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
                                                           aValue, aNotify);
 }
 
 nsresult
@@ -1400,26 +1410,16 @@ HTMLInputElement::AfterSetAttr(int32_t a
         // whether we have an image to load;
         nsAutoString src;
         if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
           LoadImage(src, false, aNotify, eImageLoadType_Normal);
         }
       }
     }
 
-    if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
-      nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
-
-      if (container) {
-        nsAutoString name;
-        GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
-        container->RadioRequiredChanged(name, this);
-      }
-    }
-
     if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
         aName == nsGkAtoms::readonly) {
       UpdateValueMissingValidityState();
 
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         UpdateBarredFromConstraintValidation();
       }
--- a/dom/html/nsIRadioGroupContainer.h
+++ b/dom/html/nsIRadioGroupContainer.h
@@ -13,18 +13,18 @@ class nsIFormControl;
 
 namespace mozilla {
 namespace dom {
 class HTMLInputElement;
 }
 }
 
 #define NS_IRADIOGROUPCONTAINER_IID   \
-{ 0x22924a01, 0x4360, 0x401b, \
-  { 0xb1, 0xd1, 0x56, 0x8d, 0xf5, 0xa3, 0xda, 0x71 } }
+{ 0x800320a0, 0x733f, 0x11e4, \
+  { 0x82, 0xf8, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
 
 /**
  * A container that has multiple radio groups in it, defined by name.
  */
 class nsIRadioGroupContainer : public nsISupports
 {
 public:
 
@@ -86,18 +86,18 @@ public:
    * store radio groups on their own.
    *
    * @param aName radio group's name
    * @param aRadio radio button's pointer
    */
   virtual void RemoveFromRadioGroup(const nsAString& aName, nsIFormControl* aRadio) = 0;
 
   virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const = 0;
-  virtual void RadioRequiredChanged(const nsAString& aName,
-                                    nsIFormControl* aRadio) = 0;
+  virtual void RadioRequiredWillChange(const nsAString& aName,
+                                       bool aRequiredAdded) = 0;
   virtual bool GetValueMissingState(const nsAString& aName) const = 0;
   virtual void SetValueMissingState(const nsAString& aName, bool aValue) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIRadioGroupContainer,
                               NS_IRADIOGROUPCONTAINER_IID)
 
 #endif /* nsIRadioGroupContainer_h__ */
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 support-files =
   save_restore_radio_groups.sjs
   test_input_number_data.js
 
 [test_bug1039548.html]
 [test_button_attributes_reflection.html]
 [test_input_radio_radiogroup.html]
+[test_input_radio_required.html]
 [test_change_event.html]
 skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_datalist_element.html]
 [test_experimental_forms_pref.html]
 [test_form_attribute-1.html]
 [test_form_attribute-2.html]
 [test_form_attribute-3.html]
 [test_form_attribute-4.html]
new file mode 100644
--- /dev/null
+++ b/dom/html/test/forms/test_input_radio_required.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id={BUGNUMBER}
+-->
+<head>
+  <title>Test for Bug 1100535</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1100535">Mozilla Bug 1100535</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<form>
+  <input type="radio" name="a">
+</form>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+  var input = document.querySelector("input");
+  input.setAttribute("required", "x");
+  input.setAttribute("required", "y");
+  is(document.forms[0].checkValidity(), false);
+  input.required = false;
+  is(document.forms[0].checkValidity(), true);
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -175,17 +175,18 @@ MediaSourceReader::OnVideoDecoded(VideoD
   }
   GetCallback()->OnVideoDecoded(aSample);
 }
 
 void
 MediaSourceReader::OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason)
 {
   MSE_DEBUG("MediaSourceReader(%p)::OnNotDecoded aType=%u aReason=%u IsEnded: %d", this, aType, aReason, IsEnded());
-  if (aReason == RequestSampleCallback::DECODE_ERROR) {
+  if (aReason == RequestSampleCallback::DECODE_ERROR ||
+      aReason == RequestSampleCallback::CANCELED) {
     GetCallback()->OnNotDecoded(aType, aReason);
     return;
   }
   // End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
   MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM);
   nsRefPtr<MediaDecoderReader> reader = aType == MediaData::AUDIO_DATA ?
                                           mAudioReader : mVideoReader;
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -522,36 +522,23 @@ public:
 
 private:
   RefPtr<SourceBufferDecoder> mDecoder;
 };
 
 void
 TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder)
 {
-  RefPtr<nsIRunnable> task;
-  nsRefPtr<MediaTaskQueue> taskQueue;
+  RefPtr<nsIRunnable> task = new DelayedDispatchToMainThread(aDecoder);
+
   {
     ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
-    if (mInitializedDecoders.RemoveElement(aDecoder)) {
-      taskQueue = aDecoder->GetReader()->GetTaskQueue();
-      task = new DelayedDispatchToMainThread(aDecoder);
-    } else {
-      task = new ReleaseDecoderTask(aDecoder);
-    }
+    mInitializedDecoders.RemoveElement(aDecoder);
     mDecoders.RemoveElement(aDecoder);
 
     if (mCurrentDecoder == aDecoder) {
       DiscardDecoder();
     }
   }
-  // At this point, task should be holding the only reference to aDecoder.
-  if (taskQueue) {
-    // If we were initialized, post the task via the reader's
-    // task queue to ensure that the reader isn't in the middle
-    // of an existing task.
-    taskQueue->Dispatch(task);
-  } else {
-    NS_DispatchToMainThread(task);
-  }
+  aDecoder->GetReader()->GetTaskQueue()->Dispatch(task);
 }
 
 } // namespace mozilla
--- a/editor/libeditor/nsTextEditRules.cpp
+++ b/editor/libeditor/nsTextEditRules.cpp
@@ -1149,17 +1149,17 @@ nsTextEditRules::CreateBogusNodeIfNeeded
   // Now we've got the body element. Iterate over the body element's children,
   // looking for editable content. If no editable content is found, insert the
   // bogus node.
   for (nsCOMPtr<nsIContent> bodyChild = body->GetFirstChild();
        bodyChild;
        bodyChild = bodyChild->GetNextSibling()) {
     if (mEditor->IsMozEditorBogusNode(bodyChild) ||
         !mEditor->IsEditable(body) || // XXX hoist out of the loop?
-        mEditor->IsEditable(bodyChild)) {
+        mEditor->IsEditable(bodyChild) || mEditor->IsBlockNode(bodyChild)) {
       return NS_OK;
     }
   }
 
   // Skip adding the bogus node if body is read-only.
   if (!mEditor->IsModifiableNode(body)) {
     return NS_OK;
   }
new file mode 100644
--- /dev/null
+++ b/editor/reftests/911201-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<body contenteditable><div contenteditable=false>foo</div></body>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/911201.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<body contenteditable onload="document.body.innerHTML='<div contenteditable=false>foo</div>';"></body>
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -120,11 +120,12 @@ needs-focus == spellcheck-contenteditabl
 == spellcheck-contenteditable-attr-dynamic.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-attr-dynamic-inherit.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-property-dynamic.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-property-dynamic-inherit.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-attr-dynamic-override.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-attr-dynamic-override-inherit.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-property-dynamic-override.html spellcheck-contenteditable-disabled-ref.html
 == spellcheck-contenteditable-property-dynamic-override-inherit.html spellcheck-contenteditable-disabled-ref.html
+== 911201.html 911201-ref.html
 needs-focus == 969773.html 969773-ref.html
 == 997805.html 997805-ref.html
 == 1088158.html 1088158-ref.html
--- a/gfx/layers/D3D9SurfaceImage.cpp
+++ b/gfx/layers/D3D9SurfaceImage.cpp
@@ -87,22 +87,23 @@ D3D9SurfaceImage::SetData(const Data& aD
   mQuery = query;
 
   return S_OK;
 }
 
 void
 D3D9SurfaceImage::EnsureSynchronized()
 {
-  if (!mQuery) {
+  RefPtr<IDirect3DQuery9> query = mQuery;
+  if (!query) {
     // Not setup, or already synchronized.
     return;
   }
   int iterations = 0;
-  while (iterations < 10 && S_FALSE == mQuery->GetData(nullptr, 0, D3DGETDATA_FLUSH)) {
+  while (iterations < 10 && S_FALSE == query->GetData(nullptr, 0, D3DGETDATA_FLUSH)) {
     Sleep(1);
     iterations++;
   }
   mQuery = nullptr;
 }
 
 HANDLE
 D3D9SurfaceImage::GetShareHandle()
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -2498,17 +2498,17 @@ MPEG4Source::~MPEG4Source() {
     free(mCurrentSampleInfoSizes);
     free(mCurrentSampleInfoOffsets);
 }
 
 static bool ValidInputSize(int32_t size) {
   // Reject compressed samples larger than an uncompressed UHD
   // frame. This is a reasonable cut-off for a lossy codec,
   // combined with the current Firefox limit to 5k video.
-  return (size > 0 && size < 4 * (1920 * 1080) * 3 / 2);
+  return (size > 0 && size <= 4 * (1920 * 1080) * 3 / 2);
 }
 
 status_t MPEG4Source::start(MetaData *params) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(!mStarted);
 
     int32_t val;
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -262,14 +262,17 @@ user_pref("loop.oauth.google.URL", "http
 user_pref("loop.oauth.google.getContactsURL", "http://%(server)s/browser/browser/components/loop/test/mochitest/google_service.sjs?action=contacts");
 user_pref("loop.oauth.google.getGroupsURL", "http://%(server)s/browser/browser/components/loop/test/mochitest/google_service.sjs?action=groups");
 user_pref("loop.CSP","default-src 'self' about: file: chrome: data: wss://* http://* https://*");
 
 // Ensure UITour won't hit the network
 user_pref("browser.uitour.pinnedTabUrl", "http://%(server)s/uitour-dummy/pinnedTab");
 user_pref("browser.uitour.url", "http://%(server)s/uitour-dummy/tour");
 
+// Don't show the search first run UI by default
+user_pref("browser.search.highlightCount", 0);
+
 user_pref("media.eme.enabled", true);
 
 // Don't prompt about e10s
 user_pref("browser.displayedE10SPrompt.1", 5);
 // Don't use auto-enabled e10s
 user_pref("browser.tabs.remote.autostart.1", false);