LCOV - code coverage report
Current view: top level - toolkit/components/satchel - nsFormFillController.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 78 674 11.6 %
Date: 2017-07-14 16:53:18 Functions: 12 87 13.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsFormFillController.h"
       8             : 
       9             : #include "mozilla/ClearOnShutdown.h"
      10             : #include "mozilla/ErrorResult.h"
      11             : #include "mozilla/dom/Element.h"
      12             : #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
      13             : #include "mozilla/dom/HTMLInputElement.h"
      14             : #include "nsIFormAutoComplete.h"
      15             : #include "nsIInputListAutoComplete.h"
      16             : #include "nsIAutoCompleteSimpleResult.h"
      17             : #include "nsString.h"
      18             : #include "nsReadableUtils.h"
      19             : #include "nsIServiceManager.h"
      20             : #include "nsIInterfaceRequestor.h"
      21             : #include "nsIInterfaceRequestorUtils.h"
      22             : #include "nsIDocShellTreeItem.h"
      23             : #include "nsPIDOMWindow.h"
      24             : #include "nsIWebNavigation.h"
      25             : #include "nsIContentViewer.h"
      26             : #include "nsIDOMKeyEvent.h"
      27             : #include "nsIDOMDocument.h"
      28             : #include "nsIDOMElement.h"
      29             : #include "nsIDocument.h"
      30             : #include "nsIContent.h"
      31             : #include "nsIPresShell.h"
      32             : #include "nsRect.h"
      33             : #include "nsIDOMHTMLFormElement.h"
      34             : #include "nsILoginManager.h"
      35             : #include "nsIDOMMouseEvent.h"
      36             : #include "mozilla/ModuleUtils.h"
      37             : #include "nsToolkitCompsCID.h"
      38             : #include "nsEmbedCID.h"
      39             : #include "nsIDOMNSEditableElement.h"
      40             : #include "nsContentUtils.h"
      41             : #include "nsILoadContext.h"
      42             : #include "nsIFrame.h"
      43             : #include "nsIScriptSecurityManager.h"
      44             : #include "nsFocusManager.h"
      45             : 
      46             : using namespace mozilla;
      47             : using namespace mozilla::dom;
      48             : using mozilla::ErrorResult;
      49             : 
      50             : static nsIFormAutoComplete*
      51           0 : GetFormAutoComplete()
      52             : {
      53           0 :   static nsCOMPtr<nsIFormAutoComplete> sInstance;
      54             :   static bool sInitialized = false;
      55           0 :   if (!sInitialized) {
      56             :     nsresult rv;
      57             :     sInstance =
      58           0 :       do_GetService("@mozilla.org/satchel/form-autocomplete;1",
      59           0 :                     &rv);
      60             : 
      61           0 :     if (NS_SUCCEEDED(rv)) {
      62           0 :       ClearOnShutdown(&sInstance);
      63           0 :       sInitialized = true;
      64             :     }
      65             :   }
      66           0 :   return sInstance;
      67             : }
      68             : 
      69           0 : NS_IMPL_CYCLE_COLLECTION(nsFormFillController,
      70             :                          mController, mLoginManager, mFocusedPopup, mDocShells,
      71             :                          mPopups, mLastListener, mLastFormAutoComplete)
      72             : 
      73          52 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormFillController)
      74          49 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFormFillController)
      75          41 :   NS_INTERFACE_MAP_ENTRY(nsIFormFillController)
      76          33 :   NS_INTERFACE_MAP_ENTRY(nsIAutoCompleteInput)
      77          33 :   NS_INTERFACE_MAP_ENTRY(nsIAutoCompleteSearch)
      78          33 :   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
      79          33 :   NS_INTERFACE_MAP_ENTRY(nsIFormAutoCompleteObserver)
      80          33 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
      81          33 : NS_INTERFACE_MAP_END
      82             : 
      83          40 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormFillController)
      84          20 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormFillController)
      85             : 
      86             : 
      87             : 
      88           3 : nsFormFillController::nsFormFillController() :
      89             :   mFocusedInput(nullptr),
      90             :   mFocusedInputNode(nullptr),
      91             :   mListNode(nullptr),
      92             :   // The amount of time a context menu event supresses showing a
      93             :   // popup from a focus event in ms. This matches the threshold in
      94             :   // toolkit/components/passwordmgr/LoginManagerContent.jsm.
      95             :   mFocusAfterRightClickThreshold(400),
      96             :   mTimeout(50),
      97             :   mMinResultsForPopup(1),
      98             :   mMaxRows(0),
      99             :   mLastRightClickTimeStamp(TimeStamp()),
     100             :   mDisableAutoComplete(false),
     101             :   mCompleteDefaultIndex(false),
     102             :   mCompleteSelectedIndex(false),
     103             :   mForceComplete(false),
     104           3 :   mSuppressOnInput(false)
     105             : {
     106           3 :   mController = do_GetService("@mozilla.org/autocomplete/controller;1");
     107           3 :   MOZ_ASSERT(mController);
     108           3 : }
     109             : 
     110           0 : nsFormFillController::~nsFormFillController()
     111             : {
     112           0 :   if (mListNode) {
     113           0 :     mListNode->RemoveMutationObserver(this);
     114           0 :     mListNode = nullptr;
     115             :   }
     116           0 :   if (mFocusedInputNode) {
     117           0 :     MaybeRemoveMutationObserver(mFocusedInputNode);
     118           0 :     mFocusedInputNode = nullptr;
     119           0 :     mFocusedInput = nullptr;
     120             :   }
     121           0 :   RemoveForDocument(nullptr);
     122             : 
     123             :   // Remove ourselves as a focus listener from all cached docShells
     124           0 :   uint32_t count = mDocShells.Length();
     125           0 :   for (uint32_t i = 0; i < count; ++i) {
     126           0 :     nsCOMPtr<nsPIDOMWindowOuter> window = GetWindowForDocShell(mDocShells[i]);
     127           0 :     RemoveWindowListeners(window);
     128             :   }
     129           0 : }
     130             : 
     131             : ////////////////////////////////////////////////////////////////////////
     132             : //// nsIMutationObserver
     133             : //
     134             : 
     135             : void
     136           0 : nsFormFillController::AttributeChanged(nsIDocument* aDocument,
     137             :                                        mozilla::dom::Element* aElement,
     138             :                                        int32_t aNameSpaceID,
     139             :                                        nsIAtom* aAttribute, int32_t aModType,
     140             :                                        const nsAttrValue* aOldValue)
     141             : {
     142           0 :   if ((aAttribute == nsGkAtoms::type || aAttribute == nsGkAtoms::readonly ||
     143           0 :        aAttribute == nsGkAtoms::autocomplete) &&
     144             :       aNameSpaceID == kNameSpaceID_None) {
     145           0 :     nsCOMPtr<nsIDOMHTMLInputElement> focusedInput(mFocusedInput);
     146             :     // Reset the current state of the controller, unconditionally.
     147           0 :     StopControllingInput();
     148             :     // Then restart based on the new values.  We have to delay this
     149             :     // to avoid ending up in an endless loop due to re-registering our
     150             :     // mutation observer (which would notify us again for *this* event).
     151             :     nsCOMPtr<nsIRunnable> event =
     152           0 :       mozilla::NewRunnableMethod<nsCOMPtr<nsIDOMHTMLInputElement>>(
     153             :         "nsFormFillController::MaybeStartControllingInput",
     154             :         this,
     155             :         &nsFormFillController::MaybeStartControllingInput,
     156           0 :         focusedInput);
     157           0 :     NS_DispatchToCurrentThread(event);
     158             :   }
     159             : 
     160           0 :   if (mListNode && mListNode->Contains(aElement)) {
     161           0 :     RevalidateDataList();
     162             :   }
     163           0 : }
     164             : 
     165             : void
     166           0 : nsFormFillController::ContentAppended(nsIDocument* aDocument,
     167             :                                       nsIContent* aContainer,
     168             :                                       nsIContent* aChild,
     169             :                                       int32_t aIndexInContainer)
     170             : {
     171           0 :   if (mListNode && mListNode->Contains(aContainer)) {
     172           0 :     RevalidateDataList();
     173             :   }
     174           0 : }
     175             : 
     176             : void
     177           0 : nsFormFillController::ContentInserted(nsIDocument* aDocument,
     178             :                                       nsIContent* aContainer,
     179             :                                       nsIContent* aChild,
     180             :                                       int32_t aIndexInContainer)
     181             : {
     182           0 :   if (mListNode && mListNode->Contains(aContainer)) {
     183           0 :     RevalidateDataList();
     184             :   }
     185           0 : }
     186             : 
     187             : void
     188           0 : nsFormFillController::ContentRemoved(nsIDocument* aDocument,
     189             :                                      nsIContent* aContainer,
     190             :                                      nsIContent* aChild,
     191             :                                      int32_t aIndexInContainer,
     192             :                                      nsIContent* aPreviousSibling)
     193             : {
     194           0 :   if (mListNode && mListNode->Contains(aContainer)) {
     195           0 :     RevalidateDataList();
     196             :   }
     197           0 : }
     198             : 
     199             : void
     200           0 : nsFormFillController::CharacterDataWillChange(nsIDocument* aDocument,
     201             :                                               nsIContent* aContent,
     202             :                                               CharacterDataChangeInfo* aInfo)
     203             : {
     204           0 : }
     205             : 
     206             : void
     207           0 : nsFormFillController::CharacterDataChanged(nsIDocument* aDocument,
     208             :                                            nsIContent* aContent,
     209             :                                            CharacterDataChangeInfo* aInfo)
     210             : {
     211           0 : }
     212             : 
     213             : void
     214           0 : nsFormFillController::AttributeWillChange(nsIDocument* aDocument,
     215             :                                           mozilla::dom::Element* aElement,
     216             :                                           int32_t aNameSpaceID,
     217             :                                           nsIAtom* aAttribute, int32_t aModType,
     218             :                                           const nsAttrValue* aNewValue)
     219             : {
     220           0 : }
     221             : 
     222             : void
     223           0 : nsFormFillController::NativeAnonymousChildListChange(nsIDocument* aDocument,
     224             :                                                      nsIContent* aContent,
     225             :                                                      bool aIsRemove)
     226             : {
     227           0 : }
     228             : 
     229             : void
     230           0 : nsFormFillController::ParentChainChanged(nsIContent* aContent)
     231             : {
     232           0 : }
     233             : 
     234             : void
     235           0 : nsFormFillController::NodeWillBeDestroyed(const nsINode* aNode)
     236             : {
     237           0 :   mPwmgrInputs.Remove(aNode);
     238           0 :   mAutofillInputs.Remove(aNode);
     239           0 :   if (aNode == mListNode) {
     240           0 :     mListNode = nullptr;
     241           0 :     RevalidateDataList();
     242           0 :   } else if (aNode == mFocusedInputNode) {
     243           0 :     mFocusedInputNode = nullptr;
     244           0 :     mFocusedInput = nullptr;
     245             :   }
     246           0 : }
     247             : 
     248             : void
     249           0 : nsFormFillController::MaybeRemoveMutationObserver(nsINode* aNode)
     250             : {
     251             :   // Nodes being tracked in mPwmgrInputs will have their observers removed when
     252             :   // they stop being tracked.
     253           0 :   if (!mPwmgrInputs.Get(aNode) && !mAutofillInputs.Get(aNode)) {
     254           0 :     aNode->RemoveMutationObserver(this);
     255             :   }
     256           0 : }
     257             : 
     258             : ////////////////////////////////////////////////////////////////////////
     259             : //// nsIFormFillController
     260             : 
     261             : NS_IMETHODIMP
     262           1 : nsFormFillController::AttachToBrowser(nsIDocShell *aDocShell, nsIAutoCompletePopup *aPopup)
     263             : {
     264           1 :   NS_ENSURE_TRUE(aDocShell && aPopup, NS_ERROR_ILLEGAL_VALUE);
     265             : 
     266           1 :   mDocShells.AppendElement(aDocShell);
     267           1 :   mPopups.AppendElement(aPopup);
     268             : 
     269             :   // Listen for focus events on the domWindow of the docShell
     270           2 :   nsCOMPtr<nsPIDOMWindowOuter> window = GetWindowForDocShell(aDocShell);
     271           1 :   AddWindowListeners(window);
     272             : 
     273           1 :   return NS_OK;
     274             : }
     275             : 
     276             : NS_IMETHODIMP
     277           0 : nsFormFillController::DetachFromBrowser(nsIDocShell *aDocShell)
     278             : {
     279           0 :   int32_t index = GetIndexOfDocShell(aDocShell);
     280           0 :   NS_ENSURE_TRUE(index >= 0, NS_ERROR_FAILURE);
     281             : 
     282             :   // Stop listening for focus events on the domWindow of the docShell
     283             :   nsCOMPtr<nsPIDOMWindowOuter> window =
     284           0 :     GetWindowForDocShell(mDocShells.SafeElementAt(index));
     285           0 :   RemoveWindowListeners(window);
     286             : 
     287           0 :   mDocShells.RemoveElementAt(index);
     288           0 :   mPopups.RemoveElementAt(index);
     289             : 
     290           0 :   return NS_OK;
     291             : }
     292             : 
     293             : 
     294             : NS_IMETHODIMP
     295           0 : nsFormFillController::MarkAsLoginManagerField(nsIDOMHTMLInputElement *aInput)
     296             : {
     297             :   /*
     298             :    * The Login Manager can supply autocomplete results for username fields,
     299             :    * when a user has multiple logins stored for a site. It uses this
     300             :    * interface to indicate that the form manager shouldn't handle the
     301             :    * autocomplete. The form manager also checks for this tag when saving
     302             :    * form history (so it doesn't save usernames).
     303             :    */
     304           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
     305           0 :   NS_ENSURE_STATE(node);
     306             : 
     307             :   // If the field was already marked, we don't want to show the popup again.
     308           0 :   if (mPwmgrInputs.Get(node)) {
     309           0 :     return NS_OK;
     310             :   }
     311             : 
     312           0 :   mPwmgrInputs.Put(node, true);
     313           0 :   node->AddMutationObserverUnlessExists(this);
     314             : 
     315           0 :   nsFocusManager *fm = nsFocusManager::GetFocusManager();
     316           0 :   if (fm) {
     317           0 :     nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
     318           0 :     if (SameCOMIdentity(focusedContent, node)) {
     319           0 :       nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(node);
     320           0 :       if (!mFocusedInput) {
     321           0 :         MaybeStartControllingInput(input);
     322             :       }
     323             :     }
     324             :   }
     325             : 
     326           0 :   if (!mLoginManager) {
     327           0 :     mLoginManager = do_GetService("@mozilla.org/login-manager;1");
     328             :   }
     329             : 
     330           0 :   return NS_OK;
     331             : }
     332             : 
     333             : NS_IMETHODIMP
     334           0 : nsFormFillController::MarkAsAutofillField(nsIDOMHTMLInputElement *aInput)
     335             : {
     336             :   /*
     337             :    * Support other components implementing form autofill and handle autocomplete
     338             :    * for the field.
     339             :    */
     340           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
     341           0 :   NS_ENSURE_STATE(node);
     342             : 
     343           0 :   if (mAutofillInputs.Get(node)) {
     344           0 :     return NS_OK;
     345             :   }
     346             : 
     347           0 :   mAutofillInputs.Put(node, true);
     348           0 :   node->AddMutationObserverUnlessExists(this);
     349             : 
     350           0 :   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(aInput);
     351           0 :   txtCtrl->EnablePreview();
     352             : 
     353           0 :   nsFocusManager *fm = nsFocusManager::GetFocusManager();
     354           0 :   if (fm) {
     355           0 :     nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
     356           0 :     if (SameCOMIdentity(focusedContent, node)) {
     357           0 :       nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(node);
     358           0 :       MaybeStartControllingInput(input);
     359             :     }
     360             :   }
     361             : 
     362           0 :   return NS_OK;
     363             : }
     364             : 
     365             : NS_IMETHODIMP
     366           0 : nsFormFillController::GetFocusedInput(nsIDOMHTMLInputElement **aInput) {
     367           0 :   *aInput = mFocusedInput;
     368           0 :   NS_IF_ADDREF(*aInput);
     369           0 :   return NS_OK;
     370             : }
     371             : 
     372             : ////////////////////////////////////////////////////////////////////////
     373             : //// nsIAutoCompleteInput
     374             : 
     375             : NS_IMETHODIMP
     376           0 : nsFormFillController::GetPopup(nsIAutoCompletePopup **aPopup)
     377             : {
     378           0 :   *aPopup = mFocusedPopup;
     379           0 :   NS_IF_ADDREF(*aPopup);
     380           0 :   return NS_OK;
     381             : }
     382             : 
     383             : NS_IMETHODIMP
     384           0 : nsFormFillController::GetController(nsIAutoCompleteController **aController)
     385             : {
     386           0 :   *aController = mController;
     387           0 :   NS_IF_ADDREF(*aController);
     388           0 :   return NS_OK;
     389             : }
     390             : 
     391             : NS_IMETHODIMP
     392           0 : nsFormFillController::GetPopupOpen(bool *aPopupOpen)
     393             : {
     394           0 :   if (mFocusedPopup) {
     395           0 :     mFocusedPopup->GetPopupOpen(aPopupOpen);
     396             :   } else {
     397           0 :     *aPopupOpen = false;
     398             :   }
     399           0 :   return NS_OK;
     400             : }
     401             : 
     402             : NS_IMETHODIMP
     403           0 : nsFormFillController::SetPopupOpen(bool aPopupOpen)
     404             : {
     405           0 :   if (mFocusedPopup) {
     406           0 :     if (aPopupOpen) {
     407             :       // make sure input field is visible before showing popup (bug 320938)
     408           0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
     409           0 :       NS_ENSURE_STATE(content);
     410           0 :       nsCOMPtr<nsIDocShell> docShell = GetDocShellForInput(mFocusedInput);
     411           0 :       NS_ENSURE_STATE(docShell);
     412           0 :       nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
     413           0 :       NS_ENSURE_STATE(presShell);
     414           0 :       presShell->ScrollContentIntoView(content,
     415             :                                        nsIPresShell::ScrollAxis(
     416             :                                          nsIPresShell::SCROLL_MINIMUM,
     417             :                                          nsIPresShell::SCROLL_IF_NOT_VISIBLE),
     418             :                                        nsIPresShell::ScrollAxis(
     419             :                                          nsIPresShell::SCROLL_MINIMUM,
     420             :                                          nsIPresShell::SCROLL_IF_NOT_VISIBLE),
     421           0 :                                        nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
     422             :       // mFocusedPopup can be destroyed after ScrollContentIntoView, see bug 420089
     423           0 :       if (mFocusedPopup) {
     424           0 :         nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mFocusedInput);
     425           0 :         mFocusedPopup->OpenAutocompletePopup(this, element);
     426             :       }
     427             :     } else {
     428           0 :       mFocusedPopup->ClosePopup();
     429             :     }
     430             :   }
     431             : 
     432           0 :   return NS_OK;
     433             : }
     434             : 
     435             : NS_IMETHODIMP
     436           0 : nsFormFillController::GetDisableAutoComplete(bool *aDisableAutoComplete)
     437             : {
     438           0 :   *aDisableAutoComplete = mDisableAutoComplete;
     439           0 :   return NS_OK;
     440             : }
     441             : 
     442             : NS_IMETHODIMP
     443           0 : nsFormFillController::SetDisableAutoComplete(bool aDisableAutoComplete)
     444             : {
     445           0 :   mDisableAutoComplete = aDisableAutoComplete;
     446           0 :   return NS_OK;
     447             : }
     448             : 
     449             : NS_IMETHODIMP
     450           0 : nsFormFillController::GetCompleteDefaultIndex(bool *aCompleteDefaultIndex)
     451             : {
     452           0 :   *aCompleteDefaultIndex = mCompleteDefaultIndex;
     453           0 :   return NS_OK;
     454             : }
     455             : 
     456             : NS_IMETHODIMP
     457           0 : nsFormFillController::SetCompleteDefaultIndex(bool aCompleteDefaultIndex)
     458             : {
     459           0 :   mCompleteDefaultIndex = aCompleteDefaultIndex;
     460           0 :   return NS_OK;
     461             : }
     462             : 
     463             : NS_IMETHODIMP
     464           0 : nsFormFillController::GetCompleteSelectedIndex(bool *aCompleteSelectedIndex)
     465             : {
     466           0 :   *aCompleteSelectedIndex = mCompleteSelectedIndex;
     467           0 :   return NS_OK;
     468             : }
     469             : 
     470             : NS_IMETHODIMP
     471           0 : nsFormFillController::SetCompleteSelectedIndex(bool aCompleteSelectedIndex)
     472             : {
     473           0 :   mCompleteSelectedIndex = aCompleteSelectedIndex;
     474           0 :   return NS_OK;
     475             : }
     476             : 
     477             : NS_IMETHODIMP
     478           0 : nsFormFillController::GetForceComplete(bool *aForceComplete)
     479             : {
     480           0 :   *aForceComplete = mForceComplete;
     481           0 :   return NS_OK;
     482             : }
     483             : 
     484           0 : NS_IMETHODIMP nsFormFillController::SetForceComplete(bool aForceComplete)
     485             : {
     486           0 :   mForceComplete = aForceComplete;
     487           0 :   return NS_OK;
     488             : }
     489             : 
     490             : NS_IMETHODIMP
     491           0 : nsFormFillController::GetMinResultsForPopup(uint32_t *aMinResultsForPopup)
     492             : {
     493           0 :   *aMinResultsForPopup = mMinResultsForPopup;
     494           0 :   return NS_OK;
     495             : }
     496             : 
     497           0 : NS_IMETHODIMP nsFormFillController::SetMinResultsForPopup(uint32_t aMinResultsForPopup)
     498             : {
     499           0 :   mMinResultsForPopup = aMinResultsForPopup;
     500           0 :   return NS_OK;
     501             : }
     502             : 
     503             : NS_IMETHODIMP
     504           0 : nsFormFillController::GetMaxRows(uint32_t *aMaxRows)
     505             : {
     506           0 :   *aMaxRows = mMaxRows;
     507           0 :   return NS_OK;
     508             : }
     509             : 
     510             : NS_IMETHODIMP
     511           0 : nsFormFillController::SetMaxRows(uint32_t aMaxRows)
     512             : {
     513           0 :   mMaxRows = aMaxRows;
     514           0 :   return NS_OK;
     515             : }
     516             : 
     517             : NS_IMETHODIMP
     518           0 : nsFormFillController::GetShowImageColumn(bool *aShowImageColumn)
     519             : {
     520           0 :   *aShowImageColumn = false;
     521           0 :   return NS_OK;
     522             : }
     523             : 
     524           0 : NS_IMETHODIMP nsFormFillController::SetShowImageColumn(bool aShowImageColumn)
     525             : {
     526           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     527             : }
     528             : 
     529             : 
     530             : NS_IMETHODIMP
     531           0 : nsFormFillController::GetShowCommentColumn(bool *aShowCommentColumn)
     532             : {
     533           0 :   *aShowCommentColumn = false;
     534           0 :   return NS_OK;
     535             : }
     536             : 
     537           0 : NS_IMETHODIMP nsFormFillController::SetShowCommentColumn(bool aShowCommentColumn)
     538             : {
     539           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     540             : }
     541             : 
     542             : NS_IMETHODIMP
     543           0 : nsFormFillController::GetTimeout(uint32_t *aTimeout)
     544             : {
     545           0 :   *aTimeout = mTimeout;
     546           0 :   return NS_OK;
     547             : }
     548             : 
     549           0 : NS_IMETHODIMP nsFormFillController::SetTimeout(uint32_t aTimeout)
     550             : {
     551           0 :   mTimeout = aTimeout;
     552           0 :   return NS_OK;
     553             : }
     554             : 
     555             : NS_IMETHODIMP
     556           0 : nsFormFillController::SetSearchParam(const nsAString &aSearchParam)
     557             : {
     558           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     559             : }
     560             : 
     561             : NS_IMETHODIMP
     562           0 : nsFormFillController::GetSearchParam(nsAString &aSearchParam)
     563             : {
     564           0 :   if (!mFocusedInput) {
     565           0 :     NS_WARNING("mFocusedInput is null for some reason! avoiding a crash. should find out why... - ben");
     566           0 :     return NS_ERROR_FAILURE; // XXX why? fix me.
     567             :   }
     568             : 
     569           0 :   mFocusedInput->GetName(aSearchParam);
     570           0 :   if (aSearchParam.IsEmpty()) {
     571           0 :     nsCOMPtr<Element> element = do_QueryInterface(mFocusedInput);
     572           0 :     element->GetId(aSearchParam);
     573             :   }
     574             : 
     575           0 :   return NS_OK;
     576             : }
     577             : 
     578             : NS_IMETHODIMP
     579           0 : nsFormFillController::GetSearchCount(uint32_t *aSearchCount)
     580             : {
     581           0 :   *aSearchCount = 1;
     582           0 :   return NS_OK;
     583             : }
     584             : 
     585             : NS_IMETHODIMP
     586           0 : nsFormFillController::GetSearchAt(uint32_t index, nsACString & _retval)
     587             : {
     588           0 :   if (mAutofillInputs.Get(mFocusedInputNode)) {
     589           0 :     nsCOMPtr<nsIAutoCompleteSearch> profileSearch = do_GetService("@mozilla.org/autocomplete/search;1?name=autofill-profiles");
     590           0 :     if (profileSearch) {
     591           0 :       _retval.AssignLiteral("autofill-profiles");
     592           0 :       return NS_OK;
     593             :     }
     594             :   }
     595             : 
     596           0 :   _retval.AssignLiteral("form-history");
     597           0 :   return NS_OK;
     598             : }
     599             : 
     600             : NS_IMETHODIMP
     601           0 : nsFormFillController::GetTextValue(nsAString & aTextValue)
     602             : {
     603           0 :   if (mFocusedInput) {
     604           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
     605           0 :     HTMLInputElement::FromContent(content)->GetValue(aTextValue,
     606           0 :                                                      CallerType::System);
     607             :   } else {
     608           0 :     aTextValue.Truncate();
     609             :   }
     610           0 :   return NS_OK;
     611             : }
     612             : 
     613             : NS_IMETHODIMP
     614           0 : nsFormFillController::SetTextValue(const nsAString & aTextValue)
     615             : {
     616           0 :   nsCOMPtr<nsIDOMNSEditableElement> editable = do_QueryInterface(mFocusedInput);
     617           0 :   if (editable) {
     618           0 :     mSuppressOnInput = true;
     619           0 :     editable->SetUserInput(aTextValue);
     620           0 :     mSuppressOnInput = false;
     621             :   }
     622           0 :   return NS_OK;
     623             : }
     624             : 
     625             : NS_IMETHODIMP
     626           0 : nsFormFillController::SetTextValueWithReason(const nsAString & aTextValue,
     627             :                                              uint16_t aReason)
     628             : {
     629           0 :   return SetTextValue(aTextValue);
     630             : }
     631             : 
     632             : NS_IMETHODIMP
     633           0 : nsFormFillController::GetSelectionStart(int32_t *aSelectionStart)
     634             : {
     635           0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
     636           0 :   if (!content) {
     637           0 :     return NS_ERROR_UNEXPECTED;
     638             :   }
     639           0 :   ErrorResult rv;
     640           0 :   *aSelectionStart =
     641           0 :     HTMLInputElement::FromContent(content)->GetSelectionStartIgnoringType(rv);
     642           0 :   return rv.StealNSResult();
     643             : }
     644             : 
     645             : NS_IMETHODIMP
     646           0 : nsFormFillController::GetSelectionEnd(int32_t *aSelectionEnd)
     647             : {
     648           0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
     649           0 :   if (!content) {
     650           0 :     return NS_ERROR_UNEXPECTED;
     651             :   }
     652           0 :   ErrorResult rv;
     653           0 :   *aSelectionEnd =
     654           0 :     HTMLInputElement::FromContent(content)->GetSelectionEndIgnoringType(rv);
     655           0 :   return rv.StealNSResult();
     656             : }
     657             : 
     658             : NS_IMETHODIMP
     659           0 : nsFormFillController::SelectTextRange(int32_t aStartIndex, int32_t aEndIndex)
     660             : {
     661           0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
     662           0 :     if (!content) {
     663           0 :     return NS_ERROR_UNEXPECTED;
     664             :   }
     665           0 :   ErrorResult rv;
     666             :   HTMLInputElement::FromContent(content)->
     667           0 :     SetSelectionRange(aStartIndex, aEndIndex, Optional<nsAString>(), rv);
     668           0 :   return rv.StealNSResult();
     669             : }
     670             : 
     671             : NS_IMETHODIMP
     672           0 : nsFormFillController::OnSearchBegin()
     673             : {
     674           0 :   return NS_OK;
     675             : }
     676             : 
     677             : NS_IMETHODIMP
     678           0 : nsFormFillController::OnSearchComplete()
     679             : {
     680           0 :   return NS_OK;
     681             : }
     682             : 
     683             : NS_IMETHODIMP
     684           0 : nsFormFillController::OnTextEntered(nsIDOMEvent* aEvent,
     685             :                                     bool* aPrevent)
     686             : {
     687           0 :   NS_ENSURE_ARG(aPrevent);
     688           0 :   NS_ENSURE_TRUE(mFocusedInput, NS_OK);
     689             :   // Fire off a DOMAutoComplete event
     690           0 :   nsCOMPtr<nsIDOMDocument> domDoc;
     691           0 :   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mFocusedInput);
     692           0 :   element->GetOwnerDocument(getter_AddRefs(domDoc));
     693           0 :   NS_ENSURE_STATE(domDoc);
     694             : 
     695           0 :   nsCOMPtr<nsIDOMEvent> event;
     696           0 :   domDoc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
     697           0 :   NS_ENSURE_STATE(event);
     698             : 
     699           0 :   event->InitEvent(NS_LITERAL_STRING("DOMAutoComplete"), true, true);
     700             : 
     701             :   // XXXjst: We mark this event as a trusted event, it's up to the
     702             :   // callers of this to ensure that it's only called from trusted
     703             :   // code.
     704           0 :   event->SetTrusted(true);
     705             : 
     706           0 :   nsCOMPtr<EventTarget> targ = do_QueryInterface(mFocusedInput);
     707             : 
     708             :   bool defaultActionEnabled;
     709           0 :   targ->DispatchEvent(event, &defaultActionEnabled);
     710           0 :   *aPrevent = !defaultActionEnabled;
     711           0 :   return NS_OK;
     712             : }
     713             : 
     714             : NS_IMETHODIMP
     715           0 : nsFormFillController::OnTextReverted(bool *_retval)
     716             : {
     717           0 :   return NS_OK;
     718             : }
     719             : 
     720             : NS_IMETHODIMP
     721           0 : nsFormFillController::GetConsumeRollupEvent(bool *aConsumeRollupEvent)
     722             : {
     723           0 :   *aConsumeRollupEvent = false;
     724           0 :   return NS_OK;
     725             : }
     726             : 
     727             : NS_IMETHODIMP
     728           0 : nsFormFillController::GetInPrivateContext(bool *aInPrivateContext)
     729             : {
     730           0 :   if (!mFocusedInput) {
     731           0 :     *aInPrivateContext = false;
     732           0 :     return NS_OK;
     733             :   }
     734             : 
     735           0 :   nsCOMPtr<nsIDOMDocument> inputDoc;
     736           0 :   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mFocusedInput);
     737           0 :   element->GetOwnerDocument(getter_AddRefs(inputDoc));
     738           0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(inputDoc);
     739           0 :   nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
     740           0 :   *aInPrivateContext = loadContext && loadContext->UsePrivateBrowsing();
     741           0 :   return NS_OK;
     742             : }
     743             : 
     744             : NS_IMETHODIMP
     745           0 : nsFormFillController::GetNoRollupOnCaretMove(bool *aNoRollupOnCaretMove)
     746             : {
     747           0 :   *aNoRollupOnCaretMove = false;
     748           0 :   return NS_OK;
     749             : }
     750             : 
     751             : NS_IMETHODIMP
     752           0 : nsFormFillController::GetUserContextId(uint32_t* aUserContextId)
     753             : {
     754           0 :   *aUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID;
     755           0 :   return NS_OK;
     756             : }
     757             : 
     758             : ////////////////////////////////////////////////////////////////////////
     759             : //// nsIAutoCompleteSearch
     760             : 
     761             : NS_IMETHODIMP
     762           0 : nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAString &aSearchParam,
     763             :                                   nsIAutoCompleteResult *aPreviousResult, nsIAutoCompleteObserver *aListener)
     764             : {
     765             :   nsresult rv;
     766           0 :   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(mFocusedInputNode);
     767             : 
     768             :   // If the login manager has indicated it's responsible for this field, let it
     769             :   // handle the autocomplete. Otherwise, handle with form history.
     770             :   // This method is sometimes called in unit tests and from XUL without a focused node.
     771           0 :   if (mFocusedInputNode &&
     772           0 :       (mPwmgrInputs.Get(mFocusedInputNode) ||
     773           0 :        formControl->ControlType() == NS_FORM_INPUT_PASSWORD)) {
     774             : 
     775             :     // Handle the case where a password field is focused but
     776             :     // MarkAsLoginManagerField wasn't called because password manager is disabled.
     777           0 :     if (!mLoginManager) {
     778           0 :       mLoginManager = do_GetService("@mozilla.org/login-manager;1");
     779             :     }
     780             : 
     781           0 :     if (NS_WARN_IF(!mLoginManager)) {
     782           0 :       return NS_ERROR_FAILURE;
     783             :     }
     784             : 
     785             :     // XXX aPreviousResult shouldn't ever be a historyResult type, since we're not letting
     786             :     // satchel manage the field?
     787           0 :     mLastListener = aListener;
     788           0 :     rv = mLoginManager->AutoCompleteSearchAsync(aSearchString,
     789             :                                                 aPreviousResult,
     790             :                                                 mFocusedInput,
     791           0 :                                                 this);
     792           0 :     NS_ENSURE_SUCCESS(rv, rv);
     793             :   } else {
     794           0 :     mLastListener = aListener;
     795             : 
     796           0 :     nsCOMPtr<nsIAutoCompleteResult> datalistResult;
     797           0 :     if (mFocusedInput) {
     798           0 :       rv = PerformInputListAutoComplete(aSearchString,
     799           0 :                                         getter_AddRefs(datalistResult));
     800           0 :       NS_ENSURE_SUCCESS(rv, rv);
     801             :     }
     802             : 
     803           0 :     auto formAutoComplete = GetFormAutoComplete();
     804           0 :     NS_ENSURE_TRUE(formAutoComplete, NS_ERROR_FAILURE);
     805             : 
     806           0 :     formAutoComplete->AutoCompleteSearchAsync(aSearchParam,
     807             :                                               aSearchString,
     808             :                                               mFocusedInput,
     809             :                                               aPreviousResult,
     810             :                                               datalistResult,
     811           0 :                                               this);
     812           0 :     mLastFormAutoComplete = formAutoComplete;
     813             :   }
     814             : 
     815           0 :   return NS_OK;
     816             : }
     817             : 
     818             : nsresult
     819           0 : nsFormFillController::PerformInputListAutoComplete(const nsAString& aSearch,
     820             :                                                    nsIAutoCompleteResult** aResult)
     821             : {
     822             :   // If an <input> is focused, check if it has a list="<datalist>" which can
     823             :   // provide the list of suggestions.
     824             : 
     825           0 :   MOZ_ASSERT(!mPwmgrInputs.Get(mFocusedInputNode));
     826             :   nsresult rv;
     827             : 
     828             :   nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
     829           0 :     do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
     830           0 :   NS_ENSURE_SUCCESS(rv, rv);
     831           0 :   rv = inputListAutoComplete->AutoCompleteSearch(aSearch,
     832             :                                                  mFocusedInput,
     833           0 :                                                  aResult);
     834           0 :   NS_ENSURE_SUCCESS(rv, rv);
     835             : 
     836           0 :   if (mFocusedInput) {
     837           0 :     nsCOMPtr<nsIDOMHTMLElement> list;
     838           0 :     mFocusedInput->GetList(getter_AddRefs(list));
     839             : 
     840             :     // Add a mutation observer to check for changes to the items in the <datalist>
     841             :     // and update the suggestions accordingly.
     842           0 :     nsCOMPtr<nsINode> node = do_QueryInterface(list);
     843           0 :     if (mListNode != node) {
     844           0 :       if (mListNode) {
     845           0 :         mListNode->RemoveMutationObserver(this);
     846           0 :         mListNode = nullptr;
     847             :       }
     848           0 :       if (node) {
     849           0 :         node->AddMutationObserverUnlessExists(this);
     850           0 :         mListNode = node;
     851             :       }
     852             :     }
     853             :   }
     854             : 
     855           0 :   return NS_OK;
     856             : }
     857             : 
     858           0 : void nsFormFillController::RevalidateDataList()
     859             : {
     860           0 :   if (!mLastListener) {
     861           0 :     return;
     862             :   }
     863             : 
     864           0 :   nsCOMPtr<nsIAutoCompleteController> controller(do_QueryInterface(mLastListener));
     865           0 :   if (!controller) {
     866           0 :     return;
     867             :   }
     868             : 
     869           0 :   controller->StartSearch(mLastSearchString);
     870             : }
     871             : 
     872             : NS_IMETHODIMP
     873           0 : nsFormFillController::StopSearch()
     874             : {
     875             :   // Make sure to stop and clear this, otherwise the controller will prevent
     876             :   // mLastFormAutoComplete from being deleted.
     877           0 :   if (mLastFormAutoComplete) {
     878           0 :     mLastFormAutoComplete->StopAutoCompleteSearch();
     879           0 :     mLastFormAutoComplete = nullptr;
     880           0 :   } else if (mLoginManager) {
     881           0 :     mLoginManager->StopSearch();
     882             :   }
     883           0 :   return NS_OK;
     884             : }
     885             : 
     886             : ////////////////////////////////////////////////////////////////////////
     887             : //// nsIFormAutoCompleteObserver
     888             : 
     889             : NS_IMETHODIMP
     890           0 : nsFormFillController::OnSearchCompletion(nsIAutoCompleteResult *aResult)
     891             : {
     892           0 :   nsAutoString searchString;
     893           0 :   aResult->GetSearchString(searchString);
     894             : 
     895           0 :   mLastSearchString = searchString;
     896             : 
     897           0 :   if (mLastListener) {
     898           0 :     mLastListener->OnSearchResult(this, aResult);
     899             :   }
     900             : 
     901           0 :   return NS_OK;
     902             : }
     903             : 
     904             : ////////////////////////////////////////////////////////////////////////
     905             : //// nsIDOMEventListener
     906             : 
     907             : NS_IMETHODIMP
     908           5 : nsFormFillController::HandleEvent(nsIDOMEvent* aEvent)
     909             : {
     910           5 :   WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
     911           5 :   NS_ENSURE_STATE(internalEvent);
     912             : 
     913           5 :   switch (internalEvent->mMessage) {
     914             :   case eFocus:
     915           4 :     return Focus(aEvent);
     916             :   case eMouseDown:
     917           0 :     return MouseDown(aEvent);
     918             :   case eKeyPress:
     919           0 :     return KeyPress(aEvent);
     920             :   case eEditorInput:
     921             :     {
     922             :       nsCOMPtr<nsINode> input = do_QueryInterface(
     923           0 :         aEvent->InternalDOMEvent()->GetTarget());
     924           0 :       if (!IsTextControl(input)) {
     925           0 :         return NS_OK;
     926             :       }
     927             : 
     928           0 :       bool unused = false;
     929           0 :       return (!mSuppressOnInput && mController && mFocusedInput) ?
     930           0 :              mController->HandleText(&unused) : NS_OK;
     931             :     }
     932             :   case eBlur:
     933           0 :     if (mFocusedInput) {
     934           0 :       StopControllingInput();
     935             :     }
     936           0 :     return NS_OK;
     937             :   case eCompositionStart:
     938           0 :     NS_ASSERTION(mController, "should have a controller!");
     939           0 :     if (mController && mFocusedInput) {
     940           0 :       mController->HandleStartComposition();
     941             :     }
     942           0 :     return NS_OK;
     943             :   case eCompositionEnd:
     944           0 :     NS_ASSERTION(mController, "should have a controller!");
     945           0 :     if (mController && mFocusedInput) {
     946           0 :       mController->HandleEndComposition();
     947             :     }
     948           0 :     return NS_OK;
     949             :   case eContextMenu:
     950           0 :     if (mFocusedPopup) {
     951           0 :       mFocusedPopup->ClosePopup();
     952             :     }
     953           0 :     return NS_OK;
     954             :   case ePageHide:
     955             :     {
     956             :       nsCOMPtr<nsIDocument> doc = do_QueryInterface(
     957           2 :         aEvent->InternalDOMEvent()->GetTarget());
     958           1 :       if (!doc) {
     959           0 :         return NS_OK;
     960             :       }
     961             : 
     962           1 :       if (mFocusedInput) {
     963           0 :         if (doc == mFocusedInputNode->OwnerDoc()) {
     964           0 :           StopControllingInput();
     965             :         }
     966             :       }
     967             : 
     968           1 :       RemoveForDocument(doc);
     969             :     }
     970           1 :     break;
     971             :   default:
     972             :     // Handling the default case to shut up stupid -Wswitch warnings.
     973             :     // One day compilers will be smarter...
     974           0 :     break;
     975             :   }
     976             : 
     977           1 :   return NS_OK;
     978             : }
     979             : 
     980             : void
     981           1 : nsFormFillController::RemoveForDocument(nsIDocument* aDoc)
     982             : {
     983           1 :   for (auto iter = mPwmgrInputs.Iter(); !iter.Done(); iter.Next()) {
     984           0 :     const nsINode* key = iter.Key();
     985           0 :     if (key && (!aDoc || key->OwnerDoc() == aDoc)) {
     986             :       // mFocusedInputNode's observer is tracked separately, so don't remove it
     987             :       // here.
     988           0 :       if (key != mFocusedInputNode) {
     989           0 :         const_cast<nsINode*>(key)->RemoveMutationObserver(this);
     990             :       }
     991           0 :       iter.Remove();
     992             :     }
     993             :   }
     994             : 
     995           1 :   for (auto iter = mAutofillInputs.Iter(); !iter.Done(); iter.Next()) {
     996           0 :     const nsINode* key = iter.Key();
     997           0 :     if (key && (!aDoc || key->OwnerDoc() == aDoc)) {
     998             :       // mFocusedInputNode's observer is tracked separately, so don't remove it
     999             :       // here.
    1000           0 :       if (key != mFocusedInputNode) {
    1001           0 :         const_cast<nsINode*>(key)->RemoveMutationObserver(this);
    1002             :       }
    1003           0 :       iter.Remove();
    1004             :     }
    1005             :   }
    1006           1 : }
    1007             : 
    1008             : bool
    1009           0 : nsFormFillController::IsTextControl(nsINode* aNode)
    1010             : {
    1011           0 :   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aNode);
    1012           0 :   return formControl &&
    1013           0 :          formControl->IsSingleLineTextControl(false);
    1014             : }
    1015             : 
    1016             : void
    1017           4 : nsFormFillController::MaybeStartControllingInput(nsIDOMHTMLInputElement* aInput)
    1018             : {
    1019           4 :   nsCOMPtr<nsINode> inputNode = do_QueryInterface(aInput);
    1020           4 :   if (!inputNode) {
    1021           4 :     return;
    1022             :   }
    1023             : 
    1024           0 :   if (!IsTextControl(inputNode)) {
    1025           0 :     return;
    1026             :   }
    1027             : 
    1028           0 :   bool isReadOnly = false;
    1029           0 :   aInput->GetReadOnly(&isReadOnly);
    1030           0 :   if (isReadOnly) {
    1031           0 :     return;
    1032             :   }
    1033             : 
    1034           0 :   bool autocomplete = nsContentUtils::IsAutocompleteEnabled(aInput);
    1035             : 
    1036           0 :   nsCOMPtr<nsIDOMHTMLElement> datalist;
    1037           0 :   aInput->GetList(getter_AddRefs(datalist));
    1038           0 :   bool hasList = datalist != nullptr;
    1039             : 
    1040           0 :   bool isPwmgrInput = false;
    1041           0 :   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aInput);
    1042           0 :   MOZ_ASSERT(formControl, "If we have a text control, we have a form control!");
    1043           0 :   if (mPwmgrInputs.Get(inputNode) ||
    1044           0 :       formControl->ControlType() == NS_FORM_INPUT_PASSWORD) {
    1045           0 :     isPwmgrInput = true;
    1046             :   }
    1047             : 
    1048           0 :   if (isPwmgrInput || hasList || autocomplete) {
    1049           0 :     StartControllingInput(aInput);
    1050             :   }
    1051             : }
    1052             : 
    1053             : nsresult
    1054           4 : nsFormFillController::Focus(nsIDOMEvent* aEvent)
    1055             : {
    1056             :   nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(
    1057           8 :     aEvent->InternalDOMEvent()->GetTarget());
    1058           4 :   MaybeStartControllingInput(input);
    1059             : 
    1060             :   // Bail if we didn't start controlling the input.
    1061           4 :   if (!mFocusedInputNode) {
    1062           4 :     return NS_OK;
    1063             :   }
    1064             : 
    1065             : #ifndef ANDROID
    1066           0 :   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(mFocusedInputNode);
    1067           0 :   MOZ_ASSERT(formControl);
    1068             : 
    1069             :   // If this focus doesn't follow a right click within our specified
    1070             :   // threshold then show the autocomplete popup for all password fields.
    1071             :   // This is done to avoid showing both the context menu and the popup
    1072             :   // at the same time.
    1073             :   // We use a timestamp instead of a bool to avoid complexity when dealing with
    1074             :   // multiple input forms and the fact that a mousedown into an already focused
    1075             :   // field does not trigger another focus.
    1076             : 
    1077           0 :   if (formControl->ControlType() != NS_FORM_INPUT_PASSWORD) {
    1078           0 :     return NS_OK;
    1079             :   }
    1080             : 
    1081             :   // If we have not seen a right click yet, just show the popup.
    1082           0 :   if (mLastRightClickTimeStamp.IsNull()) {
    1083           0 :     ShowPopup();
    1084           0 :     return NS_OK;
    1085             :   }
    1086             : 
    1087           0 :   uint64_t timeDiff = (TimeStamp::Now() - mLastRightClickTimeStamp).ToMilliseconds();
    1088           0 :   if (timeDiff > mFocusAfterRightClickThreshold) {
    1089           0 :     ShowPopup();
    1090             :   }
    1091             : #endif
    1092             : 
    1093           0 :   return NS_OK;
    1094             : }
    1095             : 
    1096             : nsresult
    1097           0 : nsFormFillController::KeyPress(nsIDOMEvent* aEvent)
    1098             : {
    1099           0 :   NS_ASSERTION(mController, "should have a controller!");
    1100           0 :   if (!mFocusedInput || !mController) {
    1101           0 :     return NS_OK;
    1102             :   }
    1103             : 
    1104           0 :   nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
    1105           0 :   if (!keyEvent) {
    1106           0 :     return NS_ERROR_FAILURE;
    1107             :   }
    1108             : 
    1109           0 :   bool cancel = false;
    1110           0 :   bool unused = false;
    1111             : 
    1112             :   uint32_t k;
    1113           0 :   keyEvent->GetKeyCode(&k);
    1114           0 :   switch (k) {
    1115             :   case nsIDOMKeyEvent::DOM_VK_DELETE:
    1116             : #ifndef XP_MACOSX
    1117           0 :     mController->HandleDelete(&cancel);
    1118           0 :     break;
    1119             :   case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
    1120           0 :     mController->HandleText(&unused);
    1121           0 :     break;
    1122             : #else
    1123             :   case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
    1124             :     {
    1125             :       bool isShift = false;
    1126             :       keyEvent->GetShiftKey(&isShift);
    1127             : 
    1128             :       if (isShift) {
    1129             :         mController->HandleDelete(&cancel);
    1130             :       } else {
    1131             :         mController->HandleText(&unused);
    1132             :       }
    1133             : 
    1134             :       break;
    1135             :     }
    1136             : #endif
    1137             :   case nsIDOMKeyEvent::DOM_VK_PAGE_UP:
    1138             :   case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN:
    1139             :     {
    1140             :       bool isCtrl, isAlt, isMeta;
    1141           0 :       keyEvent->GetCtrlKey(&isCtrl);
    1142           0 :       keyEvent->GetAltKey(&isAlt);
    1143           0 :       keyEvent->GetMetaKey(&isMeta);
    1144           0 :       if (isCtrl || isAlt || isMeta) {
    1145             :         break;
    1146             :       }
    1147             :     }
    1148             :     MOZ_FALLTHROUGH;
    1149             :   case nsIDOMKeyEvent::DOM_VK_UP:
    1150             :   case nsIDOMKeyEvent::DOM_VK_DOWN:
    1151             :   case nsIDOMKeyEvent::DOM_VK_LEFT:
    1152             :   case nsIDOMKeyEvent::DOM_VK_RIGHT:
    1153             :     {
    1154             :       // Get the writing-mode of the relevant input element,
    1155             :       // so that we can remap arrow keys if necessary.
    1156           0 :       mozilla::WritingMode wm;
    1157           0 :       if (mFocusedInputNode && mFocusedInputNode->IsElement()) {
    1158           0 :         mozilla::dom::Element *elem = mFocusedInputNode->AsElement();
    1159           0 :         nsIFrame *frame = elem->GetPrimaryFrame();
    1160           0 :         if (frame) {
    1161           0 :           wm = frame->GetWritingMode();
    1162             :         }
    1163             :       }
    1164           0 :       if (wm.IsVertical()) {
    1165           0 :         switch (k) {
    1166             :         case nsIDOMKeyEvent::DOM_VK_LEFT:
    1167           0 :           k = wm.IsVerticalLR() ? nsIDOMKeyEvent::DOM_VK_UP
    1168             :                                 : nsIDOMKeyEvent::DOM_VK_DOWN;
    1169           0 :           break;
    1170             :         case nsIDOMKeyEvent::DOM_VK_RIGHT:
    1171           0 :           k = wm.IsVerticalLR() ? nsIDOMKeyEvent::DOM_VK_DOWN
    1172             :                                 : nsIDOMKeyEvent::DOM_VK_UP;
    1173           0 :           break;
    1174             :         case nsIDOMKeyEvent::DOM_VK_UP:
    1175           0 :           k = nsIDOMKeyEvent::DOM_VK_LEFT;
    1176           0 :           break;
    1177             :         case nsIDOMKeyEvent::DOM_VK_DOWN:
    1178           0 :           k = nsIDOMKeyEvent::DOM_VK_RIGHT;
    1179           0 :           break;
    1180             :         }
    1181             :       }
    1182             :     }
    1183           0 :     mController->HandleKeyNavigation(k, &cancel);
    1184           0 :     break;
    1185             :   case nsIDOMKeyEvent::DOM_VK_ESCAPE:
    1186           0 :     mController->HandleEscape(&cancel);
    1187           0 :     break;
    1188             :   case nsIDOMKeyEvent::DOM_VK_TAB:
    1189           0 :     mController->HandleTab();
    1190           0 :     cancel = false;
    1191           0 :     break;
    1192             :   case nsIDOMKeyEvent::DOM_VK_RETURN:
    1193           0 :     mController->HandleEnter(false, aEvent, &cancel);
    1194           0 :     break;
    1195             :   }
    1196             : 
    1197           0 :   if (cancel) {
    1198           0 :     aEvent->PreventDefault();
    1199             :     // Don't let the page see the RETURN event when the popup is open
    1200             :     // (indicated by cancel=true) so sites don't manually submit forms
    1201             :     // (e.g. via submit.click()) without the autocompleted value being filled.
    1202             :     // Bug 286933 will fix this for other key events.
    1203           0 :     if (k == nsIDOMKeyEvent::DOM_VK_RETURN) {
    1204           0 :       aEvent->StopPropagation();
    1205             :     }
    1206             :   }
    1207             : 
    1208           0 :   return NS_OK;
    1209             : }
    1210             : 
    1211             : nsresult
    1212           0 : nsFormFillController::MouseDown(nsIDOMEvent* aEvent)
    1213             : {
    1214           0 :   nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aEvent));
    1215           0 :   if (!mouseEvent) {
    1216           0 :     return NS_ERROR_FAILURE;
    1217             :   }
    1218             : 
    1219             :   nsCOMPtr<nsIDOMHTMLInputElement> targetInput = do_QueryInterface(
    1220           0 :     aEvent->InternalDOMEvent()->GetTarget());
    1221           0 :   if (!targetInput) {
    1222           0 :     return NS_OK;
    1223             :   }
    1224             : 
    1225             :   int16_t button;
    1226           0 :   mouseEvent->GetButton(&button);
    1227             : 
    1228             :   // In case of a right click we set a timestamp that
    1229             :   // will be checked in Focus() to avoid showing
    1230             :   // both contextmenu and popup at the same time.
    1231           0 :   if (button == 2) {
    1232           0 :     mLastRightClickTimeStamp = TimeStamp::Now();
    1233           0 :     return NS_OK;
    1234             :   }
    1235             : 
    1236           0 :   if (button != 0) {
    1237           0 :     return NS_OK;
    1238             :   }
    1239             : 
    1240           0 :   return ShowPopup();
    1241             : }
    1242             : 
    1243             : NS_IMETHODIMP
    1244           0 : nsFormFillController::ShowPopup()
    1245             : {
    1246           0 :   bool isOpen = false;
    1247           0 :   GetPopupOpen(&isOpen);
    1248           0 :   if (isOpen) {
    1249           0 :     return SetPopupOpen(false);
    1250             :   }
    1251             : 
    1252           0 :   nsCOMPtr<nsIAutoCompleteInput> input;
    1253           0 :   mController->GetInput(getter_AddRefs(input));
    1254           0 :   if (!input) {
    1255           0 :     return NS_OK;
    1256             :   }
    1257             : 
    1258           0 :   nsAutoString value;
    1259           0 :   input->GetTextValue(value);
    1260           0 :   if (value.Length() > 0) {
    1261             :     // Show the popup with a filtered result set
    1262           0 :     mController->SetSearchString(EmptyString());
    1263           0 :     bool unused = false;
    1264           0 :     mController->HandleText(&unused);
    1265             :   } else {
    1266             :     // Show the popup with the complete result set.  Can't use HandleText()
    1267             :     // because it doesn't display the popup if the input is blank.
    1268           0 :     bool cancel = false;
    1269           0 :     mController->HandleKeyNavigation(nsIDOMKeyEvent::DOM_VK_DOWN, &cancel);
    1270             :   }
    1271             : 
    1272           0 :   return NS_OK;
    1273             : }
    1274             : 
    1275             : ////////////////////////////////////////////////////////////////////////
    1276             : //// nsFormFillController
    1277             : 
    1278             : void
    1279           1 : nsFormFillController::AddWindowListeners(nsPIDOMWindowOuter* aWindow)
    1280             : {
    1281           1 :   if (!aWindow) {
    1282           0 :     return;
    1283             :   }
    1284             : 
    1285           1 :   EventTarget* target = aWindow->GetChromeEventHandler();
    1286             : 
    1287           1 :   if (!target) {
    1288           0 :     return;
    1289             :   }
    1290             : 
    1291           3 :   target->AddEventListener(NS_LITERAL_STRING("focus"), this,
    1292           2 :                            true, false);
    1293           3 :   target->AddEventListener(NS_LITERAL_STRING("blur"), this,
    1294           2 :                            true, false);
    1295           3 :   target->AddEventListener(NS_LITERAL_STRING("pagehide"), this,
    1296           2 :                            true, false);
    1297           3 :   target->AddEventListener(NS_LITERAL_STRING("mousedown"), this,
    1298           2 :                            true, false);
    1299           3 :   target->AddEventListener(NS_LITERAL_STRING("input"), this,
    1300           2 :                            true, false);
    1301           1 :   target->AddEventListener(NS_LITERAL_STRING("keypress"), this, true, false);
    1302           3 :   target->AddEventListener(NS_LITERAL_STRING("compositionstart"), this,
    1303           2 :                            true, false);
    1304           3 :   target->AddEventListener(NS_LITERAL_STRING("compositionend"), this,
    1305           2 :                            true, false);
    1306           3 :   target->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
    1307           2 :                            true, false);
    1308             : 
    1309             :   // Note that any additional listeners added should ensure that they ignore
    1310             :   // untrusted events, which might be sent by content that's up to no good.
    1311             : }
    1312             : 
    1313             : void
    1314           0 : nsFormFillController::RemoveWindowListeners(nsPIDOMWindowOuter* aWindow)
    1315             : {
    1316           0 :   if (!aWindow) {
    1317           0 :     return;
    1318             :   }
    1319             : 
    1320           0 :   StopControllingInput();
    1321             : 
    1322           0 :   nsCOMPtr<nsIDocument> doc = aWindow->GetDoc();
    1323           0 :   RemoveForDocument(doc);
    1324             : 
    1325           0 :   EventTarget* target = aWindow->GetChromeEventHandler();
    1326             : 
    1327           0 :   if (!target) {
    1328           0 :     return;
    1329             :   }
    1330             : 
    1331           0 :   target->RemoveEventListener(NS_LITERAL_STRING("focus"), this, true);
    1332           0 :   target->RemoveEventListener(NS_LITERAL_STRING("blur"), this, true);
    1333           0 :   target->RemoveEventListener(NS_LITERAL_STRING("pagehide"), this, true);
    1334           0 :   target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true);
    1335           0 :   target->RemoveEventListener(NS_LITERAL_STRING("input"), this, true);
    1336           0 :   target->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true);
    1337           0 :   target->RemoveEventListener(NS_LITERAL_STRING("compositionstart"), this,
    1338           0 :                               true);
    1339           0 :   target->RemoveEventListener(NS_LITERAL_STRING("compositionend"), this,
    1340           0 :                               true);
    1341           0 :   target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
    1342             : }
    1343             : 
    1344             : void
    1345           0 : nsFormFillController::StartControllingInput(nsIDOMHTMLInputElement *aInput)
    1346             : {
    1347             :   // Make sure we're not still attached to an input
    1348           0 :   StopControllingInput();
    1349             : 
    1350           0 :   if (!mController) {
    1351           0 :     return;
    1352             :   }
    1353             : 
    1354             :   // Find the currently focused docShell
    1355           0 :   nsCOMPtr<nsIDocShell> docShell = GetDocShellForInput(aInput);
    1356           0 :   int32_t index = GetIndexOfDocShell(docShell);
    1357           0 :   if (index < 0) {
    1358           0 :     return;
    1359             :   }
    1360             : 
    1361             :   // Cache the popup for the focused docShell
    1362           0 :   mFocusedPopup = mPopups.SafeElementAt(index);
    1363             : 
    1364           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
    1365           0 :   if (!node) {
    1366           0 :     return;
    1367             :   }
    1368             : 
    1369           0 :   node->AddMutationObserverUnlessExists(this);
    1370           0 :   mFocusedInputNode = node;
    1371           0 :   mFocusedInput = aInput;
    1372             : 
    1373           0 :   nsCOMPtr<nsIDOMHTMLElement> list;
    1374           0 :   mFocusedInput->GetList(getter_AddRefs(list));
    1375           0 :   nsCOMPtr<nsINode> listNode = do_QueryInterface(list);
    1376           0 :   if (listNode) {
    1377           0 :     listNode->AddMutationObserverUnlessExists(this);
    1378           0 :     mListNode = listNode;
    1379             :   }
    1380             : 
    1381           0 :   mController->SetInput(this);
    1382             : }
    1383             : 
    1384             : void
    1385           0 : nsFormFillController::StopControllingInput()
    1386             : {
    1387           0 :   if (mListNode) {
    1388           0 :     mListNode->RemoveMutationObserver(this);
    1389           0 :     mListNode = nullptr;
    1390             :   }
    1391             : 
    1392           0 :   if (mController) {
    1393             :     // Reset the controller's input, but not if it has been switched
    1394             :     // to another input already, which might happen if the user switches
    1395             :     // focus by clicking another autocomplete textbox
    1396           0 :     nsCOMPtr<nsIAutoCompleteInput> input;
    1397           0 :     mController->GetInput(getter_AddRefs(input));
    1398           0 :     if (input == this) {
    1399           0 :       mController->SetInput(nullptr);
    1400             :     }
    1401             :   }
    1402             : 
    1403           0 :   if (mFocusedInputNode) {
    1404           0 :     MaybeRemoveMutationObserver(mFocusedInputNode);
    1405             : 
    1406           0 :     mFocusedInputNode = nullptr;
    1407           0 :     mFocusedInput = nullptr;
    1408             :   }
    1409             : 
    1410           0 :   if (mFocusedPopup) {
    1411           0 :     mFocusedPopup->ClosePopup();
    1412             :   }
    1413           0 :   mFocusedPopup = nullptr;
    1414           0 : }
    1415             : 
    1416             : nsIDocShell *
    1417           0 : nsFormFillController::GetDocShellForInput(nsIDOMHTMLInputElement *aInput)
    1418             : {
    1419           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
    1420           0 :   NS_ENSURE_TRUE(node, nullptr);
    1421             : 
    1422           0 :   nsCOMPtr<nsPIDOMWindowOuter> win = node->OwnerDoc()->GetWindow();
    1423           0 :   NS_ENSURE_TRUE(win, nullptr);
    1424             : 
    1425           0 :   return win->GetDocShell();
    1426             : }
    1427             : 
    1428             : nsPIDOMWindowOuter*
    1429           1 : nsFormFillController::GetWindowForDocShell(nsIDocShell *aDocShell)
    1430             : {
    1431           2 :   nsCOMPtr<nsIContentViewer> contentViewer;
    1432           1 :   aDocShell->GetContentViewer(getter_AddRefs(contentViewer));
    1433           1 :   NS_ENSURE_TRUE(contentViewer, nullptr);
    1434             : 
    1435           2 :   nsCOMPtr<nsIDOMDocument> domDoc;
    1436           1 :   contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
    1437           2 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
    1438           1 :   NS_ENSURE_TRUE(doc, nullptr);
    1439             : 
    1440           1 :   return doc->GetWindow();
    1441             : }
    1442             : 
    1443             : int32_t
    1444           0 : nsFormFillController::GetIndexOfDocShell(nsIDocShell *aDocShell)
    1445             : {
    1446           0 :   if (!aDocShell) {
    1447           0 :     return -1;
    1448             :   }
    1449             : 
    1450             :   // Loop through our cached docShells looking for the given docShell
    1451           0 :   uint32_t count = mDocShells.Length();
    1452           0 :   for (uint32_t i = 0; i < count; ++i) {
    1453           0 :     if (mDocShells[i] == aDocShell) {
    1454           0 :       return i;
    1455             :     }
    1456             :   }
    1457             : 
    1458             :   // Recursively check the parent docShell of this one
    1459           0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(aDocShell);
    1460           0 :   nsCOMPtr<nsIDocShellTreeItem> parentItem;
    1461           0 :   treeItem->GetParent(getter_AddRefs(parentItem));
    1462           0 :   if (parentItem) {
    1463           0 :     nsCOMPtr<nsIDocShell> parentShell = do_QueryInterface(parentItem);
    1464           0 :     return GetIndexOfDocShell(parentShell);
    1465             :   }
    1466             : 
    1467           0 :   return -1;
    1468             : }
    1469             : 
    1470           6 : NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormFillController)
    1471             : 
    1472             : NS_DEFINE_NAMED_CID(NS_FORMFILLCONTROLLER_CID);
    1473             : 
    1474             : static const mozilla::Module::CIDEntry kSatchelCIDs[] = {
    1475             :   { &kNS_FORMFILLCONTROLLER_CID, false, nullptr, nsFormFillControllerConstructor },
    1476             :   { nullptr }
    1477             : };
    1478             : 
    1479             : static const mozilla::Module::ContractIDEntry kSatchelContracts[] = {
    1480             :   { "@mozilla.org/satchel/form-fill-controller;1", &kNS_FORMFILLCONTROLLER_CID },
    1481             :   { NS_FORMHISTORYAUTOCOMPLETE_CONTRACTID, &kNS_FORMFILLCONTROLLER_CID },
    1482             :   { nullptr }
    1483             : };
    1484             : 
    1485             : static const mozilla::Module kSatchelModule = {
    1486             :   mozilla::Module::kVersion,
    1487             :   kSatchelCIDs,
    1488             :   kSatchelContracts
    1489             : };
    1490             : 
    1491             : NSMODULE_DEFN(satchel) = &kSatchelModule;

Generated by: LCOV version 1.13