Backed out changeset b7c10827173f (bug 1101147) to use a different patch. a=backout
authorFelipe Gomes <felipc@gmail.com>
Mon, 24 Nov 2014 08:40:21 -0200
changeset 226126 eb7826389d239b1cd94d5f14db7e6689da338727
parent 226125 51c693c1ca3f0be4c3fcd932d0030bd7f0e1c19c
child 226127 ca40bcdc68aeca0ea3ac39c447569f710906f249
push id4171
push userfelipc@gmail.com
push dateMon, 24 Nov 2014 10:41:22 +0000
treeherdermozilla-beta@65fa22861cad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1101147
milestone34.0
backs outb7c10827173f3abba596249bea047e385af1c3da
Backed out changeset b7c10827173f (bug 1101147) to use a different patch. a=backout
browser/base/content/newtab/newTab.css
browser/base/content/newtab/newTab.xul
browser/base/content/newtab/search.js
browser/base/content/test/newtab/browser_newtab_search.js
browser/modules/ContentSearch.jsm
browser/modules/test/browser_ContentSearch.js
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -328,43 +328,40 @@ input[type=button] {
   -moz-box-flex: 1;
   -moz-box-orient: horizontal;
   -moz-box-align: center;
   height: 44px; /* 32 + 6 logo top "padding" + 6 logo bottom "padding" */
   margin: 26px 20px 10px; /* top: 32 - 6 search form top "padding", bottom: 32 - 16 tiles top margin - 6 logo bottom "padding" */
   max-width: 600px; /* 2 * (290 cell width + 10 cell margin) */
 }
 
-#newtab-search-icon {
+#newtab-search-logo {
   display: -moz-box;
-  width: 38px; /* 26 image width + 6 left "padding" + 6 right "padding" */
+  width: 77px; /* 65 image width + 6 left "padding" + 6 right "padding" */
   height: 38px; /* 26 image height + 6 top "padding" + 6 bottom "padding" */
   border: 1px solid transparent;
-  -moz-margin-end: 5px;
+  -moz-margin-end: 8px;
   background-repeat: no-repeat;
   background-position: center;
-  background-size: 26px;
-  background-image: url("chrome://browser/skin/magnifier.png");
+  background-size: 65px 26px;
 }
 
-@media not all and (max-resolution: 1dppx) {
-  #newtab-search-icon {
-    background-image: url("chrome://browser/skin/magnifier@2px.png");
-  }
+#newtab-search-logo[hidden] {
+  display: none;
 }
 
-#newtab-search-icon[active],
-#newtab-search-icon:hover {
+#newtab-search-logo[active],
+#newtab-search-logo:hover {
   background-color: #e9e9e9;
   border: 1px solid rgb(226, 227, 229);
   border-radius: 2.5px;
 }
 
 #newtab-search-text {
-  height: 38px; /* same height as #newtab-search-icon */
+  height: 38px;
   -moz-box-flex: 1;
 
   padding: 0 8px;
   background: hsla(0,0%,100%,.9) padding-box;
   border: 1px solid;
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
   box-shadow: 0 1px 0 hsla(210,65%,9%,.02) inset,
               0 0 2px hsla(210,65%,9%,.1) inset,
@@ -378,17 +375,17 @@ input[type=button] {
 }
 
 #newtab-search-text:focus,
 #newtab-search-text[autofocus] {
   border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
 }
 
 #newtab-search-submit {
-  height: 38px; /* same height as #newtab-search-icon */
+  height: 38px;
   font-size: 13px !important;
 
   -moz-margin-start: -1px;
   background: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
   padding: 0 9px;
   border: 1px solid;
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
   -moz-border-start: 1px solid transparent;
--- a/browser/base/content/newtab/newTab.xul
+++ b/browser/base/content/newtab/newTab.xul
@@ -64,17 +64,17 @@
           <xul:toolbarbutton id="newtab-undo-close-button" tabindex="-1"
                              class="close-icon tabbable"
                              tooltiptext="&newtab.undo.closeTooltip;" />
         </div>
       </div>
 
       <div id="newtab-search-container">
         <form id="newtab-search-form" name="searchForm">
-          <div id="newtab-search-icon"/>
+          <div id="newtab-search-logo"/>
           <input type="text" name="q" value="" id="newtab-search-text"
                  maxlength="256" dir="auto"/>
           <input id="newtab-search-submit" type="submit"
                  value="&searchEndCap.label;"/>
         </form>
       </div>
 
       <div id="newtab-horizontal-margin">
--- a/browser/base/content/newtab/search.js
+++ b/browser/base/content/newtab/search.js
@@ -19,22 +19,22 @@ let gSearch = {
   },
 
   showPanel: function () {
     if (!Services.prefs.getBoolPref("browser.search.showOneOffButtons")) {
       return;
     }
 
     let panel = this._nodes.panel;
-    let icon = this._nodes.icon;
-    panel.openPopup(icon);
-    icon.setAttribute("active", "true");
+    let logo = this._nodes.logo;
+    panel.openPopup(logo);
+    logo.setAttribute("active", "true");
     panel.addEventListener("popuphidden", function onHidden() {
       panel.removeEventListener("popuphidden", onHidden);
-      icon.removeAttribute("active");
+      logo.removeAttribute("active");
     });
   },
 
   search: function (event) {
     if (event) {
       event.preventDefault();
     }
     let searchStr = this._nodes.text.value;
@@ -56,22 +56,24 @@ let gSearch = {
   handleEvent: function (event) {
     let methodName = "on" + event.detail.type;
     if (this.hasOwnProperty(methodName)) {
       this[methodName](event.detail.data);
     }
   },
 
   onState: function (data) {
+    this._newEngines = data.engines;
     this._setCurrentEngine(data.currentEngine);
     this._initWhenInitalStateReceived();
   },
 
   onCurrentState: function (data) {
     if (this._initialStateReceived) {
+      this._newEngines = data.engines;
       this._setCurrentEngine(data.currentEngine);
     }
   },
 
   onCurrentEngine: function (engineName) {
     if (this._initialStateReceived) {
       this._nodes.panel.hidePopup();
       this._setCurrentEngine(engineName);
@@ -79,44 +81,128 @@ let gSearch = {
   },
 
   onFocusInput: function () {
     this._nodes.text.focus();
   },
 
   _nodeIDSuffixes: [
     "form",
-    "icon",
+    "logo",
     "manage",
     "panel",
     "text",
   ],
 
   _nodes: {},
 
   _initWhenInitalStateReceived: function () {
     this._nodes.form.addEventListener("submit", e => this.search(e));
-    this._nodes.icon.addEventListener("click", e => this.showPanel());
+    this._nodes.logo.addEventListener("click", e => this.showPanel());
     this._nodes.manage.addEventListener("click", e => this.manageEngines());
+    this._nodes.panel.addEventListener("popupshowing", e => this._setUpPanel());
     this._initialStateReceived = true;
     this._initWhenInitalStateReceived = function () {};
   },
 
   _send: function (type, data=null) {
     window.dispatchEvent(new CustomEvent("ContentSearchClient", {
       detail: {
         type: type,
         data: data,
       },
     }));
   },
 
+  _setUpPanel: function () {
+    // Build the panel if necessary.
+    if (this._newEngines) {
+      this._buildPanel(this._newEngines);
+      delete this._newEngines;
+    }
+
+    // Set the selected states of the engines.
+    let panel = this._nodes.panel;
+    for (let box of panel.childNodes) {
+      if (box.getAttribute("engine") == this.currentEngineName) {
+        box.setAttribute("selected", "true");
+      }
+      else {
+        box.removeAttribute("selected");
+      }
+    }
+  },
+
+  _buildPanel: function (engines) {
+    let panel = this._nodes.panel;
+
+    // Empty the panel except for the Manage Engines row.
+    let i = 0;
+    while (i < panel.childNodes.length) {
+      let node = panel.childNodes[i];
+      if (node != this._nodes.manage) {
+        panel.removeChild(node);
+      }
+      else {
+        i++;
+      }
+    }
+
+    // Add all the engines.
+    for (let engine of engines) {
+      panel.insertBefore(this._makePanelEngine(panel, engine),
+                         this._nodes.manage);
+    }
+  },
+
+  _makePanelEngine: function (panel, engine) {
+    let box = document.createElementNS(XUL_NAMESPACE, "hbox");
+    box.className = "newtab-search-panel-engine";
+    box.setAttribute("engine", engine.name);
+
+    box.addEventListener("click", () => {
+      this._send("SetCurrentEngine", engine.name);
+      panel.hidePopup();
+      this._nodes.text.focus();
+    });
+
+    let image = document.createElementNS(XUL_NAMESPACE, "image");
+    if (engine.iconBuffer) {
+      let blob = new Blob([engine.iconBuffer]);
+      let size = Math.round(16 * window.devicePixelRatio);
+      let sizeStr = size + "," + size;
+      let uri = URL.createObjectURL(blob) + "#-moz-resolution=" + sizeStr;
+      image.setAttribute("src", uri);
+    }
+    box.appendChild(image);
+
+    let label = document.createElementNS(XUL_NAMESPACE, "label");
+    label.setAttribute("value", engine.name);
+    box.appendChild(label);
+
+    return box;
+  },
+
   _setCurrentEngine: function (engine) {
     this.currentEngineName = engine.name;
 
+    // Set the logo.
+    let logoBuf = window.devicePixelRatio == 2 ? engine.logo2xBuffer :
+                  engine.logoBuffer || engine.logo2xBuffer;
+    if (logoBuf) {
+      this._nodes.logo.hidden = false;
+      let uri = URL.createObjectURL(new Blob([logoBuf]));
+      this._nodes.logo.style.backgroundImage = "url(" + uri + ")";
+      this._nodes.text.placeholder = "";
+    }
+    else {
+      this._nodes.logo.hidden = true;
+      this._nodes.text.placeholder = engine.name;
+    }
+
     // Set up the suggestion controller.
     if (!this._suggestionController) {
       let parent = document.getElementById("newtab-scrollbox");
       this._suggestionController =
         new SearchSuggestionUIController(this._nodes.text, parent,
                                          () => this.search());
     }
     this._suggestionController.engineName = engine.name;
--- a/browser/base/content/test/newtab/browser_newtab_search.js
+++ b/browser/base/content/test/newtab/browser_newtab_search.js
@@ -98,24 +98,50 @@ function runTests() {
      "Sanity check: engine should have 2x logo");
   Services.search.currentEngine = logo1x2xEngine;
   yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
   yield checkCurrentEngine(ENGINE_1X_2X_LOGO, true, true);
 
   // Click the logo to open the search panel.
   yield Promise.all([
     promisePanelShown(panel),
-    promiseClick(iconImg()),
+    promiseClick(logoImg()),
   ]).then(TestRunner.next);
 
+  // In the search panel, click the no-logo engine.  It should become the
+  // current engine.
+  let noLogoBox = null;
+  for (let box of panel.childNodes) {
+    if (box.getAttribute("engine") == noLogoEngine.name) {
+      noLogoBox = box;
+      break;
+    }
+  }
+  ok(noLogoBox, "Search panel should contain the no-logo engine");
+  yield Promise.all([
+    promiseSearchEvents(["CurrentEngine"]),
+    promiseClick(noLogoBox),
+  ]).then(TestRunner.next);
+
+  yield checkCurrentEngine(ENGINE_NO_LOGO, false, false);
+
+  // Switch back to the 1x-and-2x logo engine.
+  Services.search.currentEngine = logo1x2xEngine;
+  yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
+  yield checkCurrentEngine(ENGINE_1X_2X_LOGO, true, true);
+
+  // Open the panel again.
+  yield Promise.all([
+    promisePanelShown(panel),
+    promiseClick(logoImg()),
+  ]).then(TestRunner.next);
+
+  // In the search panel, click the Manage Engines box.
   let manageBox = $("manage");
   ok(!!manageBox, "The Manage Engines box should be present in the document");
-  is(panel.childNodes.length, 1, "Search panel should only contain the Manage Engines entry");
-  is(panel.childNodes[0], manageBox, "Search panel should contain the Manage Engines entry");
-
   yield Promise.all([
     promiseManagerOpen(),
     promiseClick(manageBox),
   ]).then(TestRunner.next);
 
   // Add the engine that provides search suggestions and switch to it.
   let suggestionEngine = null;
   yield promiseNewSearchEngine(ENGINE_SUGGESTIONS, 0).then(engine => {
@@ -288,17 +314,68 @@ function checkCurrentEngine(basename, ha
   ok(engine.name.contains(basename),
      "Sanity check: current engine: engine.name=" + engine.name +
      " basename=" + basename);
 
   // gSearch.currentEngineName
   is(gSearch().currentEngineName, engine.name,
      "currentEngineName: " + engine.name);
 
-  executeSoon(TestRunner.next);
+  // search bar logo
+  let logoURI = null;
+  if (window.devicePixelRatio == 2) {
+    if (has2xLogo) {
+      logoURI = engine.getIconURLBySize(...LOGO_2X_DPI_SIZE);
+      ok(!!logoURI, "Sanity check: engine should have 2x logo");
+    }
+  }
+  else {
+    if (has1xLogo) {
+      logoURI = engine.getIconURLBySize(...LOGO_1X_DPI_SIZE);
+      ok(!!logoURI, "Sanity check: engine should have 1x logo");
+    }
+    else if (has2xLogo) {
+      logoURI = engine.getIconURLBySize(...LOGO_2X_DPI_SIZE);
+      ok(!!logoURI, "Sanity check: engine should have 2x logo");
+    }
+  }
+  let logo = logoImg();
+  is(logo.hidden, !logoURI,
+     "Logo should be visible iff engine has a logo: " + engine.name);
+  if (logoURI) {
+    // The URLs of blobs created with the same ArrayBuffer are different, so
+    // just check that the URI is a blob URI.
+    ok(/^url\("blob:/.test(logo.style.backgroundImage), "Logo URI"); //"
+  }
+
+  if (logo.hidden) {
+    executeSoon(TestRunner.next);
+    return;
+  }
+
+  // "selected" attributes of engines in the panel
+  let panel = searchPanel();
+  promisePanelShown(panel).then(() => {
+    panel.hidePopup();
+    for (let engineBox of panel.childNodes) {
+      let engineName = engineBox.getAttribute("engine");
+      if (engineName == engine.name) {
+        is(engineBox.getAttribute("selected"), "true",
+           "Engine box's selected attribute should be true for " +
+           "selected engine: " + engineName);
+      }
+      else {
+        ok(!engineBox.hasAttribute("selected"),
+           "Engine box's selected attribute should be absent for " +
+           "non-selected engine: " + engineName);
+      }
+    }
+    TestRunner.next();
+  });
+  panel.openPopup(logo);
 }
 
 function promisePanelShown(panel) {
   let deferred = Promise.defer();
   info("Waiting for popupshown");
   panel.addEventListener("popupshown", function onEvent() {
     panel.removeEventListener("popupshown", onEvent);
     is(panel.state, "open", "Panel state");
@@ -322,41 +399,39 @@ function promiseManagerOpen() {
   let deferred = Promise.defer();
   let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                    getService(Ci.nsIWindowWatcher);
   winWatcher.registerNotification(function onWin(subj, topic, data) {
     if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
       subj.addEventListener("load", function onLoad() {
         subj.removeEventListener("load", onLoad);
         if (subj.document.documentURI ==
-            "chrome://browser/content/preferences/preferences.xul") {
+            "chrome://browser/content/search/engineManager.xul") {
           winWatcher.unregisterNotification(onWin);
-          ok(true, "Observed Preferences window opened");
+          ok(true, "Observed search manager window opened");
           is(subj.opener, gWindow,
-             "Preferences window opener should be the chrome browser " +
+             "Search engine manager opener should be the chrome browser " +
              "window containing the newtab page");
-          is(subj.document.documentElement.currentPane.id, "paneSearch",
-             "Preferences window should be opened in the Search pane");
           executeSoon(() => {
             subj.close();
             deferred.resolve();
           });
         }
       });
     }
   });
   return deferred.promise;
 }
 
 function searchPanel() {
   return $("panel");
 }
 
-function iconImg() {
-  return $("icon");
+function logoImg() {
+  return $("logo");
 }
 
 function gSearch() {
   return getContentWindow().gSearch;
 }
 
 /**
  * Waits for a load (or custom) event to finish in a given tab. If provided
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -201,17 +201,29 @@ this.ContentSearch = {
 
   _onMessageSetCurrentEngine: function (msg, data) {
     Services.search.currentEngine = Services.search.getEngineByName(data);
     return Promise.resolve();
   },
 
   _onMessageManageEngines: function (msg, data) {
     let browserWin = msg.target.ownerDocument.defaultView;
-    browserWin.openPreferences("paneSearch");
+    let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
+             getService(Components.interfaces.nsIWindowMediator);
+    let window = wm.getMostRecentWindow("Browser:SearchManager");
+
+    if (window) {
+      window.focus()
+    }
+    else {
+      browserWin.setTimeout(function () {
+        browserWin.openDialog("chrome://browser/content/search/engineManager.xul",
+          "_blank", "chrome,dialog,modal,centerscreen,resizable");
+      }, 0);
+    }
     return Promise.resolve();
   },
 
   _onMessageGetSuggestions: Task.async(function* (msg, data) {
     this._ensureDataHasProperties(data, [
       "engineName",
       "searchString",
     ]);
--- a/browser/modules/test/browser_ContentSearch.js
+++ b/browser/modules/test/browser_ContentSearch.js
@@ -74,23 +74,21 @@ add_task(function* ManageEngines() {
   let deferred = Promise.defer();
   let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                    getService(Ci.nsIWindowWatcher);
   winWatcher.registerNotification(function onOpen(subj, topic, data) {
     if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
       subj.addEventListener("load", function onLoad() {
         subj.removeEventListener("load", onLoad);
         if (subj.document.documentURI ==
-            "chrome://browser/content/preferences/preferences.xul") {
+            "chrome://browser/content/search/engineManager.xul") {
           winWatcher.unregisterNotification(onOpen);
-          ok(true, "Observed Preferences window open");
+          ok(true, "Observed search manager window open");
           is(subj.opener, window,
-             "Preferences window opener should be this chrome window");
-          is(subj.document.documentElement.currentPane.id, "paneSearch",
-             "Preferences window should be opened in the Search pane");
+             "Search engine manager opener should be this chrome window");
           subj.close();
           deferred.resolve();
         }
       });
     }
   });
   info("Waiting for search engine manager window to open...");
   yield deferred.promise;