Bug 907001 - Location bar is slow with long text runs.r=adw draft
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 28 Apr 2016 13:59:24 +0200
changeset 357287 4e2a8eb7d9d88e60b72e1018389de03cb7e02d03
parent 356930 b0d046653bdc35de6edbd851ea104985ba95c336
child 519618 ad921ca3250291643034ddf61867524f7f9ff686
push id16753
push usermak77@bonardo.net
push dateThu, 28 Apr 2016 14:35:02 +0000
reviewersadw
bugs907001
milestone49.0a1
Bug 907001 - Location bar is slow with long text runs.r=adw MozReview-Commit-ID: KIfaGfsm26x
browser/base/content/urlbarBindings.xml
toolkit/components/places/SQLFunctions.cpp
toolkit/content/widgets/autocomplete.xml
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -129,16 +129,22 @@ file, You can obtain one at http://mozil
         this.inputField.removeEventListener("underflow", this, false);
       ]]></destructor>
 
       <field name="_value">""</field>
       <field name="gotResultForCurrentQuery">false</field>
       <field name="handleEnterWhenGotResult">false</field>
 
       <!--
+        For performance reasons we want to limit the size of the text runs we
+        build and show to the user.
+      -->
+      <field name="textRunsMaxLen">255</field>
+
+      <!--
         onBeforeValueGet is called by the base-binding's .value getter.
         It can return an object with a "value" property, to override the
         return value of the getter.
       -->
       <method name="onBeforeValueGet">
         <body><![CDATA[
           return {value: this._value};
         ]]></body>
--- a/toolkit/components/places/SQLFunctions.cpp
+++ b/toolkit/components/places/SQLFunctions.cpp
@@ -13,16 +13,20 @@
 #include "nsMathUtils.h"
 #include "nsUTF8Utils.h"
 #include "nsINavHistoryService.h"
 #include "nsPrintfCString.h"
 #include "nsNavHistory.h"
 #include "mozilla/Likely.h"
 #include "nsVariant.h"
 
+// Maximum number of chars to search through.
+// MatchAutoCompleteFunction won't look for matches over this threshold.
+#define MAX_CHARS_TO_SEARCH_THROUGH 255
+
 using namespace mozilla::storage;
 
 // Keep the GUID-related parts of this file in sync with toolkit/downloads/SQLFunctions.cpp!
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Anonymous Helpers
 
 namespace {
@@ -383,42 +387,48 @@ namespace places {
       NS_ADDREF(*_result = new IntegerVariant(0));
       return NS_OK;
     }
 
     // Obtain our search function.
     searchFunctionPtr searchFunction = getSearchFunction(matchBehavior);
 
     // Clean up our URI spec and prepare it for searching.
-    nsCString fixedURI;
-    fixupURISpec(url, matchBehavior, fixedURI);
+    nsCString fixedUrl;
+    fixupURISpec(url, matchBehavior, fixedUrl);
+    // Limit the number of chars we search through.
+    nsDependentCString trimmedUrl(fixedUrl, MAX_CHARS_TO_SEARCH_THROUGH);
 
     nsAutoCString title;
     (void)aArguments->GetUTF8String(kArgIndexTitle, title);
+    // Limit the number of chars we search through.
+    nsDependentCString trimmedTitle(title, MAX_CHARS_TO_SEARCH_THROUGH);
 
     // Determine if every token matches either the bookmark title, tags, page
     // title, or page URL.
     nsCWhitespaceTokenizer tokenizer(searchString);
     while (matches && tokenizer.hasMoreTokens()) {
       const nsDependentCSubstring &token = tokenizer.nextToken();
 
       if (HAS_BEHAVIOR(TITLE) && HAS_BEHAVIOR(URL)) {
-        matches = (searchFunction(token, title) || searchFunction(token, tags)) &&
-                  searchFunction(token, fixedURI);
+        matches = (searchFunction(token, trimmedTitle) ||
+                   searchFunction(token, tags)) &&
+                  searchFunction(token, trimmedUrl);
       }
       else if (HAS_BEHAVIOR(TITLE)) {
-        matches = searchFunction(token, title) || searchFunction(token, tags);
+        matches = searchFunction(token, trimmedTitle) ||
+                  searchFunction(token, tags);
       }
       else if (HAS_BEHAVIOR(URL)) {
-        matches = searchFunction(token, fixedURI);
+        matches = searchFunction(token, trimmedUrl);
       }
       else {
-        matches = searchFunction(token, title) ||
+        matches = searchFunction(token, trimmedTitle) ||
                   searchFunction(token, tags) ||
-                  searchFunction(token, fixedURI);
+                  searchFunction(token, trimmedUrl);
       }
     }
 
     NS_ADDREF(*_result = new IntegerVariant(matches ? 1 : 0));
     return NS_OK;
     #undef HAS_BEHAVIOR
   }
 
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -1829,17 +1829,18 @@ extends="chrome://global/content/binding
           return this._textToSubURI.unEscapeURIForUI("UTF-8", url);
           ]]>
         </body>
       </method>
 
       <method name="_adjustAcItem">
         <body>
           <![CDATA[
-          if (!this.parentNode.parentNode.popupOpen) {
+          let popup = this.parentNode.parentNode;
+          if (!popup.popupOpen) {
             // Removing the max-width and resetting it later when overflow is
             // handled is jarring when the item is visible, so skip this when
             // the popup is open.
             this._removeMaxWidths();
           }
 
           let title = this.getAttribute("title");
 
@@ -1941,22 +1942,26 @@ extends="chrome://global/content/binding
               displayUrl = this._unescapeUrl(action.params.url);
               title = displayUrl;
               let visitStr = this._stringBundle.GetStringFromName("visit");
               this._setUpDescription(this._actionText, visitStr, true);
             }
           }
 
           if (!displayUrl) {
-            let input = this.parentNode.parentNode.input;
+            let input = popup.input;
             let url = typeof(input.trimValue) == "function" ?
                       input.trimValue(originalUrl) :
                       originalUrl;
             displayUrl = this._unescapeUrl(url);
           }
+          // For performance reasons we may want to limit the displayUrl size.
+          if (popup.textRunsMaxLen) {
+            displayUrl = displayUrl.substr(0, popup.textRunsMaxLen);
+          }
           this.setAttribute("displayurl", displayUrl);
 
           // Show the domain as the title if we don't have a title.
           if (!title) {
             title = displayUrl;
             try {
               let uri = Services.io.newURI(originalUrl, null, null);
               // Not all valid URLs have a domain.
@@ -2004,18 +2009,26 @@ extends="chrome://global/content/binding
               // to the empty string.
               this._setUpDescription(this._actionText, "", false);
             }
           }
 
           this.setAttribute("type", type);
 
           if (Array.isArray(title)) {
+            // For performance reasons we may want to limit the title size.
+            if (popup.textRunsMaxLen) {
+              title = title.map(t => t.substr(0, popup.textRunsMaxLen));
+            }
             this._setUpEmphasisedSections(this._titleText, title);
           } else {
+            // For performance reasons we may want to limit the title size.
+            if (popup.textRunsMaxLen) {
+              title = title.substr(0, popup.textRunsMaxLen);
+            }
             this._setUpDescription(this._titleText, title, false);
           }
           this._setUpDescription(this._urlText, displayUrl, !emphasiseUrl);
 
           if (this._inOverflow) {
             this._handleOverflow();
           }
           ]]>