From dc628a8ae3de1b879d3280cae2b157662adfabb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Qu=C3=A8ze?= Date: Fri, 9 Jun 2017 15:11:03 +0200 Subject: [PATCH] Bug 1369705 - avoid starting the search service or calling the search-one-offs XBL constructor before first paint, r=adw. --- .../test/performance/browser_startup.js | 14 +- browser/base/content/urlbarBindings.xml | 4 +- browser/components/search/content/search.xml | 233 +++++++++--------- .../components/search/test/browser_426329.js | 8 + browser/components/tests/startupRecorder.js | 10 +- 5 files changed, 144 insertions(+), 125 deletions(-) diff --git a/browser/base/content/test/performance/browser_startup.js b/browser/base/content/test/performance/browser_startup.js index 4fc403180956..63780dda6104 100644 --- a/browser/base/content/test/performance/browser_startup.js +++ b/browser/base/content/test/performance/browser_startup.js @@ -47,22 +47,22 @@ const startupPhases = { // For the following phases of startup we have only a black list for now // We are at this phase after creating the first browser window (ie. after final-ui-startup). - "before opening first browser window": {blacklist: { + "before opening first browser window": {}, + + // We reach this phase right after showing the first browser window. + // This means that anything already loaded at this point has been loaded + // before first paint and delayed it. + "before first paint": {blacklist: { components: new Set([ "nsSearchService.js", ]) }}, - // We reach this phase right after showing the first browser window. - // This means that anything already loaded at this point has been loaded - // before first paint and delayed it. - "before first paint": {}, - // We are at this phase once we are ready to handle user events. // Anything loaded at this phase or before gets in the way of the user // interacting with the first browser window. "before handling user events": {}, -} +}; function test() { if (!AppConstants.NIGHTLY_BUILD && !AppConstants.DEBUG) { diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index 59e645eea44f..c341e4eacd35 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -121,7 +121,9 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. cxmenu.insertBefore(pasteAndGo, insertLocation.nextSibling); } - this._enableOrDisableOneOffSearches(); + this.popup.addEventListener("popupshowing", () => { + this._enableOrDisableOneOffSearches(); + }, {capturing: true, once: true}); // The autocomplete controller uses heuristic on some internal caches // to handle cases like backspace, autofill or repeated searches. diff --git a/browser/components/search/content/search.xml b/browser/components/search/content/search.xml index b2b5c8687706..7b4fda4aa44f 100644 --- a/browser/components/search/content/search.xml +++ b/browser/components/search/content/search.xml @@ -70,6 +70,8 @@ { - // Bail out if the binding's been destroyed - if (!this._initialized) - return; + (window.delayedStartupPromise || Promise.resolve()).then(() => { + window.requestIdleCallback(() => { + Services.search.init(aStatus => { + // Bail out if the binding's been destroyed + if (!this._initialized) + return; - if (Components.isSuccessCode(aStatus)) { - // Refresh the display (updating icon, etc) - this.updateDisplay(); - BrowserSearch.updateOpenSearchBadge(); - } else { - Components.utils.reportError("Cannot initialize search service, bailing out: " + aStatus); - } + if (Components.isSuccessCode(aStatus)) { + // Refresh the display (updating icon, etc) + this.updateDisplay(); + BrowserSearch.updateOpenSearchBadge(); + } else { + Components.utils.reportError("Cannot initialize search service, bailing out: " + aStatus); + } + }); + }); }); - // Some accessibility tests create their own that doesn't - // use the popup binding below, so null-check oneOffButtons. - if (this.textbox.popup.oneOffButtons) { - this.textbox.popup.oneOffButtons.telemetryOrigin = "searchbar"; - this.textbox.popup.oneOffButtons.popup = this.textbox.popup; - this.textbox.popup.oneOffButtons.textbox = this.textbox; - } + // Wait until the popupshowing event to avoid forcing immediate + // attachment of the search-one-offs binding. + this.textbox.popup.addEventListener("popupshowing", () => { + let oneOffButtons = this.textbox.popup.oneOffButtons; + // Some accessibility tests create their own that doesn't + // use the popup binding below, so null-check oneOffButtons. + if (oneOffButtons) { + oneOffButtons.telemetryOrigin = "searchbar"; + oneOffButtons.popup = this.textbox.popup; + oneOffButtons.textbox = this.textbox; + } + }, {capturing: true, once: true}); ]]> @@ -567,108 +576,115 @@ - + { this.initContextMenu(cxmenu); }, + {capturing: true, once: true}); this.setAttribute("aria-owns", this.popup.id); - - var insertLocation = cxmenu.firstChild; - while (insertLocation.nextSibling && - insertLocation.getAttribute("cmd") != "cmd_paste") - insertLocation = insertLocation.nextSibling; - if (insertLocation) { - element = document.createElementNS(kXULNS, "menuitem"); - label = this._stringBundle.getString("cmd_pasteAndSearch"); - element.setAttribute("label", label); - element.setAttribute("anonid", "paste-and-search"); - element.setAttribute("oncommand", "BrowserSearch.pasteAndSearch(event)"); - cxmenu.insertBefore(element, insertLocation.nextSibling); - pasteAndSearch = element; - } - - element = document.createElementNS(kXULNS, "menuitem"); - label = this._stringBundle.getString("cmd_clearHistory"); - akey = this._stringBundle.getString("cmd_clearHistory_accesskey"); - element.setAttribute("label", label); - element.setAttribute("accesskey", akey); - element.setAttribute("cmd", "cmd_clearhistory"); - cxmenu.appendChild(element); - - element = document.createElementNS(kXULNS, "menuitem"); - label = this._stringBundle.getString("cmd_showSuggestions"); - akey = this._stringBundle.getString("cmd_showSuggestions_accesskey"); - element.setAttribute("anonid", "toggle-suggest-item"); - element.setAttribute("label", label); - element.setAttribute("accesskey", akey); - element.setAttribute("cmd", "cmd_togglesuggest"); - element.setAttribute("type", "checkbox"); - element.setAttribute("checked", this._suggestEnabled); - element.setAttribute("autocheck", "false"); - this._suggestMenuItem = element; - cxmenu.appendChild(element); - - this.addEventListener("keypress", aEvent => { - if (navigator.platform.startsWith("Mac") && aEvent.keyCode == KeyEvent.VK_F4) - this.openSearch() - }, true); - - this.controllers.appendController(this.searchbarController); document.getBindingParent(this)._textboxInitialized = true; - - // Add observer for suggest preference - Services.prefs.addObserver("browser.search.suggest.enabled", this); ]]> - - - + // Add items to context menu and attach controller to handle them the + // first time the context menu is opened. + + + { + if (aEvent.keyCode == KeyEvent.DOM_VK_F4) + this.openSearch() + }, true); + } + + this.controllers.appendController(this.searchbarController); + + let onpopupshowing = function() { + BrowserSearch.searchBar._textbox.closePopup(); + if (suggestMenuItem) { + let enabled = + Services.prefs.getBoolPref("browser.search.suggest.enabled"); + suggestMenuItem.setAttribute("checked", enabled); + } + + if (!pasteAndSearch) + return; + let controller = document.commandDispatcher.getControllerForCommand("cmd_paste"); + let enabled = controller.isCommandEnabled("cmd_paste"); + if (enabled) + pasteAndSearch.removeAttribute("disabled"); + else + pasteAndSearch.setAttribute("disabled", "true"); + }; + aMenu.addEventListener("popupshowing", onpopupshowing); + onpopupshowing(); + ]]> +