Merge m-i and f-t to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Thu, 27 Nov 2014 22:30:17 -0800
changeset 242240 1162e4a4d7a2ba784392f7812b4aeb1e23a1d5ba
parent 242238 163b23f8ac7c49888ee394bf2ae5cff295a1296a (current diff)
parent 242239 edb694f470b87fb9f3f400c0898337ca4455c93c (diff)
child 242246 a642d245eb3698e1c68b4695cc8f749c092c40ab
child 242259 41bb0378e9f60be5d6206127d949c32d4289870c
child 242269 d9fb4a6a3c5a3ca84d65aa770c3f23a3b3fc929f
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
1162e4a4d7a2 / 36.0a1 / 20141128030201 / files
nightly linux64
1162e4a4d7a2 / 36.0a1 / 20141128030201 / files
nightly mac
1162e4a4d7a2 / 36.0a1 / 20141128030201 / files
nightly win32
1162e4a4d7a2 / 36.0a1 / 20141128030201 / files
nightly win64
1162e4a4d7a2 / 36.0a1 / 20141128030201 / 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 m-i and f-t to m-c, a=merge
browser/base/content/test/general/browser.ini
--- 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..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/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);