LCOV - code coverage report
Current view: top level - toolkit/components/autocomplete - nsAutoCompleteController.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 10 940 1.1 %
Date: 2017-07-14 16:53:18 Functions: 5 95 5.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsAutoCompleteController.h"
       7             : #include "nsAutoCompleteSimpleResult.h"
       8             : 
       9             : #include "nsAutoPtr.h"
      10             : #include "nsNetCID.h"
      11             : #include "nsIIOService.h"
      12             : #include "nsToolkitCompsCID.h"
      13             : #include "nsIServiceManager.h"
      14             : #include "nsReadableUtils.h"
      15             : #include "nsUnicharUtils.h"
      16             : #include "nsIScriptSecurityManager.h"
      17             : #include "nsITreeBoxObject.h"
      18             : #include "nsITreeColumns.h"
      19             : #include "nsIObserverService.h"
      20             : #include "nsIDOMKeyEvent.h"
      21             : #include "mozilla/Services.h"
      22             : #include "mozilla/ModuleUtils.h"
      23             : #include "mozilla/Unused.h"
      24             : 
      25             : static const char *kAutoCompleteSearchCID = "@mozilla.org/autocomplete/search;1?name=";
      26             : 
      27             : using namespace mozilla;
      28             : 
      29             : namespace {
      30             : 
      31             : void
      32           0 : SetTextValue(nsIAutoCompleteInput* aInput,
      33             :              const nsString& aValue,
      34             :              uint16_t aReason) {
      35           0 :   nsresult rv = aInput->SetTextValueWithReason(aValue, aReason);
      36           0 :   if (NS_FAILED(rv)) {
      37           0 :     aInput->SetTextValue(aValue);
      38             :   }
      39           0 : }
      40             : 
      41             : } // anon namespace
      42             : 
      43             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsAutoCompleteController)
      44             : 
      45           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAutoCompleteController)
      46           0 :   tmp->SetInput(nullptr);
      47           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      48           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAutoCompleteController)
      49           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInput)
      50           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearches)
      51           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResults)
      52           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      53             : 
      54          17 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAutoCompleteController)
      55           9 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAutoCompleteController)
      56          21 : NS_INTERFACE_TABLE_HEAD(nsAutoCompleteController)
      57          21 :   NS_INTERFACE_TABLE(nsAutoCompleteController, nsIAutoCompleteController,
      58             :                      nsIAutoCompleteObserver, nsITimerCallback, nsITreeView)
      59          21 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsAutoCompleteController)
      60           8 : NS_INTERFACE_MAP_END
      61             : 
      62           3 : nsAutoCompleteController::nsAutoCompleteController() :
      63             :   mDefaultIndexCompleted(false),
      64             :   mPopupClosedByCompositionStart(false),
      65             :   mProhibitAutoFill(false),
      66             :   mUserClearedAutoFill(false),
      67             :   mClearingAutoFillSearchesAgain(false),
      68             :   mCompositionState(eCompositionState_None),
      69             :   mSearchStatus(nsAutoCompleteController::STATUS_NONE),
      70             :   mRowCount(0),
      71             :   mSearchesOngoing(0),
      72             :   mSearchesFailed(0),
      73             :   mFirstSearchResult(false),
      74             :   mImmediateSearchesCount(0),
      75           3 :   mCompletedSelectionIndex(-1)
      76             : {
      77           3 : }
      78             : 
      79           0 : nsAutoCompleteController::~nsAutoCompleteController()
      80             : {
      81           0 :   SetInput(nullptr);
      82           0 : }
      83             : 
      84             : ////////////////////////////////////////////////////////////////////////
      85             : //// nsIAutoCompleteController
      86             : 
      87             : NS_IMETHODIMP
      88           0 : nsAutoCompleteController::GetSearchStatus(uint16_t *aSearchStatus)
      89             : {
      90           0 :   *aSearchStatus = mSearchStatus;
      91           0 :   return NS_OK;
      92             : }
      93             : 
      94             : NS_IMETHODIMP
      95           0 : nsAutoCompleteController::GetMatchCount(uint32_t *aMatchCount)
      96             : {
      97           0 :   *aMatchCount = mRowCount;
      98           0 :   return NS_OK;
      99             : }
     100             : 
     101             : NS_IMETHODIMP
     102           0 : nsAutoCompleteController::GetInput(nsIAutoCompleteInput **aInput)
     103             : {
     104           0 :   *aInput = mInput;
     105           0 :   NS_IF_ADDREF(*aInput);
     106           0 :   return NS_OK;
     107             : }
     108             : 
     109             : NS_IMETHODIMP
     110           0 : nsAutoCompleteController::SetInitiallySelectedIndex(int32_t aSelectedIndex)
     111             : {
     112             :   // First forward to the popup.
     113           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     114           0 :   NS_ENSURE_STATE(input);
     115           0 :   nsCOMPtr<nsIAutoCompletePopup> popup;
     116           0 :   input->GetPopup(getter_AddRefs(popup));
     117           0 :   NS_ENSURE_STATE(popup);
     118           0 :   popup->SetSelectedIndex(aSelectedIndex);
     119             : 
     120             :   // Now take care of internal stuff.
     121             :   bool completeSelection;
     122           0 :   if (NS_SUCCEEDED(input->GetCompleteSelectedIndex(&completeSelection)) &&
     123             :       completeSelection) {
     124           0 :     mCompletedSelectionIndex = aSelectedIndex;
     125             :   }
     126           0 :   return NS_OK;
     127             : }
     128             : 
     129             : NS_IMETHODIMP
     130           0 : nsAutoCompleteController::SetInput(nsIAutoCompleteInput *aInput)
     131             : {
     132             :   // Don't do anything if the input isn't changing.
     133           0 :   if (mInput == aInput)
     134           0 :     return NS_OK;
     135             : 
     136           0 :   Unused << ResetInternalState();
     137           0 :   if (mInput) {
     138           0 :     mSearches.Clear();
     139           0 :     ClosePopup();
     140             :   }
     141             : 
     142           0 :   mInput = aInput;
     143             : 
     144             :   // Nothing more to do if the input was just being set to null.
     145           0 :   if (!mInput) {
     146           0 :     return NS_OK;
     147             :   }
     148           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     149             : 
     150             :   // Reset the current search string.
     151           0 :   input->GetTextValue(mSearchString);
     152             : 
     153             :   // Clear out this reference in case the new input's popup has no tree
     154           0 :   mTree = nullptr;
     155             : 
     156             :   // Initialize our list of search objects
     157             :   uint32_t searchCount;
     158           0 :   input->GetSearchCount(&searchCount);
     159           0 :   mResults.SetCapacity(searchCount);
     160           0 :   mSearches.SetCapacity(searchCount);
     161           0 :   mImmediateSearchesCount = 0;
     162             : 
     163           0 :   const char *searchCID = kAutoCompleteSearchCID;
     164             : 
     165             :   // Since the controller can be used as a service it's important to reset this.
     166           0 :   mClearingAutoFillSearchesAgain = false;
     167             : 
     168           0 :   for (uint32_t i = 0; i < searchCount; ++i) {
     169             :     // Use the search name to create the contract id string for the search service
     170           0 :     nsAutoCString searchName;
     171           0 :     input->GetSearchAt(i, searchName);
     172           0 :     nsAutoCString cid(searchCID);
     173           0 :     cid.Append(searchName);
     174             : 
     175             :     // Use the created cid to get a pointer to the search service and store it for later
     176           0 :     nsCOMPtr<nsIAutoCompleteSearch> search = do_GetService(cid.get());
     177           0 :     if (search) {
     178           0 :       mSearches.AppendObject(search);
     179             : 
     180             :       // Count immediate searches.
     181             :       nsCOMPtr<nsIAutoCompleteSearchDescriptor> searchDesc =
     182           0 :         do_QueryInterface(search);
     183           0 :       if (searchDesc) {
     184           0 :         uint16_t searchType = nsIAutoCompleteSearchDescriptor::SEARCH_TYPE_DELAYED;
     185           0 :         if (NS_SUCCEEDED(searchDesc->GetSearchType(&searchType)) &&
     186           0 :             searchType == nsIAutoCompleteSearchDescriptor::SEARCH_TYPE_IMMEDIATE) {
     187           0 :           mImmediateSearchesCount++;
     188             :         }
     189             : 
     190           0 :         if (!mClearingAutoFillSearchesAgain) {
     191           0 :           searchDesc->GetClearingAutoFillSearchesAgain(&mClearingAutoFillSearchesAgain);
     192             :         }
     193             :       }
     194             :     }
     195             :   }
     196             : 
     197           0 :   return NS_OK;
     198             : }
     199             : 
     200             : NS_IMETHODIMP
     201           0 : nsAutoCompleteController::ResetInternalState()
     202             : {
     203             :   // Clear out the current search context
     204           0 :   if (mInput) {
     205           0 :     nsAutoString value;
     206           0 :     mInput->GetTextValue(value);
     207             :     // Stop all searches in case they are async.
     208           0 :     Unused << StopSearch();
     209           0 :     Unused << ClearResults();
     210           0 :     mSearchString = value;
     211             :   }
     212             : 
     213           0 :   mPlaceholderCompletionString.Truncate();
     214           0 :   mDefaultIndexCompleted = false;
     215           0 :   mProhibitAutoFill = false;
     216           0 :   mSearchStatus = nsIAutoCompleteController::STATUS_NONE;
     217           0 :   mRowCount = 0;
     218           0 :   mCompletedSelectionIndex = -1;
     219             : 
     220           0 :   return NS_OK;
     221             : }
     222             : 
     223             : NS_IMETHODIMP
     224           0 : nsAutoCompleteController::StartSearch(const nsAString &aSearchString)
     225             : {
     226           0 :   mSearchString = aSearchString;
     227           0 :   StartSearches();
     228           0 :   return NS_OK;
     229             : }
     230             : 
     231             : NS_IMETHODIMP
     232           0 : nsAutoCompleteController::HandleText(bool *_retval)
     233             : {
     234           0 :   *_retval = false;
     235             :   // Note: the events occur in the following order when IME is used.
     236             :   // 1. a compositionstart event(HandleStartComposition)
     237             :   // 2. some input events (HandleText), eCompositionState_Composing
     238             :   // 3. a compositionend event(HandleEndComposition)
     239             :   // 4. an input event(HandleText), eCompositionState_Committing
     240             :   // We should do nothing during composition.
     241           0 :   if (mCompositionState == eCompositionState_Composing) {
     242           0 :     return NS_OK;
     243             :   }
     244             : 
     245             :   bool handlingCompositionCommit =
     246           0 :     (mCompositionState == eCompositionState_Committing);
     247           0 :   bool popupClosedByCompositionStart = mPopupClosedByCompositionStart;
     248           0 :   if (handlingCompositionCommit) {
     249           0 :     mCompositionState = eCompositionState_None;
     250           0 :     mPopupClosedByCompositionStart = false;
     251             :   }
     252             : 
     253           0 :   if (!mInput) {
     254             :     // Stop all searches in case they are async.
     255           0 :     StopSearch();
     256             :     // Note: if now is after blur and IME end composition,
     257             :     // check mInput before calling.
     258             :     // See https://bugzilla.mozilla.org/show_bug.cgi?id=193544#c31
     259           0 :     NS_ERROR("Called before attaching to the control or after detaching from the control");
     260           0 :     return NS_OK;
     261             :   }
     262             : 
     263           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     264           0 :   nsAutoString newValue;
     265           0 :   input->GetTextValue(newValue);
     266             : 
     267             :   // Stop all searches in case they are async.
     268           0 :   StopSearch();
     269             : 
     270           0 :   if (!mInput) {
     271             :     // StopSearch() can call PostSearchCleanup() which might result
     272             :     // in a blur event, which could null out mInput, so we need to check it
     273             :     // again.  See bug #395344 for more details
     274           0 :     return NS_OK;
     275             :   }
     276             : 
     277             :   bool disabled;
     278           0 :   input->GetDisableAutoComplete(&disabled);
     279           0 :   NS_ENSURE_TRUE(!disabled, NS_OK);
     280             : 
     281             :   // Usually we don't search again if the new string is the same as the last one.
     282             :   // However, if this is called immediately after compositionend event,
     283             :   // we need to search the same value again since the search was canceled
     284             :   // at compositionstart event handler.
     285             :   // The new string might also be the same as the last search if the autofilled
     286             :   // portion was cleared. In this case, we may want to search again.
     287             : 
     288             :   // Whether the user removed some text at the end.
     289             :   bool userRemovedText =
     290           0 :     newValue.Length() < mSearchString.Length() &&
     291           0 :     Substring(mSearchString, 0, newValue.Length()).Equals(newValue);
     292             : 
     293             :   // Whether the user is repeating the previous search.
     294           0 :   bool repeatingPreviousSearch = !userRemovedText &&
     295           0 :                                  newValue.Equals(mSearchString);
     296             : 
     297           0 :   mUserClearedAutoFill =
     298           0 :     repeatingPreviousSearch &&
     299           0 :     newValue.Length() < mPlaceholderCompletionString.Length() &&
     300           0 :     Substring(mPlaceholderCompletionString, 0, newValue.Length()).Equals(newValue);
     301           0 :   bool searchAgainOnAutoFillClear = mUserClearedAutoFill && mClearingAutoFillSearchesAgain;
     302             : 
     303           0 :   if (!handlingCompositionCommit &&
     304           0 :       !searchAgainOnAutoFillClear &&
     305           0 :       newValue.Length() > 0 &&
     306             :       repeatingPreviousSearch) {
     307           0 :     return NS_OK;
     308             :   }
     309             : 
     310           0 :   if (userRemovedText || searchAgainOnAutoFillClear) {
     311           0 :     if (userRemovedText) {
     312             :       // We need to throw away previous results so we don't try to search
     313             :       // through them again.
     314           0 :       ClearResults();
     315             :     }
     316           0 :     mProhibitAutoFill = true;
     317           0 :     mPlaceholderCompletionString.Truncate();
     318             :   } else {
     319           0 :     mProhibitAutoFill = false;
     320             :   }
     321             : 
     322           0 :   mSearchString = newValue;
     323             : 
     324             :   // Don't search if the value is empty
     325           0 :   if (newValue.Length() == 0) {
     326             :     // If autocomplete popup was closed by compositionstart event handler,
     327             :     // we should reopen it forcibly even if the value is empty.
     328           0 :     if (popupClosedByCompositionStart && handlingCompositionCommit) {
     329             :       bool cancel;
     330           0 :       HandleKeyNavigation(nsIDOMKeyEvent::DOM_VK_DOWN, &cancel);
     331           0 :       return NS_OK;
     332             :     }
     333           0 :     ClosePopup();
     334           0 :     return NS_OK;
     335             :   }
     336             : 
     337           0 :   *_retval = true;
     338           0 :   StartSearches();
     339             : 
     340           0 :   return NS_OK;
     341             : }
     342             : 
     343             : NS_IMETHODIMP
     344           0 : nsAutoCompleteController::HandleEnter(bool aIsPopupSelection,
     345             :                                       nsIDOMEvent *aEvent,
     346             :                                       bool *_retval)
     347             : {
     348           0 :   *_retval = false;
     349           0 :   if (!mInput)
     350           0 :     return NS_OK;
     351             : 
     352           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     353             : 
     354             :   // allow the event through unless there is something selected in the popup
     355           0 :   input->GetPopupOpen(_retval);
     356           0 :   if (*_retval) {
     357           0 :     nsCOMPtr<nsIAutoCompletePopup> popup;
     358           0 :     input->GetPopup(getter_AddRefs(popup));
     359             : 
     360           0 :     if (popup) {
     361             :       int32_t selectedIndex;
     362           0 :       popup->GetSelectedIndex(&selectedIndex);
     363           0 :       *_retval = selectedIndex >= 0;
     364             :     }
     365             :   }
     366             : 
     367             :   // Stop the search, and handle the enter.
     368           0 :   StopSearch();
     369           0 :   EnterMatch(aIsPopupSelection, aEvent);
     370             : 
     371           0 :   return NS_OK;
     372             : }
     373             : 
     374             : NS_IMETHODIMP
     375           0 : nsAutoCompleteController::HandleEscape(bool *_retval)
     376             : {
     377           0 :   *_retval = false;
     378           0 :   if (!mInput)
     379           0 :     return NS_OK;
     380             : 
     381           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     382             : 
     383             :   // allow the event through if the popup is closed
     384           0 :   input->GetPopupOpen(_retval);
     385             : 
     386             :   // Stop all searches in case they are async.
     387           0 :   StopSearch();
     388           0 :   ClearResults();
     389           0 :   RevertTextValue();
     390           0 :   ClosePopup();
     391             : 
     392           0 :   return NS_OK;
     393             : }
     394             : 
     395             : NS_IMETHODIMP
     396           0 : nsAutoCompleteController::HandleStartComposition()
     397             : {
     398           0 :   NS_ENSURE_TRUE(mCompositionState != eCompositionState_Composing, NS_OK);
     399             : 
     400           0 :   mPopupClosedByCompositionStart = false;
     401           0 :   mCompositionState = eCompositionState_Composing;
     402             : 
     403           0 :   if (!mInput)
     404           0 :     return NS_OK;
     405             : 
     406           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     407             :   bool disabled;
     408           0 :   input->GetDisableAutoComplete(&disabled);
     409           0 :   if (disabled)
     410           0 :     return NS_OK;
     411             : 
     412             :   // Stop all searches in case they are async.
     413           0 :   StopSearch();
     414             : 
     415           0 :   bool isOpen = false;
     416           0 :   input->GetPopupOpen(&isOpen);
     417           0 :   if (isOpen) {
     418           0 :     ClosePopup();
     419             : 
     420           0 :     bool stillOpen = false;
     421           0 :     input->GetPopupOpen(&stillOpen);
     422           0 :     mPopupClosedByCompositionStart = !stillOpen;
     423             :   }
     424           0 :   return NS_OK;
     425             : }
     426             : 
     427             : NS_IMETHODIMP
     428           0 : nsAutoCompleteController::HandleEndComposition()
     429             : {
     430           0 :   NS_ENSURE_TRUE(mCompositionState == eCompositionState_Composing, NS_OK);
     431             : 
     432             :   // We can't yet retrieve the committed value from the editor, since it isn't
     433             :   // completely committed yet. Set mCompositionState to
     434             :   // eCompositionState_Committing, so that when HandleText() is called (in
     435             :   // response to the "input" event), we know that we should handle the
     436             :   // committed text.
     437           0 :   mCompositionState = eCompositionState_Committing;
     438           0 :   return NS_OK;
     439             : }
     440             : 
     441             : NS_IMETHODIMP
     442           0 : nsAutoCompleteController::HandleTab()
     443             : {
     444             :   bool cancel;
     445           0 :   return HandleEnter(false, nullptr, &cancel);
     446             : }
     447             : 
     448             : NS_IMETHODIMP
     449           0 : nsAutoCompleteController::HandleKeyNavigation(uint32_t aKey, bool *_retval)
     450             : {
     451             :   // By default, don't cancel the event
     452           0 :   *_retval = false;
     453             : 
     454           0 :   if (!mInput) {
     455             :     // Stop all searches in case they are async.
     456           0 :     StopSearch();
     457             :     // Note: if now is after blur and IME end composition,
     458             :     // check mInput before calling.
     459             :     // See https://bugzilla.mozilla.org/show_bug.cgi?id=193544#c31
     460           0 :     NS_ERROR("Called before attaching to the control or after detaching from the control");
     461           0 :     return NS_OK;
     462             :   }
     463             : 
     464           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     465           0 :   nsCOMPtr<nsIAutoCompletePopup> popup;
     466           0 :   input->GetPopup(getter_AddRefs(popup));
     467           0 :   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
     468             : 
     469             :   bool disabled;
     470           0 :   input->GetDisableAutoComplete(&disabled);
     471           0 :   NS_ENSURE_TRUE(!disabled, NS_OK);
     472             : 
     473           0 :   if (aKey == nsIDOMKeyEvent::DOM_VK_UP ||
     474           0 :       aKey == nsIDOMKeyEvent::DOM_VK_DOWN ||
     475           0 :       aKey == nsIDOMKeyEvent::DOM_VK_PAGE_UP ||
     476             :       aKey == nsIDOMKeyEvent::DOM_VK_PAGE_DOWN)
     477             :   {
     478             :     // Prevent the input from handling up/down events, as it may move
     479             :     // the cursor to home/end on some systems
     480           0 :     *_retval = true;
     481             : 
     482           0 :     bool isOpen = false;
     483           0 :     input->GetPopupOpen(&isOpen);
     484           0 :     if (isOpen) {
     485             :       bool reverse = aKey == nsIDOMKeyEvent::DOM_VK_UP ||
     486           0 :                       aKey == nsIDOMKeyEvent::DOM_VK_PAGE_UP ? true : false;
     487             :       bool page = aKey == nsIDOMKeyEvent::DOM_VK_PAGE_UP ||
     488           0 :                     aKey == nsIDOMKeyEvent::DOM_VK_PAGE_DOWN ? true : false;
     489             : 
     490             :       // Fill in the value of the textbox with whatever is selected in the popup
     491             :       // if the completeSelectedIndex attribute is set.  We check this before
     492             :       // calling SelectBy of an earlier attempt to avoid crashing.
     493             :       bool completeSelection;
     494           0 :       input->GetCompleteSelectedIndex(&completeSelection);
     495             : 
     496             :       // Instruct the result view to scroll by the given amount and direction
     497           0 :       popup->SelectBy(reverse, page);
     498             : 
     499           0 :       if (completeSelection)
     500             :       {
     501             :         int32_t selectedIndex;
     502           0 :         popup->GetSelectedIndex(&selectedIndex);
     503           0 :         if (selectedIndex >= 0) {
     504             :           //  A result is selected, so fill in its value
     505           0 :           nsAutoString value;
     506           0 :           if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) {
     507             :             // If the result is the previously autofilled string, then restore
     508             :             // the search string and selection that existed when the result was
     509             :             // autofilled.  Else, fill the result and move the caret to the end.
     510             :             int32_t start;
     511           0 :             if (value.Equals(mPlaceholderCompletionString,
     512           0 :                              nsCaseInsensitiveStringComparator())) {
     513           0 :               start = mSearchString.Length();
     514           0 :               value = mPlaceholderCompletionString;
     515           0 :               SetTextValue(input, value,
     516           0 :                            nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
     517             :             } else {
     518           0 :               start = value.Length();
     519           0 :               SetTextValue(input, value,
     520           0 :                            nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETESELECTED);
     521             :             }
     522             : 
     523           0 :             input->SelectTextRange(start, value.Length());
     524             :           }
     525           0 :           mCompletedSelectionIndex = selectedIndex;
     526             :         } else {
     527             :           // Nothing is selected, so fill in the last typed value
     528           0 :           SetTextValue(input, mSearchString,
     529           0 :                        nsIAutoCompleteInput::TEXTVALUE_REASON_REVERT);
     530           0 :           input->SelectTextRange(mSearchString.Length(), mSearchString.Length());
     531           0 :           mCompletedSelectionIndex = -1;
     532             :         }
     533             :       }
     534             :     } else {
     535             : #ifdef XP_MACOSX
     536             :       // on Mac, only show the popup if the caret is at the start or end of
     537             :       // the input and there is no selection, so that the default defined key
     538             :       // shortcuts for up and down move to the beginning and end of the field
     539             :       // otherwise.
     540             :       int32_t start, end;
     541             :       if (aKey == nsIDOMKeyEvent::DOM_VK_UP) {
     542             :         input->GetSelectionStart(&start);
     543             :         input->GetSelectionEnd(&end);
     544             :         if (start > 0 || start != end)
     545             :           *_retval = false;
     546             :       }
     547             :       else if (aKey == nsIDOMKeyEvent::DOM_VK_DOWN) {
     548             :         nsAutoString text;
     549             :         input->GetTextValue(text);
     550             :         input->GetSelectionStart(&start);
     551             :         input->GetSelectionEnd(&end);
     552             :         if (start != end || end < (int32_t)text.Length())
     553             :           *_retval = false;
     554             :       }
     555             : #endif
     556           0 :       if (*_retval) {
     557             :         // Open the popup if there has been a previous search, or else kick off a new search
     558           0 :         if (!mResults.IsEmpty()) {
     559           0 :           if (mRowCount) {
     560           0 :             OpenPopup();
     561             :           }
     562             :         } else {
     563             :           // Stop all searches in case they are async.
     564           0 :           StopSearch();
     565             : 
     566           0 :           if (!mInput) {
     567             :             // StopSearch() can call PostSearchCleanup() which might result
     568             :             // in a blur event, which could null out mInput, so we need to check it
     569             :             // again.  See bug #395344 for more details
     570           0 :             return NS_OK;
     571             :           }
     572             : 
     573             :           // Some script may have changed the value of the text field since our
     574             :           // last keypress or after our focus handler and we don't want to search
     575             :           // for a stale string.
     576           0 :           nsAutoString value;
     577           0 :           input->GetTextValue(value);
     578           0 :           mSearchString = value;
     579             : 
     580           0 :           StartSearches();
     581             :         }
     582             :       }
     583           0 :     }
     584           0 :   } else if (   aKey == nsIDOMKeyEvent::DOM_VK_LEFT
     585           0 :              || aKey == nsIDOMKeyEvent::DOM_VK_RIGHT
     586             : #ifndef XP_MACOSX
     587           0 :              || aKey == nsIDOMKeyEvent::DOM_VK_HOME
     588             : #endif
     589             :             )
     590             :   {
     591             :     // The user hit a text-navigation key.
     592           0 :     bool isOpen = false;
     593           0 :     input->GetPopupOpen(&isOpen);
     594             : 
     595             :     // If minresultsforpopup > 1 and there's less matches than the minimum
     596             :     // required, the popup is not open, but the search suggestion is showing
     597             :     // inline, so we should proceed as if we had the popup.
     598             :     uint32_t minResultsForPopup;
     599           0 :     input->GetMinResultsForPopup(&minResultsForPopup);
     600           0 :     if (isOpen || (mRowCount > 0 && mRowCount < minResultsForPopup)) {
     601             :       // For completeSelectedIndex autocomplete fields, if the popup shouldn't
     602             :       // close when the caret is moved, don't adjust the text value or caret
     603             :       // position.
     604           0 :       if (isOpen) {
     605             :         bool noRollup;
     606           0 :         input->GetNoRollupOnCaretMove(&noRollup);
     607           0 :         if (noRollup) {
     608             :           bool completeSelection;
     609           0 :           input->GetCompleteSelectedIndex(&completeSelection);
     610           0 :           if (completeSelection) {
     611           0 :             return NS_OK;
     612             :           }
     613             :         }
     614             :       }
     615             : 
     616             :       int32_t selectedIndex;
     617           0 :       popup->GetSelectedIndex(&selectedIndex);
     618             :       bool shouldComplete;
     619           0 :       input->GetCompleteDefaultIndex(&shouldComplete);
     620           0 :       if (selectedIndex >= 0) {
     621             :         // The pop-up is open and has a selection, take its value
     622           0 :         nsAutoString value;
     623           0 :         if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) {
     624           0 :           SetTextValue(input, value,
     625           0 :                        nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETESELECTED);
     626           0 :           input->SelectTextRange(value.Length(), value.Length());
     627             :         }
     628             :       }
     629           0 :       else if (shouldComplete) {
     630             :         // We usually try to preserve the casing of what user has typed, but
     631             :         // if he wants to autocomplete, we will replace the value with the
     632             :         // actual autocomplete result. Note that the autocomplete input can also
     633             :         // be showing e.g. "bar >> foo bar" if the search matched "bar", a
     634             :         // word not at the start of the full value "foo bar".
     635             :         // The user wants explicitely to use that result, so this ensures
     636             :         // association of the result with the autocompleted text.
     637           0 :         nsAutoString value;
     638           0 :         nsAutoString inputValue;
     639           0 :         input->GetTextValue(inputValue);
     640           0 :         if (NS_SUCCEEDED(GetDefaultCompleteValue(-1, false, value))) {
     641           0 :           nsAutoString suggestedValue;
     642           0 :           int32_t pos = inputValue.Find(" >> ");
     643           0 :           if (pos > 0) {
     644           0 :             inputValue.Right(suggestedValue, inputValue.Length() - pos - 4);
     645             :           } else {
     646           0 :             suggestedValue = inputValue;
     647             :           }
     648             : 
     649           0 :           if (value.Equals(suggestedValue, nsCaseInsensitiveStringComparator())) {
     650           0 :             SetTextValue(input, value,
     651           0 :                          nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
     652           0 :             input->SelectTextRange(value.Length(), value.Length());
     653             :           }
     654             :         }
     655             :       }
     656             : 
     657             :       // Close the pop-up even if nothing was selected
     658           0 :       ClearSearchTimer();
     659           0 :       ClosePopup();
     660             :     }
     661             :     // Update last-searched string to the current input, since the input may
     662             :     // have changed.  Without this, subsequent backspaces look like text
     663             :     // additions, not text deletions.
     664           0 :     nsAutoString value;
     665           0 :     input->GetTextValue(value);
     666           0 :     mSearchString = value;
     667             :   }
     668             : 
     669           0 :   return NS_OK;
     670             : }
     671             : 
     672             : NS_IMETHODIMP
     673           0 : nsAutoCompleteController::HandleDelete(bool *_retval)
     674             : {
     675           0 :   *_retval = false;
     676           0 :   if (!mInput)
     677           0 :     return NS_OK;
     678             : 
     679           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
     680           0 :   bool isOpen = false;
     681           0 :   input->GetPopupOpen(&isOpen);
     682           0 :   if (!isOpen || mRowCount == 0) {
     683             :     // Nothing left to delete, proceed as normal
     684           0 :     bool unused = false;
     685           0 :     HandleText(&unused);
     686           0 :     return NS_OK;
     687             :   }
     688             : 
     689           0 :   nsCOMPtr<nsIAutoCompletePopup> popup;
     690           0 :   input->GetPopup(getter_AddRefs(popup));
     691             : 
     692             :   int32_t index, searchIndex, rowIndex;
     693           0 :   popup->GetSelectedIndex(&index);
     694           0 :   if (index == -1) {
     695             :     // No row is selected in the list
     696           0 :     bool unused = false;
     697           0 :     HandleText(&unused);
     698           0 :     return NS_OK;
     699             :   }
     700             : 
     701           0 :   RowIndexToSearch(index, &searchIndex, &rowIndex);
     702           0 :   NS_ENSURE_TRUE(searchIndex >= 0 && rowIndex >= 0, NS_ERROR_FAILURE);
     703             : 
     704           0 :   nsIAutoCompleteResult *result = mResults.SafeObjectAt(searchIndex);
     705           0 :   NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
     706             : 
     707           0 :   nsAutoString search;
     708           0 :   input->GetSearchParam(search);
     709             : 
     710             :   // Clear the row in our result and in the DB.
     711           0 :   result->RemoveValueAt(rowIndex, true);
     712           0 :   --mRowCount;
     713             : 
     714             :   // We removed it, so make sure we cancel the event that triggered this call.
     715           0 :   *_retval = true;
     716             : 
     717             :   // Unselect the current item.
     718           0 :   popup->SetSelectedIndex(-1);
     719             : 
     720             :   // Tell the tree that the row count changed.
     721           0 :   if (mTree)
     722           0 :     mTree->RowCountChanged(mRowCount, -1);
     723             : 
     724             :   // Adjust index, if needed.
     725           0 :   MOZ_ASSERT(index >= 0); // We verified this above, after RowIndexToSearch.
     726           0 :   if (static_cast<uint32_t>(index) >= mRowCount)
     727           0 :     index = mRowCount - 1;
     728             : 
     729           0 :   if (mRowCount > 0) {
     730             :     // There are still rows in the popup, select the current index again.
     731           0 :     popup->SetSelectedIndex(index);
     732             : 
     733             :     // Complete to the new current value.
     734           0 :     bool shouldComplete = false;
     735           0 :     input->GetCompleteDefaultIndex(&shouldComplete);
     736           0 :     if (shouldComplete) {
     737           0 :       nsAutoString value;
     738           0 :       if (NS_SUCCEEDED(GetResultValueAt(index, false, value))) {
     739           0 :         CompleteValue(value);
     740             :       }
     741             :     }
     742             : 
     743             :     // Invalidate the popup.
     744           0 :     popup->Invalidate(nsIAutoCompletePopup::INVALIDATE_REASON_DELETE);
     745             :   } else {
     746             :     // Nothing left in the popup, clear any pending search timers and
     747             :     // close the popup.
     748           0 :     ClearSearchTimer();
     749             :     uint32_t minResults;
     750           0 :     input->GetMinResultsForPopup(&minResults);
     751           0 :     if (minResults) {
     752           0 :       ClosePopup();
     753             :     }
     754             :   }
     755             : 
     756           0 :   return NS_OK;
     757             : }
     758             : 
     759             : nsresult
     760           0 : nsAutoCompleteController::GetResultAt(int32_t aIndex, nsIAutoCompleteResult** aResult,
     761             :                                       int32_t* aRowIndex)
     762             : {
     763             :   int32_t searchIndex;
     764           0 :   RowIndexToSearch(aIndex, &searchIndex, aRowIndex);
     765           0 :   NS_ENSURE_TRUE(searchIndex >= 0 && *aRowIndex >= 0, NS_ERROR_FAILURE);
     766             : 
     767           0 :   *aResult = mResults.SafeObjectAt(searchIndex);
     768           0 :   NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE);
     769           0 :   return NS_OK;
     770             : }
     771             : 
     772             : NS_IMETHODIMP
     773           0 : nsAutoCompleteController::GetValueAt(int32_t aIndex, nsAString & _retval)
     774             : {
     775           0 :   GetResultLabelAt(aIndex, _retval);
     776             : 
     777           0 :   return NS_OK;
     778             : }
     779             : 
     780             : NS_IMETHODIMP
     781           0 : nsAutoCompleteController::GetLabelAt(int32_t aIndex, nsAString & _retval)
     782             : {
     783           0 :   GetResultLabelAt(aIndex, _retval);
     784             : 
     785           0 :   return NS_OK;
     786             : }
     787             : 
     788             : NS_IMETHODIMP
     789           0 : nsAutoCompleteController::GetCommentAt(int32_t aIndex, nsAString & _retval)
     790             : {
     791             :   int32_t rowIndex;
     792             :   nsIAutoCompleteResult* result;
     793           0 :   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
     794           0 :   NS_ENSURE_SUCCESS(rv, rv);
     795             : 
     796           0 :   return result->GetCommentAt(rowIndex, _retval);
     797             : }
     798             : 
     799             : NS_IMETHODIMP
     800           0 : nsAutoCompleteController::GetStyleAt(int32_t aIndex, nsAString & _retval)
     801             : {
     802             :   int32_t rowIndex;
     803             :   nsIAutoCompleteResult* result;
     804           0 :   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
     805           0 :   NS_ENSURE_SUCCESS(rv, rv);
     806             : 
     807           0 :   return result->GetStyleAt(rowIndex, _retval);
     808             : }
     809             : 
     810             : NS_IMETHODIMP
     811           0 : nsAutoCompleteController::GetImageAt(int32_t aIndex, nsAString & _retval)
     812             : {
     813             :   int32_t rowIndex;
     814             :   nsIAutoCompleteResult* result;
     815           0 :   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
     816           0 :   NS_ENSURE_SUCCESS(rv, rv);
     817             : 
     818           0 :   return result->GetImageAt(rowIndex, _retval);
     819             : }
     820             : 
     821             : NS_IMETHODIMP
     822           0 : nsAutoCompleteController::GetFinalCompleteValueAt(int32_t aIndex,
     823             :                                                   nsAString & _retval)
     824             : {
     825             :   int32_t rowIndex;
     826             :   nsIAutoCompleteResult* result;
     827           0 :   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
     828           0 :   NS_ENSURE_SUCCESS(rv, rv);
     829             : 
     830           0 :   return result->GetFinalCompleteValueAt(rowIndex, _retval);
     831             : }
     832             : 
     833             : NS_IMETHODIMP
     834           0 : nsAutoCompleteController::SetSearchString(const nsAString &aSearchString)
     835             : {
     836           0 :   mSearchString = aSearchString;
     837           0 :   return NS_OK;
     838             : }
     839             : 
     840             : NS_IMETHODIMP
     841           0 : nsAutoCompleteController::GetSearchString(nsAString &aSearchString)
     842             : {
     843           0 :   aSearchString = mSearchString;
     844           0 :   return NS_OK;
     845             : }
     846             : 
     847             : void
     848           0 : nsAutoCompleteController::HandleSearchResult(nsIAutoCompleteSearch *aSearch,
     849             :                                              nsIAutoCompleteResult *aResult)
     850             : {
     851             :   // Look up the index of the search which is returning.
     852           0 :   for (uint32_t i = 0; i < mSearches.Length(); ++i) {
     853           0 :     if (mSearches[i] == aSearch) {
     854           0 :       ProcessResult(i, aResult);
     855             :     }
     856             :   }
     857           0 : }
     858             : 
     859             : 
     860             : ////////////////////////////////////////////////////////////////////////
     861             : //// nsIAutoCompleteObserver
     862             : 
     863             : NS_IMETHODIMP
     864           0 : nsAutoCompleteController::OnUpdateSearchResult(nsIAutoCompleteSearch *aSearch, nsIAutoCompleteResult* aResult)
     865             : {
     866           0 :   MOZ_ASSERT(mSearches.Contains(aSearch));
     867             : 
     868           0 :   ClearResults();
     869           0 :   HandleSearchResult(aSearch, aResult);
     870           0 :   return NS_OK;
     871             : }
     872             : 
     873             : NS_IMETHODIMP
     874           0 : nsAutoCompleteController::OnSearchResult(nsIAutoCompleteSearch *aSearch, nsIAutoCompleteResult* aResult)
     875             : {
     876           0 :   MOZ_ASSERT(mSearchesOngoing > 0 && mSearches.Contains(aSearch));
     877             : 
     878             :   // If this is the first search result we are processing
     879             :   // we should clear out the previously cached results.
     880           0 :   if (mFirstSearchResult) {
     881           0 :     ClearResults();
     882           0 :     mFirstSearchResult = false;
     883             :   }
     884             : 
     885           0 :   uint16_t result = 0;
     886           0 :   if (aResult) {
     887           0 :     aResult->GetSearchResult(&result);
     888             :   }
     889             : 
     890             :   // If our results are incremental, the search is still ongoing.
     891           0 :   if (result != nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING &&
     892           0 :       result != nsIAutoCompleteResult::RESULT_NOMATCH_ONGOING) {
     893           0 :     --mSearchesOngoing;
     894             :   }
     895             : 
     896           0 :   HandleSearchResult(aSearch, aResult);
     897             : 
     898           0 :   if (mSearchesOngoing == 0) {
     899             :     // If this is the last search to return, cleanup.
     900           0 :     PostSearchCleanup();
     901             :   }
     902             : 
     903           0 :   return NS_OK;
     904             : }
     905             : 
     906             : ////////////////////////////////////////////////////////////////////////
     907             : //// nsITimerCallback
     908             : 
     909             : NS_IMETHODIMP
     910           0 : nsAutoCompleteController::Notify(nsITimer *timer)
     911             : {
     912           0 :   mTimer = nullptr;
     913             : 
     914           0 :   if (mImmediateSearchesCount == 0) {
     915             :     // If there were no immediate searches, BeforeSearches has not yet been
     916             :     // called, so do it now.
     917           0 :     nsresult rv = BeforeSearches();
     918           0 :     if (NS_FAILED(rv))
     919           0 :       return rv;
     920             :   }
     921           0 :   StartSearch(nsIAutoCompleteSearchDescriptor::SEARCH_TYPE_DELAYED);
     922           0 :   AfterSearches();
     923           0 :   return NS_OK;
     924             : }
     925             : 
     926             : ////////////////////////////////////////////////////////////////////////
     927             : // nsITreeView
     928             : 
     929             : NS_IMETHODIMP
     930           0 : nsAutoCompleteController::GetRowCount(int32_t *aRowCount)
     931             : {
     932           0 :   *aRowCount = mRowCount;
     933           0 :   return NS_OK;
     934             : }
     935             : 
     936             : NS_IMETHODIMP
     937           0 : nsAutoCompleteController::GetRowProperties(int32_t index, nsAString& aProps)
     938             : {
     939           0 :   return NS_OK;
     940             : }
     941             : 
     942             : NS_IMETHODIMP
     943           0 : nsAutoCompleteController::GetCellProperties(int32_t row, nsITreeColumn* col,
     944             :                                             nsAString& aProps)
     945             : {
     946           0 :   if (row >= 0) {
     947           0 :     GetStyleAt(row, aProps);
     948             :   }
     949             : 
     950           0 :   return NS_OK;
     951             : }
     952             : 
     953             : NS_IMETHODIMP
     954           0 : nsAutoCompleteController::GetColumnProperties(nsITreeColumn* col, nsAString& aProps)
     955             : {
     956           0 :   return NS_OK;
     957             : }
     958             : 
     959             : NS_IMETHODIMP
     960           0 : nsAutoCompleteController::GetImageSrc(int32_t row, nsITreeColumn* col, nsAString& _retval)
     961             : {
     962             :   const char16_t* colID;
     963           0 :   col->GetIdConst(&colID);
     964             : 
     965           0 :   if (NS_LITERAL_STRING("treecolAutoCompleteValue").Equals(colID))
     966           0 :     return GetImageAt(row, _retval);
     967             : 
     968           0 :   return NS_OK;
     969             : }
     970             : 
     971             : NS_IMETHODIMP
     972           0 : nsAutoCompleteController::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval)
     973             : {
     974           0 :   NS_NOTREACHED("tree has no progress cells");
     975           0 :   return NS_OK;
     976             : }
     977             : 
     978             : NS_IMETHODIMP
     979           0 : nsAutoCompleteController::GetCellValue(int32_t row, nsITreeColumn* col, nsAString& _retval)
     980             : {
     981           0 :   NS_NOTREACHED("all of our cells are text");
     982           0 :   return NS_OK;
     983             : }
     984             : 
     985             : NS_IMETHODIMP
     986           0 : nsAutoCompleteController::GetCellText(int32_t row, nsITreeColumn* col, nsAString& _retval)
     987             : {
     988             :   const char16_t* colID;
     989           0 :   col->GetIdConst(&colID);
     990             : 
     991           0 :   if (NS_LITERAL_STRING("treecolAutoCompleteValue").Equals(colID))
     992           0 :     GetValueAt(row, _retval);
     993           0 :   else if (NS_LITERAL_STRING("treecolAutoCompleteComment").Equals(colID))
     994           0 :     GetCommentAt(row, _retval);
     995             : 
     996           0 :   return NS_OK;
     997             : }
     998             : 
     999             : NS_IMETHODIMP
    1000           0 : nsAutoCompleteController::IsContainer(int32_t index, bool *_retval)
    1001             : {
    1002           0 :   *_retval = false;
    1003           0 :   return NS_OK;
    1004             : }
    1005             : 
    1006             : NS_IMETHODIMP
    1007           0 : nsAutoCompleteController::IsContainerOpen(int32_t index, bool *_retval)
    1008             : {
    1009           0 :   NS_NOTREACHED("no container cells");
    1010           0 :   return NS_OK;
    1011             : }
    1012             : 
    1013             : NS_IMETHODIMP
    1014           0 : nsAutoCompleteController::IsContainerEmpty(int32_t index, bool *_retval)
    1015             : {
    1016           0 :   NS_NOTREACHED("no container cells");
    1017           0 :   return NS_OK;
    1018             : }
    1019             : 
    1020             : NS_IMETHODIMP
    1021           0 : nsAutoCompleteController::GetLevel(int32_t index, int32_t *_retval)
    1022             : {
    1023           0 :   *_retval = 0;
    1024           0 :   return NS_OK;
    1025             : }
    1026             : 
    1027             : NS_IMETHODIMP
    1028           0 : nsAutoCompleteController::GetParentIndex(int32_t rowIndex, int32_t *_retval)
    1029             : {
    1030           0 :   *_retval = -1;
    1031           0 :   return NS_OK;
    1032             : }
    1033             : 
    1034             : NS_IMETHODIMP
    1035           0 : nsAutoCompleteController::HasNextSibling(int32_t rowIndex, int32_t afterIndex, bool *_retval)
    1036             : {
    1037           0 :   *_retval = false;
    1038           0 :   return NS_OK;
    1039             : }
    1040             : 
    1041             : NS_IMETHODIMP
    1042           0 : nsAutoCompleteController::ToggleOpenState(int32_t index)
    1043             : {
    1044           0 :   return NS_OK;
    1045             : }
    1046             : 
    1047             : NS_IMETHODIMP
    1048           0 : nsAutoCompleteController::SetTree(nsITreeBoxObject *tree)
    1049             : {
    1050           0 :   mTree = tree;
    1051           0 :   return NS_OK;
    1052             : }
    1053             : 
    1054             : NS_IMETHODIMP
    1055           0 : nsAutoCompleteController::GetSelection(nsITreeSelection * *aSelection)
    1056             : {
    1057           0 :   *aSelection = mSelection;
    1058           0 :   NS_IF_ADDREF(*aSelection);
    1059           0 :   return NS_OK;
    1060             : }
    1061             : 
    1062           0 : NS_IMETHODIMP nsAutoCompleteController::SetSelection(nsITreeSelection * aSelection)
    1063             : {
    1064           0 :   mSelection = aSelection;
    1065           0 :   return NS_OK;
    1066             : }
    1067             : 
    1068             : NS_IMETHODIMP
    1069           0 : nsAutoCompleteController::SelectionChanged()
    1070             : {
    1071           0 :   return NS_OK;
    1072             : }
    1073             : 
    1074             : NS_IMETHODIMP
    1075           0 : nsAutoCompleteController::SetCellValue(int32_t row, nsITreeColumn* col, const nsAString& value)
    1076             : {
    1077           0 :   return NS_OK;
    1078             : }
    1079             : 
    1080             : NS_IMETHODIMP
    1081           0 : nsAutoCompleteController::SetCellText(int32_t row, nsITreeColumn* col, const nsAString& value)
    1082             : {
    1083           0 :   return NS_OK;
    1084             : }
    1085             : 
    1086             : NS_IMETHODIMP
    1087           0 : nsAutoCompleteController::CycleHeader(nsITreeColumn* col)
    1088             : {
    1089           0 :   return NS_OK;
    1090             : }
    1091             : 
    1092             : NS_IMETHODIMP
    1093           0 : nsAutoCompleteController::CycleCell(int32_t row, nsITreeColumn* col)
    1094             : {
    1095           0 :   return NS_OK;
    1096             : }
    1097             : 
    1098             : NS_IMETHODIMP
    1099           0 : nsAutoCompleteController::IsEditable(int32_t row, nsITreeColumn* col, bool *_retval)
    1100             : {
    1101           0 :   *_retval = false;
    1102           0 :   return NS_OK;
    1103             : }
    1104             : 
    1105             : NS_IMETHODIMP
    1106           0 : nsAutoCompleteController::IsSelectable(int32_t row, nsITreeColumn* col, bool *_retval)
    1107             : {
    1108           0 :   *_retval = false;
    1109           0 :   return NS_OK;
    1110             : }
    1111             : 
    1112             : NS_IMETHODIMP
    1113           0 : nsAutoCompleteController::IsSeparator(int32_t index, bool *_retval)
    1114             : {
    1115           0 :   *_retval = false;
    1116           0 :   return NS_OK;
    1117             : }
    1118             : 
    1119             : NS_IMETHODIMP
    1120           0 : nsAutoCompleteController::IsSorted(bool *_retval)
    1121             : {
    1122           0 :   *_retval = false;
    1123           0 :   return NS_OK;
    1124             : }
    1125             : 
    1126             : NS_IMETHODIMP
    1127           0 : nsAutoCompleteController::CanDrop(int32_t index, int32_t orientation,
    1128             :                                   nsIDOMDataTransfer* dataTransfer, bool *_retval)
    1129             : {
    1130           0 :   return NS_OK;
    1131             : }
    1132             : 
    1133             : NS_IMETHODIMP
    1134           0 : nsAutoCompleteController::Drop(int32_t row, int32_t orientation, nsIDOMDataTransfer* dataTransfer)
    1135             : {
    1136           0 :   return NS_OK;
    1137             : }
    1138             : 
    1139             : NS_IMETHODIMP
    1140           0 : nsAutoCompleteController::PerformAction(const char16_t *action)
    1141             : {
    1142           0 :   return NS_OK;
    1143             : }
    1144             : 
    1145             : NS_IMETHODIMP
    1146           0 : nsAutoCompleteController::PerformActionOnRow(const char16_t *action, int32_t row)
    1147             : {
    1148           0 :   return NS_OK;
    1149             : }
    1150             : 
    1151             : NS_IMETHODIMP
    1152           0 : nsAutoCompleteController::PerformActionOnCell(const char16_t* action, int32_t row, nsITreeColumn* col)
    1153             : {
    1154           0 :   return NS_OK;
    1155             : }
    1156             : 
    1157             : ////////////////////////////////////////////////////////////////////////
    1158             : //// nsAutoCompleteController
    1159             : 
    1160             : nsresult
    1161           0 : nsAutoCompleteController::OpenPopup()
    1162             : {
    1163             :   uint32_t minResults;
    1164           0 :   mInput->GetMinResultsForPopup(&minResults);
    1165             : 
    1166           0 :   if (mRowCount >= minResults) {
    1167           0 :     return mInput->SetPopupOpen(true);
    1168             :   }
    1169             : 
    1170           0 :   return NS_OK;
    1171             : }
    1172             : 
    1173             : nsresult
    1174           0 : nsAutoCompleteController::ClosePopup()
    1175             : {
    1176           0 :   if (!mInput) {
    1177           0 :     return NS_OK;
    1178             :   }
    1179             : 
    1180           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1181             : 
    1182           0 :   bool isOpen = false;
    1183           0 :   input->GetPopupOpen(&isOpen);
    1184           0 :   if (!isOpen)
    1185           0 :     return NS_OK;
    1186             : 
    1187           0 :   nsCOMPtr<nsIAutoCompletePopup> popup;
    1188           0 :   input->GetPopup(getter_AddRefs(popup));
    1189           0 :   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
    1190           0 :   popup->SetSelectedIndex(-1);
    1191           0 :   return input->SetPopupOpen(false);
    1192             : }
    1193             : 
    1194             : nsresult
    1195           0 : nsAutoCompleteController::BeforeSearches()
    1196             : {
    1197           0 :   NS_ENSURE_STATE(mInput);
    1198             : 
    1199           0 :   mSearchStatus = nsIAutoCompleteController::STATUS_SEARCHING;
    1200           0 :   mDefaultIndexCompleted = false;
    1201             : 
    1202             :   // The first search result will clear mResults array, though we should pass
    1203             :   // the previous result to each search to allow them to reuse it.  So we
    1204             :   // temporarily cache current results till AfterSearches().
    1205           0 :   if (!mResultCache.AppendObjects(mResults)) {
    1206           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1207             :   }
    1208             : 
    1209           0 :   mSearchesOngoing = mSearches.Length();
    1210           0 :   mSearchesFailed = 0;
    1211           0 :   mFirstSearchResult = true;
    1212             : 
    1213             :   // notify the input that the search is beginning
    1214           0 :   mInput->OnSearchBegin();
    1215             : 
    1216           0 :   return NS_OK;
    1217             : }
    1218             : 
    1219             : nsresult
    1220           0 : nsAutoCompleteController::StartSearch(uint16_t aSearchType)
    1221             : {
    1222           0 :   NS_ENSURE_STATE(mInput);
    1223           0 :   nsCOMPtr<nsIAutoCompleteInput> input = mInput;
    1224             : 
    1225             :   // Iterate a copy of |mSearches| so that we don't run into trouble if the
    1226             :   // array is mutated while we're still in the loop. An nsIAutoCompleteSearch
    1227             :   // implementation could synchronously start a new search when StartSearch()
    1228             :   // is called and that would lead to assertions down the way.
    1229           0 :   nsCOMArray<nsIAutoCompleteSearch> searchesCopy(mSearches);
    1230           0 :   for (uint32_t i = 0; i < searchesCopy.Length(); ++i) {
    1231           0 :     nsCOMPtr<nsIAutoCompleteSearch> search = searchesCopy[i];
    1232             : 
    1233             :     // Filter on search type.  Not all the searches implement this interface,
    1234             :     // in such a case just consider them delayed.
    1235           0 :     uint16_t searchType = nsIAutoCompleteSearchDescriptor::SEARCH_TYPE_DELAYED;
    1236             :     nsCOMPtr<nsIAutoCompleteSearchDescriptor> searchDesc =
    1237           0 :       do_QueryInterface(search);
    1238           0 :     if (searchDesc)
    1239           0 :       searchDesc->GetSearchType(&searchType);
    1240           0 :     if (searchType != aSearchType)
    1241           0 :       continue;
    1242             : 
    1243           0 :     nsIAutoCompleteResult *result = mResultCache.SafeObjectAt(i);
    1244             : 
    1245           0 :     if (result) {
    1246             :       uint16_t searchResult;
    1247           0 :       result->GetSearchResult(&searchResult);
    1248           0 :       if (searchResult != nsIAutoCompleteResult::RESULT_SUCCESS &&
    1249           0 :           searchResult != nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING &&
    1250           0 :           searchResult != nsIAutoCompleteResult::RESULT_NOMATCH)
    1251           0 :         result = nullptr;
    1252             :     }
    1253             : 
    1254           0 :     nsAutoString searchParam;
    1255           0 :     nsresult rv = input->GetSearchParam(searchParam);
    1256           0 :     if (NS_FAILED(rv))
    1257           0 :       return rv;
    1258             : 
    1259             :     // FormFill expects the searchParam to only contain the input element id,
    1260             :     // other consumers may have other expectations, so this modifies it only
    1261             :     // for new consumers handling autoFill by themselves.
    1262           0 :     if (mProhibitAutoFill && mClearingAutoFillSearchesAgain) {
    1263           0 :       searchParam.AppendLiteral(" prohibit-autofill");
    1264             :     }
    1265             : 
    1266             :     uint32_t userContextId;
    1267           0 :     rv = input->GetUserContextId(&userContextId);
    1268           0 :     if (NS_SUCCEEDED(rv) &&
    1269           0 :         userContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
    1270           0 :       searchParam.AppendLiteral(" user-context-id:");
    1271           0 :       searchParam.AppendInt(userContextId, 10);
    1272             :     }
    1273             : 
    1274           0 :     rv = search->StartSearch(mSearchString, searchParam, result, static_cast<nsIAutoCompleteObserver *>(this));
    1275           0 :     if (NS_FAILED(rv)) {
    1276           0 :       ++mSearchesFailed;
    1277           0 :       MOZ_ASSERT(mSearchesOngoing > 0);
    1278           0 :       --mSearchesOngoing;
    1279             :     }
    1280             :     // Because of the joy of nested event loops (which can easily happen when some
    1281             :     // code uses a generator for an asynchronous AutoComplete search),
    1282             :     // nsIAutoCompleteSearch::StartSearch might cause us to be detached from our input
    1283             :     // field.  The next time we iterate, we'd be touching something that we shouldn't
    1284             :     // be, and result in a crash.
    1285           0 :     if (!mInput) {
    1286             :       // The search operation has been finished.
    1287           0 :       return NS_OK;
    1288             :     }
    1289             :   }
    1290             : 
    1291           0 :   return NS_OK;
    1292             : }
    1293             : 
    1294             : void
    1295           0 : nsAutoCompleteController::AfterSearches()
    1296             : {
    1297           0 :   mResultCache.Clear();
    1298           0 :   if (mSearchesFailed == mSearches.Length())
    1299           0 :     PostSearchCleanup();
    1300           0 : }
    1301             : 
    1302             : NS_IMETHODIMP
    1303           0 : nsAutoCompleteController::StopSearch()
    1304             : {
    1305             :   // Stop the timer if there is one
    1306           0 :   ClearSearchTimer();
    1307             : 
    1308             :   // Stop any ongoing asynchronous searches
    1309           0 :   if (mSearchStatus == nsIAutoCompleteController::STATUS_SEARCHING) {
    1310           0 :     for (uint32_t i = 0; i < mSearches.Length(); ++i) {
    1311           0 :       nsCOMPtr<nsIAutoCompleteSearch> search = mSearches[i];
    1312           0 :       search->StopSearch();
    1313             :     }
    1314           0 :     mSearchesOngoing = 0;
    1315             :     // since we were searching, but now we've stopped,
    1316             :     // we need to call PostSearchCleanup()
    1317           0 :     PostSearchCleanup();
    1318             :   }
    1319           0 :   return NS_OK;
    1320             : }
    1321             : 
    1322             : void
    1323           0 : nsAutoCompleteController::MaybeCompletePlaceholder()
    1324             : {
    1325           0 :   MOZ_ASSERT(mInput);
    1326             : 
    1327           0 :   if (!mInput) { // or mInput depending on what you choose
    1328           0 :     MOZ_ASSERT_UNREACHABLE("Input should always be valid at this point");
    1329             :     return;
    1330             :   }
    1331             : 
    1332             :   int32_t selectionStart;
    1333           0 :   mInput->GetSelectionStart(&selectionStart);
    1334             :   int32_t selectionEnd;
    1335           0 :   mInput->GetSelectionEnd(&selectionEnd);
    1336             : 
    1337             :   // Check if the current input should be completed with the placeholder string
    1338             :   // from the last completion until the actual search results come back.
    1339             :   // The new input string needs to be compatible with the last completed string.
    1340             :   // E.g. if the new value is "fob", but the last completion was "foobar",
    1341             :   // then the last completion is incompatible.
    1342             :   // If the search string is the same as the last completion value, then don't
    1343             :   // complete the value again (this prevents completion to happen e.g. if the
    1344             :   // cursor is moved and StartSeaches() is invoked).
    1345             :   // In addition, the selection must be at the end of the current input to
    1346             :   // trigger the placeholder completion.
    1347             :   bool usePlaceholderCompletion =
    1348           0 :     !mUserClearedAutoFill &&
    1349           0 :     !mPlaceholderCompletionString.IsEmpty() &&
    1350           0 :     mPlaceholderCompletionString.Length() > mSearchString.Length() &&
    1351           0 :     selectionEnd == selectionStart &&
    1352           0 :     selectionEnd == (int32_t)mSearchString.Length() &&
    1353           0 :     StringBeginsWith(mPlaceholderCompletionString, mSearchString,
    1354           0 :                     nsCaseInsensitiveStringComparator());
    1355             : 
    1356           0 :   if (usePlaceholderCompletion) {
    1357           0 :     CompleteValue(mPlaceholderCompletionString);
    1358             :   } else {
    1359           0 :     mPlaceholderCompletionString.Truncate();
    1360             :   }
    1361           0 : }
    1362             : 
    1363             : nsresult
    1364           0 : nsAutoCompleteController::StartSearches()
    1365             : {
    1366             :   // Don't create a new search timer if we're already waiting for one to fire.
    1367             :   // If we don't check for this, we won't be able to cancel the original timer
    1368             :   // and may crash when it fires (bug 236659).
    1369           0 :   if (mTimer || !mInput)
    1370           0 :     return NS_OK;
    1371             : 
    1372             :   // Check if the current input should be completed with the placeholder string
    1373             :   // from the last completion until the actual search results come back.
    1374           0 :   MaybeCompletePlaceholder();
    1375             : 
    1376           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1377             : 
    1378             :   // Get the timeout for delayed searches.
    1379             :   uint32_t timeout;
    1380           0 :   input->GetTimeout(&timeout);
    1381             : 
    1382           0 :   uint32_t immediateSearchesCount = mImmediateSearchesCount;
    1383           0 :   if (timeout == 0) {
    1384             :     // All the searches should be executed immediately.
    1385           0 :     immediateSearchesCount = mSearches.Length();
    1386             :   }
    1387             : 
    1388           0 :   if (immediateSearchesCount > 0) {
    1389           0 :     nsresult rv = BeforeSearches();
    1390           0 :     if (NS_FAILED(rv))
    1391           0 :       return rv;
    1392           0 :     StartSearch(nsIAutoCompleteSearchDescriptor::SEARCH_TYPE_IMMEDIATE);
    1393             : 
    1394           0 :     if (mSearches.Length() == immediateSearchesCount) {
    1395             :       // Either all searches are immediate, or the timeout is 0.  In the
    1396             :       // latter case we still have to execute the delayed searches, otherwise
    1397             :       // this will be a no-op.
    1398           0 :       StartSearch(nsIAutoCompleteSearchDescriptor::SEARCH_TYPE_DELAYED);
    1399             : 
    1400             :       // All the searches have been started, just finish.
    1401           0 :       AfterSearches();
    1402           0 :       return NS_OK;
    1403             :     }
    1404             :   }
    1405             : 
    1406           0 :   MOZ_ASSERT(timeout > 0, "Trying to delay searches with a 0 timeout!");
    1407             : 
    1408             :   // Now start the delayed searches.
    1409             :   nsresult rv;
    1410           0 :   mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
    1411           0 :   if (NS_FAILED(rv))
    1412           0 :       return rv;
    1413           0 :   rv = mTimer->InitWithCallback(this, timeout, nsITimer::TYPE_ONE_SHOT);
    1414           0 :   if (NS_FAILED(rv))
    1415           0 :       mTimer = nullptr;
    1416             : 
    1417           0 :   return rv;
    1418             : }
    1419             : 
    1420             : nsresult
    1421           0 : nsAutoCompleteController::ClearSearchTimer()
    1422             : {
    1423           0 :   if (mTimer) {
    1424           0 :     mTimer->Cancel();
    1425           0 :     mTimer = nullptr;
    1426             :   }
    1427           0 :   return NS_OK;
    1428             : }
    1429             : 
    1430             : nsresult
    1431           0 : nsAutoCompleteController::EnterMatch(bool aIsPopupSelection,
    1432             :                                      nsIDOMEvent *aEvent)
    1433             : {
    1434           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1435           0 :   nsCOMPtr<nsIAutoCompletePopup> popup;
    1436           0 :   input->GetPopup(getter_AddRefs(popup));
    1437           0 :   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
    1438             : 
    1439             :   bool forceComplete;
    1440           0 :   input->GetForceComplete(&forceComplete);
    1441             : 
    1442             :   // Ask the popup if it wants to enter a special value into the textbox
    1443           0 :   nsAutoString value;
    1444           0 :   popup->GetOverrideValue(value);
    1445           0 :   if (value.IsEmpty()) {
    1446             :     bool shouldComplete;
    1447           0 :     input->GetCompleteDefaultIndex(&shouldComplete);
    1448             :     bool completeSelection;
    1449           0 :     input->GetCompleteSelectedIndex(&completeSelection);
    1450             : 
    1451             :     int32_t selectedIndex;
    1452           0 :     popup->GetSelectedIndex(&selectedIndex);
    1453           0 :     if (selectedIndex >= 0) {
    1454           0 :       nsAutoString inputValue;
    1455           0 :       input->GetTextValue(inputValue);
    1456           0 :       if (aIsPopupSelection || !completeSelection) {
    1457             :         // We need to fill-in the value if:
    1458             :         //  * completeselectedindex is false
    1459             :         //  * A row in the popup was confirmed
    1460             :         //
    1461             :         // TODO: This is not totally correct, cause it will also confirm
    1462             :         // a result selected with a simple mouseover, that could also have
    1463             :         // happened accidentally, maybe touching a touchpad.
    1464             :         // The reason is that autocomplete.xml sets selectedIndex on mousemove
    1465             :         // making impossible, in the !completeSelection case, to distinguish if
    1466             :         // the user wanted to confirm autoFill or the popup entry.
    1467             :         // The solution may be to change autocomplete.xml to set selectedIndex
    1468             :         // only on popupClick, but that requires changing the selection behavior.
    1469           0 :         GetResultValueAt(selectedIndex, true, value);
    1470           0 :       } else if (mDefaultIndexCompleted &&
    1471           0 :                  inputValue.Equals(mPlaceholderCompletionString,
    1472           0 :                                    nsCaseInsensitiveStringComparator())) {
    1473             :         // We also need to fill-in the value if the default index completion was
    1474             :         // confirmed, though we cannot use the selectedIndex cause the selection
    1475             :         // may have been changed by the mouse in the meanwhile.
    1476           0 :         GetFinalDefaultCompleteValue(value);
    1477           0 :       } else if (mCompletedSelectionIndex != -1) {
    1478             :         // If completeselectedindex is true, and EnterMatch was not invoked by
    1479             :         // mouse-clicking a match (for example the user pressed Enter),
    1480             :         // don't fill in the value as it will have already been filled in as
    1481             :         // needed, unless the selected match has a final complete value that
    1482             :         // differs from the user-facing value.
    1483           0 :         nsAutoString finalValue;
    1484           0 :         GetResultValueAt(mCompletedSelectionIndex, true, finalValue);
    1485           0 :         if (!inputValue.Equals(finalValue)) {
    1486           0 :           value = finalValue;
    1487             :         }
    1488             :         // Note that if the user opens the popup, mouses over entries without
    1489             :         // ever selecting one with the keyboard, and then hits enter, none of
    1490             :         // the above cases will be hit, since mouseover doesn't activate
    1491             :         // completeselectedindex and thus mCompletedSelectionIndex would be
    1492             :         // -1.
    1493             :       }
    1494           0 :     } else if (shouldComplete) {
    1495             :       // We usually try to preserve the casing of what user has typed, but
    1496             :       // if he wants to autocomplete, we will replace the value with the
    1497             :       // actual autocomplete result.
    1498             :       // The user wants explicitely to use that result, so this ensures
    1499             :       // association of the result with the autocompleted text.
    1500           0 :       nsAutoString defaultIndexValue;
    1501           0 :       if (NS_SUCCEEDED(GetFinalDefaultCompleteValue(defaultIndexValue)))
    1502           0 :         value = defaultIndexValue;
    1503             :     }
    1504             : 
    1505           0 :     if (forceComplete && value.IsEmpty() && shouldComplete) {
    1506             :       // See if inputValue is one of the autocomplete results. It can be an
    1507             :       // identical value, or if it matched the middle of a result it can be
    1508             :       // something like "bar >> foobar" (user entered bar and foobar is
    1509             :       // the result value).
    1510             :       // If the current search matches one of the autocomplete results, we
    1511             :       // should use that result, and not overwrite it with the default value.
    1512             :       // It's indeed possible EnterMatch gets called a second time (for example
    1513             :       // by the blur handler) and it should not overwrite the current match.
    1514           0 :       nsAutoString inputValue;
    1515           0 :       input->GetTextValue(inputValue);
    1516           0 :       nsAutoString suggestedValue;
    1517           0 :       int32_t pos = inputValue.Find(" >> ");
    1518           0 :       if (pos > 0) {
    1519           0 :         inputValue.Right(suggestedValue, inputValue.Length() - pos - 4);
    1520             :       } else {
    1521           0 :         suggestedValue = inputValue;
    1522             :       }
    1523             : 
    1524           0 :       for (uint32_t i = 0; i < mResults.Length(); ++i) {
    1525           0 :         nsIAutoCompleteResult *result = mResults[i];
    1526           0 :         if (result) {
    1527           0 :           uint32_t matchCount = 0;
    1528           0 :           result->GetMatchCount(&matchCount);
    1529           0 :           for (uint32_t j = 0; j < matchCount; ++j) {
    1530           0 :             nsAutoString matchValue;
    1531           0 :             result->GetValueAt(j, matchValue);
    1532           0 :             if (suggestedValue.Equals(matchValue, nsCaseInsensitiveStringComparator())) {
    1533           0 :               nsAutoString finalMatchValue;
    1534           0 :               result->GetFinalCompleteValueAt(j, finalMatchValue);
    1535           0 :               value = finalMatchValue;
    1536           0 :               break;
    1537             :             }
    1538             :           }
    1539             :         }
    1540             :       }
    1541             :       // The value should have been set at this point. If not, then it's not
    1542             :       // a value that should be autocompleted.
    1543             :     }
    1544           0 :     else if (forceComplete && value.IsEmpty() && completeSelection) {
    1545             :       // Since nothing was selected, and forceComplete is specified, that means
    1546             :       // we have to find the first default match and enter it instead.
    1547           0 :       for (uint32_t i = 0; i < mResults.Length(); ++i) {
    1548           0 :         nsIAutoCompleteResult *result = mResults[i];
    1549           0 :         if (result) {
    1550             :           int32_t defaultIndex;
    1551           0 :           result->GetDefaultIndex(&defaultIndex);
    1552           0 :           if (defaultIndex >= 0) {
    1553           0 :             result->GetFinalCompleteValueAt(defaultIndex, value);
    1554           0 :             break;
    1555             :           }
    1556             :         }
    1557             :       }
    1558             :     }
    1559             :   }
    1560             : 
    1561           0 :   nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
    1562           0 :   NS_ENSURE_STATE(obsSvc);
    1563           0 :   obsSvc->NotifyObservers(input, "autocomplete-will-enter-text", nullptr);
    1564             : 
    1565           0 :   if (!value.IsEmpty()) {
    1566           0 :     SetTextValue(input, value, nsIAutoCompleteInput::TEXTVALUE_REASON_ENTERMATCH);
    1567           0 :     input->SelectTextRange(value.Length(), value.Length());
    1568           0 :     mSearchString = value;
    1569             :   }
    1570             : 
    1571           0 :   obsSvc->NotifyObservers(input, "autocomplete-did-enter-text", nullptr);
    1572           0 :   ClosePopup();
    1573             : 
    1574             :   bool cancel;
    1575           0 :   input->OnTextEntered(aEvent, &cancel);
    1576             : 
    1577           0 :   return NS_OK;
    1578             : }
    1579             : 
    1580             : nsresult
    1581           0 : nsAutoCompleteController::RevertTextValue()
    1582             : {
    1583             :   // StopSearch() can call PostSearchCleanup() which might result
    1584             :   // in a blur event, which could null out mInput, so we need to check it
    1585             :   // again.  See bug #408463 for more details
    1586           0 :   if (!mInput)
    1587           0 :     return NS_OK;
    1588             : 
    1589           0 :   nsAutoString oldValue(mSearchString);
    1590           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1591             : 
    1592           0 :   bool cancel = false;
    1593           0 :   input->OnTextReverted(&cancel);
    1594             : 
    1595           0 :   if (!cancel) {
    1596           0 :     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
    1597           0 :     NS_ENSURE_STATE(obsSvc);
    1598           0 :     obsSvc->NotifyObservers(input, "autocomplete-will-revert-text", nullptr);
    1599             : 
    1600           0 :     nsAutoString inputValue;
    1601           0 :     input->GetTextValue(inputValue);
    1602             :     // Don't change the value if it is the same to prevent sending useless events.
    1603             :     // NOTE: how can |RevertTextValue| be called with inputValue != oldValue?
    1604           0 :     if (!oldValue.Equals(inputValue)) {
    1605           0 :       SetTextValue(input, oldValue, nsIAutoCompleteInput::TEXTVALUE_REASON_REVERT);
    1606             :     }
    1607             : 
    1608           0 :     obsSvc->NotifyObservers(input, "autocomplete-did-revert-text", nullptr);
    1609             :   }
    1610             : 
    1611           0 :   return NS_OK;
    1612             : }
    1613             : 
    1614             : nsresult
    1615           0 : nsAutoCompleteController::ProcessResult(int32_t aSearchIndex, nsIAutoCompleteResult *aResult)
    1616             : {
    1617           0 :   NS_ENSURE_STATE(mInput);
    1618           0 :   MOZ_ASSERT(aResult, "ProcessResult should always receive a result");
    1619           0 :   NS_ENSURE_ARG(aResult);
    1620           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1621             : 
    1622           0 :   uint16_t searchResult = 0;
    1623           0 :   aResult->GetSearchResult(&searchResult);
    1624             : 
    1625             :   // The following code supports incremental updating results in 2 ways:
    1626             :   //  * The search may reuse the same result, just by adding entries to it.
    1627             :   //  * The search may send a new result every time.  In this case we merge
    1628             :   //    the results and proceed on the same code path as before.
    1629             :   // This way both mSearches and mResults can be indexed by the search index,
    1630             :   // cause we'll always have only one result per search.
    1631           0 :   if (mResults.IndexOf(aResult) == -1) {
    1632           0 :     nsIAutoCompleteResult* oldResult = mResults.SafeObjectAt(aSearchIndex);
    1633           0 :     if (oldResult) {
    1634           0 :       MOZ_ASSERT(false, "Passing new matches to OnSearchResult with a new "
    1635             :                         "nsIAutoCompleteResult every time is deprecated, please "
    1636             :                         "update the same result until the search is done");
    1637             :       // Build a new nsIAutocompleteSimpleResult and merge results into it.
    1638             :       RefPtr<nsAutoCompleteSimpleResult> mergedResult =
    1639             :         new nsAutoCompleteSimpleResult();
    1640             :       mergedResult->AppendResult(oldResult);
    1641             :       mergedResult->AppendResult(aResult);
    1642             :       mResults.ReplaceObjectAt(mergedResult, aSearchIndex);
    1643             :     } else {
    1644             :       // This inserts and grows the array if needed.
    1645           0 :       mResults.ReplaceObjectAt(aResult, aSearchIndex);
    1646             :     }
    1647             :   }
    1648             :   // When found the result should have the same index as the search.
    1649           0 :   MOZ_ASSERT_IF(mResults.IndexOf(aResult) != -1,
    1650             :                 mResults.IndexOf(aResult) == aSearchIndex);
    1651           0 :   MOZ_ASSERT(mResults.Count() >= aSearchIndex + 1,
    1652             :              "aSearchIndex should always be valid for mResults");
    1653             : 
    1654           0 :   uint32_t oldRowCount = mRowCount;
    1655             :   // If the search failed, increase the match count to include the error
    1656             :   // description.
    1657           0 :   if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) {
    1658           0 :     nsAutoString error;
    1659           0 :     aResult->GetErrorDescription(error);
    1660           0 :     if (!error.IsEmpty()) {
    1661           0 :       ++mRowCount;
    1662           0 :       if (mTree) {
    1663           0 :         mTree->RowCountChanged(oldRowCount, 1);
    1664             :       }
    1665             :     }
    1666           0 :   } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
    1667           0 :              searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
    1668             :     // Increase the match count for all matches in this result.
    1669           0 :     uint32_t totalMatchCount = 0;
    1670           0 :     for (uint32_t i = 0; i < mResults.Length(); i++) {
    1671           0 :       nsIAutoCompleteResult* result = mResults.SafeObjectAt(i);
    1672           0 :       if (result) {
    1673           0 :         uint32_t matchCount = 0;
    1674           0 :         result->GetMatchCount(&matchCount);
    1675           0 :         totalMatchCount += matchCount;
    1676             :       }
    1677             :     }
    1678           0 :     uint32_t delta = totalMatchCount - oldRowCount;
    1679             : 
    1680           0 :     mRowCount += delta;
    1681           0 :     if (mTree) {
    1682           0 :       mTree->RowCountChanged(oldRowCount, delta);
    1683             :     }
    1684             :   }
    1685             : 
    1686             :   // Try to autocomplete the default index for this search.
    1687             :   // Do this before invalidating so the binding knows about it.
    1688           0 :   CompleteDefaultIndex(aSearchIndex);
    1689             : 
    1690             :   // Refresh the popup view to display the new search results
    1691           0 :   nsCOMPtr<nsIAutoCompletePopup> popup;
    1692           0 :   input->GetPopup(getter_AddRefs(popup));
    1693           0 :   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
    1694           0 :   popup->Invalidate(nsIAutoCompletePopup::INVALIDATE_REASON_NEW_RESULT);
    1695             : 
    1696             :   uint32_t minResults;
    1697           0 :   input->GetMinResultsForPopup(&minResults);
    1698             : 
    1699             :   // Make sure the popup is open, if necessary, since we now have at least one
    1700             :   // search result ready to display. Don't force the popup closed if we might
    1701             :   // get results in the future to avoid unnecessarily canceling searches.
    1702           0 :   if (mRowCount || !minResults) {
    1703           0 :     OpenPopup();
    1704           0 :   } else if (mSearchesOngoing == 0) {
    1705           0 :     ClosePopup();
    1706             :   }
    1707             : 
    1708           0 :   return NS_OK;
    1709             : }
    1710             : 
    1711             : nsresult
    1712           0 : nsAutoCompleteController::PostSearchCleanup()
    1713             : {
    1714           0 :   NS_ENSURE_STATE(mInput);
    1715           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1716             : 
    1717             :   uint32_t minResults;
    1718           0 :   input->GetMinResultsForPopup(&minResults);
    1719             : 
    1720           0 :   if (mRowCount || minResults == 0) {
    1721           0 :     OpenPopup();
    1722           0 :     if (mRowCount)
    1723           0 :       mSearchStatus = nsIAutoCompleteController::STATUS_COMPLETE_MATCH;
    1724             :     else
    1725           0 :       mSearchStatus = nsIAutoCompleteController::STATUS_COMPLETE_NO_MATCH;
    1726             :   } else {
    1727           0 :     mSearchStatus = nsIAutoCompleteController::STATUS_COMPLETE_NO_MATCH;
    1728           0 :     ClosePopup();
    1729             :   }
    1730             : 
    1731             :   // notify the input that the search is complete
    1732           0 :   input->OnSearchComplete();
    1733             : 
    1734           0 :   return NS_OK;
    1735             : }
    1736             : 
    1737             : nsresult
    1738           0 : nsAutoCompleteController::ClearResults()
    1739             : {
    1740           0 :   int32_t oldRowCount = mRowCount;
    1741           0 :   mRowCount = 0;
    1742           0 :   mResults.Clear();
    1743           0 :   if (oldRowCount != 0) {
    1744           0 :     if (mTree)
    1745           0 :       mTree->RowCountChanged(0, -oldRowCount);
    1746           0 :     else if (mInput) {
    1747           0 :       nsCOMPtr<nsIAutoCompletePopup> popup;
    1748           0 :       mInput->GetPopup(getter_AddRefs(popup));
    1749           0 :       NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
    1750             :       // if we had a tree, RowCountChanged() would have cleared the selection
    1751             :       // when the selected row was removed.  But since we don't have a tree,
    1752             :       // we need to clear the selection manually.
    1753           0 :       popup->SetSelectedIndex(-1);
    1754             :     }
    1755             :   }
    1756           0 :   return NS_OK;
    1757             : }
    1758             : 
    1759             : nsresult
    1760           0 : nsAutoCompleteController::CompleteDefaultIndex(int32_t aResultIndex)
    1761             : {
    1762           0 :   if (mDefaultIndexCompleted || mProhibitAutoFill || mSearchString.Length() == 0 || !mInput)
    1763           0 :     return NS_OK;
    1764             : 
    1765           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1766             : 
    1767             :   int32_t selectionStart;
    1768           0 :   input->GetSelectionStart(&selectionStart);
    1769             :   int32_t selectionEnd;
    1770           0 :   input->GetSelectionEnd(&selectionEnd);
    1771             : 
    1772             :   bool isPlaceholderSelected =
    1773           0 :       selectionEnd == (int32_t)mPlaceholderCompletionString.Length() &&
    1774           0 :       selectionStart == (int32_t)mSearchString.Length() &&
    1775           0 :       StringBeginsWith(mPlaceholderCompletionString,
    1776           0 :         mSearchString, nsCaseInsensitiveStringComparator());
    1777             : 
    1778             :   // Don't try to automatically complete to the first result if there's already
    1779             :   // a selection or the cursor isn't at the end of the input. In case the
    1780             :   // selection is from the current placeholder completion value, then still
    1781             :   // automatically complete.
    1782           0 :   if (!isPlaceholderSelected && (selectionEnd != selectionStart ||
    1783           0 :         selectionEnd != (int32_t)mSearchString.Length()))
    1784           0 :     return NS_OK;
    1785             : 
    1786             :   bool shouldComplete;
    1787           0 :   input->GetCompleteDefaultIndex(&shouldComplete);
    1788           0 :   if (!shouldComplete)
    1789           0 :     return NS_OK;
    1790             : 
    1791           0 :   nsAutoString resultValue;
    1792           0 :   if (NS_SUCCEEDED(GetDefaultCompleteValue(aResultIndex, true, resultValue))) {
    1793           0 :     CompleteValue(resultValue);
    1794             : 
    1795           0 :     mDefaultIndexCompleted = true;
    1796             :   }
    1797             : 
    1798           0 :   return NS_OK;
    1799             : }
    1800             : 
    1801             : nsresult
    1802           0 : nsAutoCompleteController::GetDefaultCompleteResult(int32_t aResultIndex,
    1803             :                                                    nsIAutoCompleteResult** _result,
    1804             :                                                    int32_t* _defaultIndex)
    1805             : {
    1806           0 :   *_defaultIndex = -1;
    1807           0 :   int32_t resultIndex = aResultIndex;
    1808             : 
    1809             :   // If a result index was not provided, find the first defaultIndex result.
    1810           0 :   for (int32_t i = 0; resultIndex < 0 && i < mResults.Count(); ++i) {
    1811           0 :     nsIAutoCompleteResult *result = mResults.SafeObjectAt(i);
    1812           0 :     if (result &&
    1813           0 :         NS_SUCCEEDED(result->GetDefaultIndex(_defaultIndex)) &&
    1814           0 :         *_defaultIndex >= 0) {
    1815           0 :       resultIndex = i;
    1816             :     }
    1817             :   }
    1818           0 :   if (resultIndex < 0) {
    1819           0 :     return NS_ERROR_FAILURE;
    1820             :   }
    1821             : 
    1822           0 :   *_result = mResults.SafeObjectAt(resultIndex);
    1823           0 :   NS_ENSURE_TRUE(*_result, NS_ERROR_FAILURE);
    1824             : 
    1825           0 :   if (*_defaultIndex < 0) {
    1826             :     // The search must explicitly provide a default index in order
    1827             :     // for us to be able to complete.
    1828           0 :     (*_result)->GetDefaultIndex(_defaultIndex);
    1829             :   }
    1830             : 
    1831           0 :   if (*_defaultIndex < 0) {
    1832             :     // We were given a result index, but that result doesn't want to
    1833             :     // be autocompleted.
    1834           0 :     return NS_ERROR_FAILURE;
    1835             :   }
    1836             : 
    1837             :   // If the result wrongly notifies a RESULT_SUCCESS with no matches, or
    1838             :   // provides a defaultIndex greater than its matchCount, avoid trying to
    1839             :   // complete to an empty value.
    1840           0 :   uint32_t matchCount = 0;
    1841           0 :   (*_result)->GetMatchCount(&matchCount);
    1842             :   // Here defaultIndex is surely non-negative, so can be cast to unsigned.
    1843           0 :   if ((uint32_t)(*_defaultIndex) >= matchCount) {
    1844           0 :     return NS_ERROR_FAILURE;
    1845             :   }
    1846             : 
    1847           0 :   return NS_OK;
    1848             : }
    1849             : 
    1850             : nsresult
    1851           0 : nsAutoCompleteController::GetDefaultCompleteValue(int32_t aResultIndex,
    1852             :                                                   bool aPreserveCasing,
    1853             :                                                   nsAString &_retval)
    1854             : {
    1855             :   nsIAutoCompleteResult *result;
    1856           0 :   int32_t defaultIndex = -1;
    1857           0 :   nsresult rv = GetDefaultCompleteResult(aResultIndex, &result, &defaultIndex);
    1858           0 :   if (NS_FAILED(rv)) return rv;
    1859             : 
    1860           0 :   nsAutoString resultValue;
    1861           0 :   result->GetValueAt(defaultIndex, resultValue);
    1862           0 :   if (aPreserveCasing &&
    1863           0 :       StringBeginsWith(resultValue, mSearchString,
    1864           0 :                        nsCaseInsensitiveStringComparator())) {
    1865             :     // We try to preserve user casing, otherwise we would end up changing
    1866             :     // the case of what he typed, if we have a result with a different casing.
    1867             :     // For example if we have result "Test", and user starts writing "tuna",
    1868             :     // after digiting t, we would convert it to T trying to autocomplete "Test".
    1869             :     // We will still complete to cased "Test" if the user explicitely choose
    1870             :     // that result, by either selecting it in the results popup, or with
    1871             :     // keyboard navigation or if autocompleting in the middle.
    1872           0 :     nsAutoString casedResultValue;
    1873           0 :     casedResultValue.Assign(mSearchString);
    1874             :     // Use what the user has typed so far.
    1875           0 :     casedResultValue.Append(Substring(resultValue,
    1876             :                                       mSearchString.Length(),
    1877           0 :                                       resultValue.Length()));
    1878           0 :     _retval = casedResultValue;
    1879             :   }
    1880             :   else
    1881           0 :     _retval = resultValue;
    1882             : 
    1883           0 :   return NS_OK;
    1884             : }
    1885             : 
    1886             : nsresult
    1887           0 : nsAutoCompleteController::GetFinalDefaultCompleteValue(nsAString &_retval)
    1888             : {
    1889           0 :   MOZ_ASSERT(mInput, "Must have a valid input");
    1890           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1891             :   nsIAutoCompleteResult *result;
    1892           0 :   int32_t defaultIndex = -1;
    1893           0 :   nsresult rv = GetDefaultCompleteResult(-1, &result, &defaultIndex);
    1894           0 :   if (NS_FAILED(rv)) return rv;
    1895             : 
    1896           0 :   result->GetValueAt(defaultIndex, _retval);
    1897           0 :   nsAutoString inputValue;
    1898           0 :   input->GetTextValue(inputValue);
    1899           0 :   if (!_retval.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
    1900           0 :     return NS_ERROR_FAILURE;
    1901             :   }
    1902             : 
    1903           0 :   nsAutoString finalCompleteValue;
    1904           0 :   rv = result->GetFinalCompleteValueAt(defaultIndex, finalCompleteValue);
    1905           0 :   if (NS_SUCCEEDED(rv)) {
    1906           0 :     _retval = finalCompleteValue;
    1907             :   }
    1908             : 
    1909           0 :   return NS_OK;
    1910             : }
    1911             : 
    1912             : nsresult
    1913           0 : nsAutoCompleteController::CompleteValue(nsString &aValue)
    1914             : /* mInput contains mSearchString, which we want to autocomplete to aValue.  If
    1915             :  * selectDifference is true, select the remaining portion of aValue not
    1916             :  * contained in mSearchString. */
    1917             : {
    1918           0 :   MOZ_ASSERT(mInput, "Must have a valid input");
    1919             : 
    1920           0 :   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
    1921           0 :   const int32_t mSearchStringLength = mSearchString.Length();
    1922           0 :   int32_t endSelect = aValue.Length();  // By default, select all of aValue.
    1923             : 
    1924           0 :   if (aValue.IsEmpty() ||
    1925           0 :       StringBeginsWith(aValue, mSearchString,
    1926           0 :                        nsCaseInsensitiveStringComparator())) {
    1927             :     // aValue is empty (we were asked to clear mInput), or mSearchString
    1928             :     // matches the beginning of aValue.  In either case we can simply
    1929             :     // autocomplete to aValue.
    1930           0 :     mPlaceholderCompletionString = aValue;
    1931           0 :     SetTextValue(input, aValue,
    1932           0 :                  nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
    1933             :   } else {
    1934             :     nsresult rv;
    1935           0 :     nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
    1936           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1937           0 :     nsAutoCString scheme;
    1938           0 :     if (NS_SUCCEEDED(ios->ExtractScheme(NS_ConvertUTF16toUTF8(aValue), scheme))) {
    1939             :       // Trying to autocomplete a URI from somewhere other than the beginning.
    1940             :       // Only succeed if the missing portion is "http://"; otherwise do not
    1941             :       // autocomplete.  This prevents us from "helpfully" autocompleting to a
    1942             :       // URI that isn't equivalent to what the user expected.
    1943           0 :       const int32_t findIndex = 7; // length of "http://"
    1944             : 
    1945           0 :       if ((endSelect < findIndex + mSearchStringLength) ||
    1946           0 :           !scheme.LowerCaseEqualsLiteral("http") ||
    1947           0 :           !Substring(aValue, findIndex, mSearchStringLength).Equals(
    1948           0 :             mSearchString, nsCaseInsensitiveStringComparator())) {
    1949           0 :         return NS_OK;
    1950             :       }
    1951             : 
    1952           0 :       mPlaceholderCompletionString = mSearchString +
    1953           0 :         Substring(aValue, mSearchStringLength + findIndex, endSelect);
    1954           0 :       SetTextValue(input, mPlaceholderCompletionString,
    1955           0 :                    nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
    1956             : 
    1957           0 :       endSelect -= findIndex; // We're skipping this many characters of aValue.
    1958             :     } else {
    1959             :       // Autocompleting something other than a URI from the middle.
    1960             :       // Use the format "searchstring >> full string" to indicate to the user
    1961             :       // what we are going to replace their search string with.
    1962           0 :       SetTextValue(input, mSearchString + NS_LITERAL_STRING(" >> ") + aValue,
    1963           0 :                    nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
    1964             : 
    1965           0 :       endSelect = mSearchString.Length() + 4 + aValue.Length();
    1966             : 
    1967             :       // Reset the last search completion.
    1968           0 :       mPlaceholderCompletionString.Truncate();
    1969             :     }
    1970             :   }
    1971             : 
    1972           0 :   input->SelectTextRange(mSearchStringLength, endSelect);
    1973             : 
    1974           0 :   return NS_OK;
    1975             : }
    1976             : 
    1977             : nsresult
    1978           0 : nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, nsAString & _retval)
    1979             : {
    1980           0 :   return GetResultValueLabelAt(aIndex, false, false, _retval);
    1981             : }
    1982             : 
    1983             : nsresult
    1984           0 : nsAutoCompleteController::GetResultValueAt(int32_t aIndex, bool aGetFinalValue,
    1985             :                                            nsAString & _retval)
    1986             : {
    1987           0 :   return GetResultValueLabelAt(aIndex, aGetFinalValue, true, _retval);
    1988             : }
    1989             : 
    1990             : nsresult
    1991           0 : nsAutoCompleteController::GetResultValueLabelAt(int32_t aIndex,
    1992             :                                                 bool aGetFinalValue,
    1993             :                                                 bool aGetValue,
    1994             :                                                 nsAString & _retval)
    1995             : {
    1996           0 :   NS_ENSURE_TRUE(aIndex >= 0 && static_cast<uint32_t>(aIndex) < mRowCount, NS_ERROR_ILLEGAL_VALUE);
    1997             : 
    1998             :   int32_t rowIndex;
    1999             :   nsIAutoCompleteResult *result;
    2000           0 :   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
    2001           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2002             : 
    2003             :   uint16_t searchResult;
    2004           0 :   result->GetSearchResult(&searchResult);
    2005             : 
    2006           0 :   if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) {
    2007           0 :     if (aGetValue)
    2008           0 :       return NS_ERROR_FAILURE;
    2009           0 :     result->GetErrorDescription(_retval);
    2010           0 :   } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
    2011           0 :              searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
    2012           0 :     if (aGetFinalValue) {
    2013             :       // Some implementations may miss finalCompleteValue, try to be backwards
    2014             :       // compatible.
    2015           0 :       if (NS_FAILED(result->GetFinalCompleteValueAt(rowIndex, _retval))) {
    2016           0 :         result->GetValueAt(rowIndex, _retval);
    2017             :       }
    2018           0 :     } else if (aGetValue) {
    2019           0 :       result->GetValueAt(rowIndex, _retval);
    2020             :     } else {
    2021           0 :       result->GetLabelAt(rowIndex, _retval);
    2022             :     }
    2023             :   }
    2024             : 
    2025           0 :   return NS_OK;
    2026             : }
    2027             : 
    2028             : /**
    2029             :  * Given the index of a row in the autocomplete popup, find the
    2030             :  * corresponding nsIAutoCompleteSearch index, and sub-index into
    2031             :  * the search's results list.
    2032             :  */
    2033             : nsresult
    2034           0 : nsAutoCompleteController::RowIndexToSearch(int32_t aRowIndex, int32_t *aSearchIndex, int32_t *aItemIndex)
    2035             : {
    2036           0 :   *aSearchIndex = -1;
    2037           0 :   *aItemIndex = -1;
    2038             : 
    2039           0 :   uint32_t index = 0;
    2040             : 
    2041             :   // Move index through the results of each registered nsIAutoCompleteSearch
    2042             :   // until we find the given row
    2043           0 :   for (uint32_t i = 0; i < mSearches.Length(); ++i) {
    2044           0 :     nsIAutoCompleteResult *result = mResults.SafeObjectAt(i);
    2045           0 :     if (!result)
    2046           0 :       continue;
    2047             : 
    2048           0 :     uint32_t rowCount = 0;
    2049             : 
    2050             :     uint16_t searchResult;
    2051           0 :     result->GetSearchResult(&searchResult);
    2052             : 
    2053             :     // Find out how many results were provided by the
    2054             :     // current nsIAutoCompleteSearch.
    2055           0 :     if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
    2056           0 :         searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
    2057           0 :       result->GetMatchCount(&rowCount);
    2058             :     }
    2059             : 
    2060             :     // If the given row index is within the results range
    2061             :     // of the current nsIAutoCompleteSearch then return the
    2062             :     // search index and sub-index into the results array
    2063           0 :     if ((rowCount != 0) && (index + rowCount-1 >= (uint32_t) aRowIndex)) {
    2064           0 :       *aSearchIndex = i;
    2065           0 :       *aItemIndex = aRowIndex - index;
    2066           0 :       return NS_OK;
    2067             :     }
    2068             : 
    2069             :     // Advance the popup table index cursor past the
    2070             :     // results of the current search.
    2071           0 :     index += rowCount;
    2072             :   }
    2073             : 
    2074           0 :   return NS_OK;
    2075             : }
    2076             : 
    2077           6 : NS_GENERIC_FACTORY_CONSTRUCTOR(nsAutoCompleteController)
    2078           0 : NS_GENERIC_FACTORY_CONSTRUCTOR(nsAutoCompleteSimpleResult)
    2079             : 
    2080             : NS_DEFINE_NAMED_CID(NS_AUTOCOMPLETECONTROLLER_CID);
    2081             : NS_DEFINE_NAMED_CID(NS_AUTOCOMPLETESIMPLERESULT_CID);
    2082             : 
    2083             : static const mozilla::Module::CIDEntry kAutoCompleteCIDs[] = {
    2084             :   { &kNS_AUTOCOMPLETECONTROLLER_CID, false, nullptr, nsAutoCompleteControllerConstructor },
    2085             :   { &kNS_AUTOCOMPLETESIMPLERESULT_CID, false, nullptr, nsAutoCompleteSimpleResultConstructor },
    2086             :   { nullptr }
    2087             : };
    2088             : 
    2089             : static const mozilla::Module::ContractIDEntry kAutoCompleteContracts[] = {
    2090             :   { NS_AUTOCOMPLETECONTROLLER_CONTRACTID, &kNS_AUTOCOMPLETECONTROLLER_CID },
    2091             :   { NS_AUTOCOMPLETESIMPLERESULT_CONTRACTID, &kNS_AUTOCOMPLETESIMPLERESULT_CID },
    2092             :   { nullptr }
    2093             : };
    2094             : 
    2095             : static const mozilla::Module kAutoCompleteModule = {
    2096             :   mozilla::Module::kVersion,
    2097             :   kAutoCompleteCIDs,
    2098             :   kAutoCompleteContracts
    2099             : };
    2100             : 
    2101             : NSMODULE_DEFN(tkAutoCompleteModule) = &kAutoCompleteModule;

Generated by: LCOV version 1.13