Bug 754265 - Add a dedicated API to provide a final complete value different from the matching one, r=Enn sr=gavin
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 18 Apr 2014 16:04:19 +0200
changeset 197778 669dff46362f638112c7c910a3c0804c5b9af706
parent 197777 75f108774d93669302358a91e4c9f9f393ea533c
child 197779 db31631ce10ce8afb43e54c7f39bc3a6be92c7fc
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEnn, gavin
bugs754265
milestone31.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
Bug 754265 - Add a dedicated API to provide a final complete value different from the matching one, r=Enn sr=gavin
accessible/tests/mochitest/autocomplete.js
toolkit/components/autocomplete/nsAutoCompleteController.cpp
toolkit/components/autocomplete/nsAutoCompleteController.h
toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
toolkit/components/autocomplete/nsIAutoCompleteController.idl
toolkit/components/autocomplete/nsIAutoCompleteResult.idl
toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
toolkit/components/autocomplete/tests/unit/head_autocomplete.js
toolkit/components/autocomplete/tests/unit/test_378079.js
toolkit/components/autocomplete/tests/unit/test_393191.js
toolkit/components/autocomplete/tests/unit/test_440866.js
toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js
toolkit/components/autocomplete/tests/unit/test_finalCompleteValue_forceComplete.js
toolkit/components/autocomplete/tests/unit/test_finalDefaultCompleteValue.js
toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js
toolkit/components/autocomplete/tests/unit/test_previousResult.js
toolkit/components/autocomplete/tests/unit/xpcshell.ini
toolkit/components/filepicker/nsFileView.cpp
toolkit/components/passwordmgr/nsLoginManager.js
toolkit/components/places/nsPlacesAutoComplete.js
toolkit/components/places/nsTaggingService.js
toolkit/components/satchel/nsFormAutoComplete.js
toolkit/components/satchel/nsFormAutoCompleteResult.jsm
toolkit/content/tests/chrome/test_autocomplete2.xul
toolkit/content/tests/chrome/test_autocomplete3.xul
toolkit/content/tests/chrome/test_autocomplete4.xul
toolkit/content/tests/chrome/test_autocomplete5.xul
toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul
--- a/accessible/tests/mochitest/autocomplete.js
+++ b/accessible/tests/mochitest/autocomplete.js
@@ -194,16 +194,21 @@ AutoCompleteResult.prototype =
     return null;
   },
 
   getImageAt: function(aIndex)
   {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex)
+  {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(nsISupports) ||
         iid.equals(nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp
@@ -405,17 +405,17 @@ nsAutoCompleteController::HandleKeyNavig
 
       if (completeSelection)
       {
         int32_t selectedIndex;
         popup->GetSelectedIndex(&selectedIndex);
         if (selectedIndex >= 0) {
           //  A result is selected, so fill in its value
           nsAutoString value;
-          if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) {
+          if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) {
             input->SetTextValue(value);
             input->SelectTextRange(value.Length(), value.Length());
           }
         } else {
           // Nothing is selected, so fill in the last typed value
           input->SetTextValue(mSearchString);
           input->SelectTextRange(mSearchString.Length(), mSearchString.Length());
         }
@@ -476,17 +476,17 @@ nsAutoCompleteController::HandleKeyNavig
     if (isOpen) {
       int32_t selectedIndex;
       popup->GetSelectedIndex(&selectedIndex);
       bool shouldComplete;
       input->GetCompleteDefaultIndex(&shouldComplete);
       if (selectedIndex >= 0) {
         // The pop-up is open and has a selection, take its value
         nsAutoString value;
-        if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) {
+        if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) {
           input->SetTextValue(value);
           input->SelectTextRange(value.Length(), value.Length());
         }
       }
       else if (shouldComplete) {
         // We usually try to preserve the casing of what user has typed, but
         // if he wants to autocomplete, we will replace the value with the
         // actual autocomplete result.
@@ -574,17 +574,17 @@ nsAutoCompleteController::HandleDelete(b
     // There are still rows in the popup, select the current index again.
     popup->SetSelectedIndex(index);
 
     // Complete to the new current value.
     bool shouldComplete = false;
     input->GetCompleteDefaultIndex(&shouldComplete);
     if (shouldComplete) {
       nsAutoString value;
-      if (NS_SUCCEEDED(GetResultValueAt(index, true, value))) {
+      if (NS_SUCCEEDED(GetResultValueAt(index, false, value))) {
         CompleteValue(value);
       }
     }
 
     // Invalidate the popup.
     popup->Invalidate();
   } else {
     // Nothing left in the popup, clear any pending search timers and
@@ -611,25 +611,25 @@ nsAutoCompleteController::GetResultAt(in
   *aResult = mResults[searchIndex];
   NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetValueAt(int32_t aIndex, nsAString & _retval)
 {
-  GetResultLabelAt(aIndex, false, _retval);
+  GetResultLabelAt(aIndex, _retval);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetLabelAt(int32_t aIndex, nsAString & _retval)
 {
-  GetResultLabelAt(aIndex, false, _retval);
+  GetResultLabelAt(aIndex, _retval);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetCommentAt(int32_t aIndex, nsAString & _retval)
 {
   int32_t rowIndex;
@@ -658,16 +658,28 @@ nsAutoCompleteController::GetImageAt(int
   nsIAutoCompleteResult* result;
   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return result->GetImageAt(rowIndex, _retval);
 }
 
 NS_IMETHODIMP
+nsAutoCompleteController::GetFinalCompleteValueAt(int32_t aIndex,
+                                                  nsAString & _retval)
+{
+  int32_t rowIndex;
+  nsIAutoCompleteResult* result;
+  nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return result->GetFinalCompleteValueAt(rowIndex, _retval);
+}
+
+NS_IMETHODIMP
 nsAutoCompleteController::SetSearchString(const nsAString &aSearchString)
 {
   mSearchString = aSearchString;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetSearchString(nsAString &aSearchString)
@@ -1176,19 +1188,24 @@ nsAutoCompleteController::EnterMatch(boo
 
     int32_t selectedIndex;
     popup->GetSelectedIndex(&selectedIndex);
     if (selectedIndex >= 0) {
       // If completeselectedindex is false or a row was selected from the popup,
       // enter it into the textbox. If completeselectedindex is true, or
       // EnterMatch was called via other means, for instance pressing Enter,
       // don't fill in the value as it will have already been filled in as
-      // needed.
-      if (!completeSelection || aIsPopupSelection)
-        GetResultValueAt(selectedIndex, true, value);
+      // needed, unless the final complete value differs.
+      nsAutoString finalValue, inputValue;
+      GetResultValueAt(selectedIndex, true, finalValue);
+      input->GetTextValue(inputValue);
+      if (!completeSelection || aIsPopupSelection ||
+          !finalValue.Equals(inputValue)) {
+        value = finalValue;
+      }
     }
     else if (shouldComplete) {
       // We usually try to preserve the casing of what user has typed, but
       // if he wants to autocomplete, we will replace the value with the
       // actual autocomplete result.
       // The user wants explicitely to use that result, so this ensures
       // association of the result with the autocompleted text.
       nsAutoString defaultIndexValue;
@@ -1201,17 +1218,17 @@ nsAutoCompleteController::EnterMatch(boo
       // we have to find the first default match and enter it instead
       for (uint32_t i = 0; i < mResults.Length(); ++i) {
         nsIAutoCompleteResult *result = mResults[i];
 
         if (result) {
           int32_t defaultIndex;
           result->GetDefaultIndex(&defaultIndex);
           if (defaultIndex >= 0) {
-            result->GetValueAt(defaultIndex, value);
+            result->GetFinalCompleteValueAt(defaultIndex, value);
             break;
           }
         }
       }
     }
   }
 
   nsCOMPtr<nsIObserverService> obsSvc =
@@ -1544,28 +1561,20 @@ nsAutoCompleteController::GetFinalDefaul
 
   result->GetValueAt(defaultIndex, _retval);
   nsAutoString inputValue;
   mInput->GetTextValue(inputValue);
   if (!_retval.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
     return NS_ERROR_FAILURE;
   }
 
-  // Hack: For typeAheadResults allow the comment to be used as the final
-  // defaultComplete value if provided, otherwise fall back to the usual
-  // value.  This allows to provide a different complete text when the user
-  // confirms the match.  Don't rely on this for production code, since it's a
-  // temporary solution that needs a dedicated API (bug 754265).
-  bool isTypeAheadResult = false;
-  nsAutoString commentValue;
-  if (NS_SUCCEEDED(result->GetTypeAheadResult(&isTypeAheadResult)) &&
-      isTypeAheadResult &&
-      NS_SUCCEEDED(result->GetCommentAt(defaultIndex, commentValue)) &&
-      !commentValue.IsEmpty()) {
-    _retval = commentValue;
+  nsAutoString finalCompleteValue;
+  rv = result->GetFinalCompleteValueAt(defaultIndex, finalCompleteValue);
+  if (NS_SUCCEEDED(rv)) {
+    _retval = finalCompleteValue;
   }
 
   MOZ_ASSERT(FindInReadable(inputValue, _retval, nsCaseInsensitiveStringComparator()),
              "Return value must include input value.");
   return NS_OK;
 }
 
 nsresult
@@ -1620,48 +1629,53 @@ nsAutoCompleteController::CompleteValue(
   }
 
   mInput->SelectTextRange(mSearchStringLength, endSelect);
 
   return NS_OK;
 }
 
 nsresult
-nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, bool aValueOnly, nsAString & _retval)
+nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, nsAString & _retval)
 {
-  return GetResultValueLabelAt(aIndex, aValueOnly, false, _retval);
+  return GetResultValueLabelAt(aIndex, false, false, _retval);
 }
 
 nsresult
-nsAutoCompleteController::GetResultValueAt(int32_t aIndex, bool aValueOnly, nsAString & _retval)
+nsAutoCompleteController::GetResultValueAt(int32_t aIndex, bool aGetFinalValue,
+                                           nsAString & _retval)
 {
-  return GetResultValueLabelAt(aIndex, aValueOnly, true, _retval);
+  return GetResultValueLabelAt(aIndex, aGetFinalValue, true, _retval);
 }
 
 nsresult
-nsAutoCompleteController::GetResultValueLabelAt(int32_t aIndex, bool aValueOnly,
-                                                bool aGetValue, nsAString & _retval)
+nsAutoCompleteController::GetResultValueLabelAt(int32_t aIndex,
+                                                bool aGetFinalValue,
+                                                bool aGetValue,
+                                                nsAString & _retval)
 {
   NS_ENSURE_TRUE(aIndex >= 0 && (uint32_t) aIndex < mRowCount, NS_ERROR_ILLEGAL_VALUE);
 
   int32_t rowIndex;
   nsIAutoCompleteResult *result;
   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint16_t searchResult;
   result->GetSearchResult(&searchResult);
 
   if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) {
-    if (aValueOnly)
+    if (aGetValue)
       return NS_ERROR_FAILURE;
     result->GetErrorDescription(_retval);
   } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
              searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
-    if (aGetValue)
+    if (aGetFinalValue)
+      result->GetFinalCompleteValueAt(rowIndex, _retval);
+    else if (aGetValue)
       result->GetValueAt(rowIndex, _retval);
     else
       result->GetLabelAt(rowIndex, _retval);
   }
 
   return NS_OK;
 }
 
--- a/toolkit/components/autocomplete/nsAutoCompleteController.h
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.h
@@ -54,22 +54,21 @@ protected:
   nsresult EnterMatch(bool aIsPopupSelection);
   nsresult RevertTextValue();
 
   nsresult CompleteDefaultIndex(int32_t aResultIndex);
   nsresult CompleteValue(nsString &aValue);
 
   nsresult GetResultAt(int32_t aIndex, nsIAutoCompleteResult** aResult,
                        int32_t* aRowIndex);
-  nsresult GetResultValueAt(int32_t aIndex, bool aValueOnly,
+  nsresult GetResultValueAt(int32_t aIndex, bool aGetFinalValue,
                             nsAString & _retval);
-  nsresult GetResultLabelAt(int32_t aIndex, bool aValueOnly,
-                            nsAString & _retval);
+  nsresult GetResultLabelAt(int32_t aIndex, nsAString & _retval);
 private:
-  nsresult GetResultValueLabelAt(int32_t aIndex, bool aValueOnly,
+  nsresult GetResultValueLabelAt(int32_t aIndex, bool aGetFinalValue,
                                  bool aGetValue, nsAString & _retval);
 protected:
 
   /**
    * Gets and validates the defaultComplete result and the relative
    * defaultIndex value.
    *
    * @param aResultIndex
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
@@ -85,17 +85,18 @@ nsAutoCompleteSimpleResult::SetTypeAhead
   mTypeAheadResult = aTypeAheadResult;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::AppendMatch(const nsAString& aValue,
                                         const nsAString& aComment,
                                         const nsAString& aImage,
-                                        const nsAString& aStyle)
+                                        const nsAString& aStyle,
+                                        const nsAString& aFinalCompleteValue)
 {
   CheckInvariants();
 
   if (! mValues.AppendElement(aValue))
     return NS_ERROR_OUT_OF_MEMORY;
   if (! mComments.AppendElement(aComment)) {
     mValues.RemoveElementAt(mValues.Length() - 1);
     return NS_ERROR_OUT_OF_MEMORY;
@@ -106,16 +107,23 @@ nsAutoCompleteSimpleResult::AppendMatch(
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (! mStyles.AppendElement(aStyle)) {
     mValues.RemoveElementAt(mValues.Length() - 1);
     mComments.RemoveElementAt(mComments.Length() - 1);
     mImages.RemoveElementAt(mImages.Length() - 1);
     return NS_ERROR_OUT_OF_MEMORY;
   }
+  if (!mFinalCompleteValues.AppendElement(aFinalCompleteValue)) {
+    mValues.RemoveElementAt(mValues.Length() - 1);
+    mComments.RemoveElementAt(mComments.Length() - 1);
+    mImages.RemoveElementAt(mImages.Length() - 1);
+    mStyles.RemoveElementAt(mStyles.Length() - 1);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::GetMatchCount(uint32_t *aMatchCount)
 {
   CheckInvariants();
 
@@ -166,16 +174,29 @@ nsAutoCompleteSimpleResult::GetStyleAt(i
   NS_ENSURE_TRUE(aIndex >= 0 && aIndex < int32_t(mStyles.Length()),
                  NS_ERROR_ILLEGAL_VALUE);
   CheckInvariants();
   _retval = mStyles[aIndex];
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsAutoCompleteSimpleResult::GetFinalCompleteValueAt(int32_t aIndex,
+                                                    nsAString& _retval)
+{
+  NS_ENSURE_TRUE(aIndex >= 0 && aIndex < int32_t(mFinalCompleteValues.Length()),
+                 NS_ERROR_ILLEGAL_VALUE);
+  CheckInvariants();
+  _retval = mFinalCompleteValues[aIndex];
+  if (_retval.Length() == 0)
+    _retval = mValues[aIndex];
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsAutoCompleteSimpleResult::SetListener(nsIAutoCompleteSimpleResultListener* aListener)
 {
   mListener = aListener;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::RemoveValueAt(int32_t aRowIndex,
@@ -184,14 +205,15 @@ nsAutoCompleteSimpleResult::RemoveValueA
   NS_ENSURE_TRUE(aRowIndex >= 0 && aRowIndex < int32_t(mValues.Length()),
                  NS_ERROR_ILLEGAL_VALUE);
 
   nsAutoString removedValue(mValues[aRowIndex]);
   mValues.RemoveElementAt(aRowIndex);
   mComments.RemoveElementAt(aRowIndex);
   mImages.RemoveElementAt(aRowIndex);
   mStyles.RemoveElementAt(aRowIndex);
+  mFinalCompleteValues.RemoveElementAt(aRowIndex);
 
   if (mListener)
     mListener->OnValueRemoved(this, removedValue, aRemoveFromDb);
 
   return NS_OK;
 }
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
+++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
@@ -16,16 +16,17 @@
 class nsAutoCompleteSimpleResult MOZ_FINAL : public nsIAutoCompleteSimpleResult
 {
 public:
   nsAutoCompleteSimpleResult();
   inline void CheckInvariants() {
     NS_ASSERTION(mValues.Length() == mComments.Length(), "Arrays out of sync");
     NS_ASSERTION(mValues.Length() == mImages.Length(),   "Arrays out of sync");
     NS_ASSERTION(mValues.Length() == mStyles.Length(),   "Arrays out of sync");
+    NS_ASSERTION(mValues.Length() == mFinalCompleteValues.Length(), "Arrays out of sync");
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAUTOCOMPLETERESULT
   NS_DECL_NSIAUTOCOMPLETESIMPLERESULT
 
 private:
   ~nsAutoCompleteSimpleResult() {}
@@ -34,16 +35,17 @@ protected:
 
   // What we really want is an array of structs with value/comment/image/style contents.
   // But then we'd either have to use COM or manage object lifetimes ourselves.
   // Having four arrays of string simplifies this, but is stupid.
   nsTArray<nsString> mValues;
   nsTArray<nsString> mComments;
   nsTArray<nsString> mImages;
   nsTArray<nsString> mStyles;
+  nsTArray<nsString> mFinalCompleteValues;
 
   nsString mSearchString;
   nsString mErrorDescription;
   int32_t mDefaultIndex;
   uint32_t mSearchResult;
 
   bool mTypeAheadResult;
 
--- a/toolkit/components/autocomplete/nsIAutoCompleteController.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteController.idl
@@ -1,17 +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/. */
 
 #include "nsISupports.idl"
 
 interface nsIAutoCompleteInput;
 
-[scriptable, uuid(dd2c4489-e4bd-4702-86bc-e1691744e556)]
+[scriptable, uuid(ff9f8465-204a-47a6-b3c9-0628b3856684)]
 interface nsIAutoCompleteController : nsISupports
 {
   /*
    * Possible values for the searchStatus attribute
    */
   const unsigned short STATUS_NONE = 1;
   const unsigned short STATUS_SEARCHING = 2;
   const unsigned short STATUS_COMPLETE_NO_MATCH = 3;
@@ -130,12 +130,18 @@ interface nsIAutoCompleteController : ns
   AString getStyleAt(in long index);
 
   /*
    * Get the url of the image of the result at a given index in the last completed search
    */
   AString getImageAt(in long index);
 
   /*
+   * For the last completed search, get the final value that should be completed
+   * when the user confirms the match at the given index
+   */
+  AString getFinalCompleteValueAt(in long index);
+
+  /*
    * Get / set the current search string.  Note, setting will not start searching
    */
   attribute AString searchString;
 };
--- a/toolkit/components/autocomplete/nsIAutoCompleteResult.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteResult.idl
@@ -1,15 +1,15 @@
 /* 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/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(7b43fad1-c735-4b45-9383-c3f057fed20d)]
+[scriptable, uuid(9203c031-c4e7-4537-a4ec-81443d623d5a)]
 interface nsIAutoCompleteResult : nsISupports
 {
   /**
    * Possible values for the searchResult attribute
    */
   const unsigned short RESULT_IGNORED = 1; /* indicates invalid searchString */
   const unsigned short RESULT_FAILURE = 2; /* indicates failure */
   const unsigned short RESULT_NOMATCH = 3; /* indicates success with no matches
@@ -77,14 +77,20 @@ interface nsIAutoCompleteResult : nsISup
   AString getStyleAt(in long index);
 
   /**
    * Get the image of the result at the given index
    */
   AString getImageAt(in long index);
 
   /**
+   * Get the final value that should be completed when the user confirms
+   * the match at the given index.
+   */
+  AString getFinalCompleteValueAt(in long index);
+
+  /**
    * Remove the value at the given index from the autocomplete results.
    * If removeFromDb is set to true, the value should be removed from
    * persistent storage as well.
    */
   void removeValueAt(in long rowIndex, in boolean removeFromDb);
 };
--- a/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
@@ -9,17 +9,17 @@ interface nsIAutoCompleteSimpleResultLis
 
 /**
  * This class implements nsIAutoCompleteResult and provides simple methods
  * for setting the value and result items. It can be used whenever some basic
  * auto complete results are needed that can be pre-generated and filled into
  * an array.
  */
 
-[scriptable, uuid(c738dc26-aa71-4561-a3fd-b5a0e4aa80d2)]
+[scriptable, uuid(fe8802f9-c2b7-4141-8e5b-280df3f62251)]
 interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult
 {
   /**
    * A writer for the readonly attribute 'searchString' which should contain
    * the string that the user typed.
    */
   void setSearchString(in AString aSearchString);
 
@@ -43,22 +43,35 @@ interface nsIAutoCompleteSimpleResult : 
 
   /**
    * A writer for the readonly attribute 'typeAheadResult', typically set
    * because a result is only intended for type-ahead completion.
    */
   void setTypeAheadResult(in boolean aHidden);
 
   /**
-   * Appends a result item consisting of the given value, comment, image and style.
-   * This is how you add results.  Note:  image and style are optional. 
+   * Appends a match consisting of the given value, comment, image, style and
+   * the value to use for defaultIndex completion.
+   * @param aValue
+   *        The value to autocomplete to
+   * @param aComment
+   *        Comment shown in the autocomplete widget to describe this match
+   * @param aImage
+   *        Image shown in the autocomplete widget for this match.
+   * @param aStyle
+   *        Describes how to style the match in the autocomplete widget
+   * @param aFinalCompleteValue
+   *        Value used when the user confirms selecting this match. If not
+   *        provided, aValue will be used.
    */
-  void appendMatch(in AString aValue, in AString aComment, 
-                   [optional] in AString aImage, 
-                   [optional] in AString aStyle);
+  void appendMatch(in AString aValue,
+                   in AString aComment,
+                   [optional] in AString aImage,
+                   [optional] in AString aStyle,
+                   [optional] in AString aFinalCompleteValue);
 
   /**
    * Sets a listener for changes in the result.
    */
   void setListener(in nsIAutoCompleteSimpleResultListener aListener);
 };
 
 [scriptable, uuid(004efdc5-1989-4874-8a7a-345bf2fa33af)]
--- a/toolkit/components/autocomplete/tests/unit/head_autocomplete.js
+++ b/toolkit/components/autocomplete/tests/unit/head_autocomplete.js
@@ -73,17 +73,18 @@ function AutoCompleteResultBase(aValues)
   this._values = aValues;
 }
 AutoCompleteResultBase.prototype = {
   
   // Arrays
   _values: null,
   _comments: [],
   _styles: [],
-  
+  _finalCompleteValues: [],
+
   searchString: "",
   searchResult: null,
   
   defaultIndex: -1,
   
   _typeAheadResult: false,
   get typeAheadResult() {
     return this._typeAheadResult;
@@ -108,16 +109,20 @@ AutoCompleteResultBase.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this._finalCompleteValues[aIndex] || this._values[aIndex];
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult])
 }
 
 /** 
  * nsIAutoCompleteSearch implementation that always returns
--- a/toolkit/components/autocomplete/tests/unit/test_378079.js
+++ b/toolkit/components/autocomplete/tests/unit/test_378079.js
@@ -118,16 +118,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/test_393191.js
+++ b/toolkit/components/autocomplete/tests/unit/test_393191.js
@@ -117,16 +117,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/test_440866.js
+++ b/toolkit/components/autocomplete/tests/unit/test_440866.js
@@ -116,16 +116,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
 
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
+++ b/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
@@ -105,16 +105,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js
@@ -0,0 +1,54 @@
+/* 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/. */
+
+function AutoCompleteResult(aValues, aFinalCompleteValues) {
+  this._values = aValues;
+  this._finalCompleteValues = aFinalCompleteValues;
+}
+AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
+
+function AutoCompleteInput(aSearches) {
+  this.searches = aSearches;
+  this.popup.selectedIndex = 0;
+}
+AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
+
+function run_test() {
+  run_next_test();
+}
+
+add_test(function test_handleEnter() {
+  doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) {
+    do_check_eq(aController.input.textValue, "moz");
+    do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
+    aController.handleEnter(false);
+    do_check_eq(aController.input.textValue, "http://www.mozilla.com");
+  });
+});
+
+function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
+  let search = new AutoCompleteSearchBase(
+    "search",
+    new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
+  );
+  registerAutoCompleteSearch(search);
+
+  let controller = Cc["@mozilla.org/autocomplete/controller;1"].
+                   getService(Ci.nsIAutoCompleteController);  
+  
+  // Make an AutoCompleteInput that uses our searches and confirms results.
+  let input = new AutoCompleteInput([ search.name ]);
+  input.textValue = aSearchString;
+
+  controller.input = input;
+  controller.startSearch(aSearchString);
+
+  input.onSearchComplete = function onSearchComplete() {
+    aOnCompleteCallback(controller);
+
+    // Clean up.
+    unregisterAutoCompleteSearch(search);
+    run_next_test();
+  };
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue_forceComplete.js
@@ -0,0 +1,56 @@
+/* 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/. */
+
+function AutoCompleteResult(aValues, aFinalCompleteValues) {
+  this._values = aValues;
+  this._finalCompleteValues = aFinalCompleteValues;
+  this.defaultIndex = 0;
+}
+AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
+
+function AutoCompleteInput(aSearches) {
+  this.searches = aSearches;
+  this.popup.selectedIndex = -1;
+}
+AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
+
+function run_test() {
+  run_next_test();
+}
+
+add_test(function test_handleEnter() {
+  doSearch("", "mozilla.com", "http://www.mozilla.com", function(aController) {
+    do_check_eq(aController.input.textValue, "");
+    do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
+    aController.input.forceComplete = true;
+    aController.handleEnter(false);
+    do_check_eq(aController.input.textValue, "http://www.mozilla.com");
+  });
+});
+
+function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
+  let search = new AutoCompleteSearchBase(
+    "search",
+    new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
+  );
+  registerAutoCompleteSearch(search);
+
+  let controller = Cc["@mozilla.org/autocomplete/controller;1"].
+                   getService(Ci.nsIAutoCompleteController);  
+  
+  // Make an AutoCompleteInput that uses our searches and confirms results.
+  let input = new AutoCompleteInput([ search.name ]);
+  input.textValue = aSearchString;
+
+  controller.input = input;
+  controller.startSearch(aSearchString);
+
+  input.onSearchComplete = function onSearchComplete() {
+    aOnCompleteCallback(controller);
+
+    // Clean up.
+    unregisterAutoCompleteSearch(search);
+    run_next_test();
+  };
+}
--- a/toolkit/components/autocomplete/tests/unit/test_finalDefaultCompleteValue.js
+++ b/toolkit/components/autocomplete/tests/unit/test_finalDefaultCompleteValue.js
@@ -1,17 +1,16 @@
 /* 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/. */
 
-function AutoCompleteResult(aValues, aComments) {
+function AutoCompleteResult(aValues, aFinalCompleteValues) {
   this._values = aValues;
-  this._comments = aComments;
+  this._finalCompleteValues = aFinalCompleteValues;
   this.defaultIndex = 0;
-  this._typeAheadResult = true;
 }
 AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
 
 function AutoCompleteInput(aSearches) {
   this.searches = aSearches;
   this.popup.selectedIndex = -1;
   this.completeDefaultIndex = true;
 }
@@ -32,20 +31,20 @@ add_test(function test_keyNavigation() {
 add_test(function test_handleEnter() {
   doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) {
     do_check_eq(aController.input.textValue, "mozilla.com");
     aController.handleEnter(false);
     do_check_eq(aController.input.textValue, "http://www.mozilla.com");
   });
 });
 
-function doSearch(aSearchString, aResultValue, aCommentValue, aOnCompleteCallback) {
+function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
   let search = new AutoCompleteSearchBase(
     "search",
-    new AutoCompleteResult([ aResultValue ], [ aCommentValue ], 0)
+    new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
   );
   registerAutoCompleteSearch(search);
 
   let controller = Cc["@mozilla.org/autocomplete/controller;1"].
                    getService(Ci.nsIAutoCompleteController);  
   
   // Make an AutoCompleteInput that uses our searches and confirms results.
   let input = new AutoCompleteInput([ search.name ]);
--- a/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js
+++ b/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js
@@ -1,23 +1,22 @@
 /* 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/. */
 
-function AutoCompleteTypeAheadResult(aValues, aComments) {
+function AutoCompleteTypeAheadResult(aValues, aFinalCompleteValues) {
   this._values = aValues;
-  this._comments = aComments;
+  this._finalCompleteValues = aFinalCompleteValues;
   this.defaultIndex = 0;
   this._typeAheadResult = true;
 }
 AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype);
 
-function AutoCompleteResult(aValues, aComments) {
+function AutoCompleteResult(aValues) {
   this._values = aValues;
-  this._comments = aComments;
 }
 AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
 
 function AutoCompleteInput(aSearches) {
   this.searches = aSearches;
   this.popupOpen = true;
   this.completeDefaultIndex = true;
   this.completeSelectedIndex = true;
@@ -40,17 +39,17 @@ function doSearch(aSearchString, aOnComp
   let typeAheadSearch = new AutoCompleteSearchBase(
     "typeAheadSearch",
     new AutoCompleteTypeAheadResult([ "mozilla.com" ], [ "http://www.mozilla.com" ])
   );
   registerAutoCompleteSearch(typeAheadSearch);
 
   let search = new AutoCompleteSearchBase(
     "search",
-    new AutoCompleteResult([ "mozilla.org" ], [ "http://www.mozilla.org" ])
+    new AutoCompleteResult([ "mozilla.org" ])
   );
   registerAutoCompleteSearch(search);
 
   let controller = Cc["@mozilla.org/autocomplete/controller;1"].
                    getService(Ci.nsIAutoCompleteController);
 
   // Make an AutoCompleteInput that uses our searches and confirms results.
   let input = new AutoCompleteInput([ typeAheadSearch.name, search.name ]);
--- a/toolkit/components/autocomplete/tests/unit/test_previousResult.js
+++ b/toolkit/components/autocomplete/tests/unit/test_previousResult.js
@@ -116,16 +116,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/xpcshell.ini
+++ b/toolkit/components/autocomplete/tests/unit/xpcshell.ini
@@ -6,14 +6,16 @@ tail =
 [test_378079.js]
 [test_393191.js]
 [test_440866.js]
 [test_463023.js]
 [test_660156.js]
 [test_autocomplete_multiple.js]
 [test_badDefaultIndex.js]
 [test_completeDefaultIndex_casing.js]
+[test_finalCompleteValue.js]
+[test_finalCompleteValue_forceComplete.js]
 [test_finalDefaultCompleteValue.js]
 [test_hiddenResult.js]
 [test_immediate_search.js]
 [test_popupSelectionVsDefaultCompleteValue.js]
 [test_previousResult.js]
 [test_stopSearch.js]
--- a/toolkit/components/filepicker/nsFileView.cpp
+++ b/toolkit/components/filepicker/nsFileView.cpp
@@ -167,16 +167,21 @@ NS_IMETHODIMP nsFileResult::GetStyleAt(i
   return NS_OK;
 }
 
 NS_IMETHODIMP nsFileResult::GetImageAt(int32_t index, nsAString & aImage)
 {
   aImage.Truncate();
   return NS_OK;
 }
+NS_IMETHODIMP nsFileResult::GetFinalCompleteValueAt(int32_t index,
+                                                    nsAString & aValue)
+{
+  return GetValueAt(index, aValue);
+}
 
 NS_IMETHODIMP nsFileResult::RemoveValueAt(int32_t rowIndex, bool removeFromDb)
 {
   return NS_OK;
 }
 
 class nsFileComplete MOZ_FINAL : public nsIAutoCompleteSearch
 {
--- a/toolkit/components/passwordmgr/nsLoginManager.js
+++ b/toolkit/components/passwordmgr/nsLoginManager.js
@@ -606,16 +606,20 @@ UserAutoCompleteResult.prototype = {
     getStyleAt : function (index) {
         return "";
     },
 
     getImageAt : function (index) {
         return "";
     },
 
+    getFinalCompleteValueAt : function (index) {
+        return this.getValueAt(index);
+    },
+
     removeValueAt : function (index, removeFromDB) {
         if (index < 0 || index >= this.logins.length)
             throw "Index out of range.";
 
         var [removedLogin] = this.logins.splice(index, 1);
 
         this.matchCount--;
         if (this.defaultIndex > this.logins.length)
--- a/toolkit/components/places/nsPlacesAutoComplete.js
+++ b/toolkit/components/places/nsPlacesAutoComplete.js
@@ -1399,19 +1399,17 @@ urlInlineComplete.prototype = {
         let untrimmedHost = row.getResultByIndex(1);
         // If the untrimmed value doesn't preserve the user's input just
         // ignore it and complete to the found host.
         if (untrimmedHost &&
             !untrimmedHost.toLowerCase().contains(ac._originalSearchString.toLowerCase())) {
           untrimmedHost = null;
         }
 
-        // TODO (bug 754265): this is a temporary solution introduced while
-        // waiting for a propert dedicated API.
-        ac._result.appendMatch(ac._strippedPrefix + trimmedHost, untrimmedHost);
+        ac._result.appendMatch(ac._strippedPrefix + trimmedHost, "", "", "", untrimmedHost);
 
         // handleCompletion() will cause the result listener to be called, and
         // will display the result in the UI.
       },
 
       handleError: function (aError) {
         Components.utils.reportError(
           "URL Inline Complete: An async statement encountered an " +
@@ -1475,19 +1473,17 @@ urlInlineComplete.prototype = {
         // If the untrimmed value doesn't preserve the user's input just
         // ignore it and complete to the found url.
         let untrimmedURL = prefix + url;
         if (untrimmedURL &&
             !untrimmedURL.toLowerCase().contains(ac._originalSearchString.toLowerCase())) {
           untrimmedURL = null;
          }
 
-        // TODO (bug 754265): this is a temporary solution introduced while
-        // waiting for a propert dedicated API.
-        ac._result.appendMatch(ac._strippedPrefix + url, untrimmedURL);
+        ac._result.appendMatch(ac._strippedPrefix + url, "", "", "", untrimmedURL);
 
         // handleCompletion() will cause the result listener to be called, and
         // will display the result in the UI.
       },
 
       handleError: function(aError) {
         Components.utils.reportError(
           "URL Inline Complete: An async statement encountered an " +
--- a/toolkit/components/places/nsTaggingService.js
+++ b/toolkit/components/places/nsTaggingService.js
@@ -538,16 +538,23 @@ TagAutoCompleteResult.prototype = {
   /**
    * Get the image for the result at the given index
    */
   getImageAt: function PTACR_getImageAt(index) {
     return null;
   },
 
   /**
+   * Get the image for the result at the given index
+   */
+  getFinalCompleteValueAt: function PTACR_getFinalCompleteValueAt(index) {
+    return this.getValueAt(index);
+  },
+
+  /**
    * Remove the value at the given index from the autocomplete results.
    * If removeFromDb is set to true, the value should be removed from
    * persistent storage as well.
    */
   removeValueAt: function PTACR_removeValueAt(index, removeFromDb) {
     this._results.splice(index, 1);
     this._comments.splice(index, 1);
   },
--- a/toolkit/components/satchel/nsFormAutoComplete.js
+++ b/toolkit/components/satchel/nsFormAutoComplete.js
@@ -471,16 +471,20 @@ FormAutoCompleteResult.prototype = {
         return "";
     },
 
     getImageAt : function (index) {
         this._checkIndexBounds(index);
         return "";
     },
 
+    getFinalCompleteValueAt : function (index) {
+        return this.getValueAt(index);
+    },
+
     removeValueAt : function (index, removeFromDB) {
         this._checkIndexBounds(index);
 
         let [removedEntry] = this.entries.splice(index, 1);
 
         if (removeFromDB) {
           this.formHistory.update({ op: "remove",
                                     fieldname: this.fieldName,
--- a/toolkit/components/satchel/nsFormAutoCompleteResult.jsm
+++ b/toolkit/components/satchel/nsFormAutoCompleteResult.jsm
@@ -147,16 +147,25 @@ FormAutoCompleteResult.prototype = {
    * @return          the image url at the specified index
    */
   getImageAt: function(index) {
     this._checkIndexBounds(index);
     return "";
   },
 
   /**
+   * Retrieves a result
+   * @param  index    the index of the result requested
+   * @return          the result at the specified index
+   */
+  getFinalCompleteValueAt: function(index) {
+    return this.getValueAt(index);
+  },
+
+  /**
    * Removes a result from the resultset
    * @param  index    the index of the result to remove
    */
   removeValueAt: function(index, removeFromDatabase) {
     this._checkIndexBounds(index);
     // Forward the removeValueAt call to the underlying result if we have one
     // Note: this assumes that the form history results were added to the top
     // of our arrays.
--- a/toolkit/content/tests/chrome/test_autocomplete2.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete2.xul
@@ -39,16 +39,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: -1,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete3.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete3.xul
@@ -39,16 +39,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete4.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete4.xul
@@ -41,16 +41,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete5.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete5.xul
@@ -37,16 +37,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: -1,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
@@ -37,16 +37,17 @@ autoCompleteSimpleResult.prototype = {
  searchResult: Components.interfaces.nsIAutoCompleteResult.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that returns one result.
 let autoCompleteSimple = {
   classID: Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"),
   contractID: "@mozilla.org/autocomplete/search;1?name=simple",
--- a/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul
@@ -52,16 +52,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: nsIAutoCompleteResult.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function(aIndex) { return aIndex == 0 ? this._value : null; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function(aIndex) { return this.getValueAt(aIndex); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID =
   Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName =