Bug 1525101 - adjust nsIAutoCompletePopup to make custom element popups working, r=peterv
authorAlexander Surkov <surkov.alexander@gmail.com>
Mon, 25 Feb 2019 20:02:17 +0000
changeset 461009 bea571f9708b466869f9032e2faedac64e62f05b
parent 461008 be96f71b4344ffa18e7621bbc21e236f1a596d31
child 461010 fcf3d5468b1f1838504b2b75f856f2beff73fab7
push id112146
push usernerli@mozilla.com
push dateTue, 26 Feb 2019 04:26:08 +0000
treeherdermozilla-inbound@c4ce50209f19 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs1525101
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1525101 - adjust nsIAutoCompletePopup to make custom element popups working, r=peterv Differential Revision: https://phabricator.services.mozilla.com/D20504
dom/base/Element.cpp
dom/base/Element.h
toolkit/components/autocomplete/nsAutoCompleteController.cpp
toolkit/components/autocomplete/nsAutoCompleteController.h
toolkit/components/autocomplete/nsIAutoCompleteInput.idl
toolkit/components/places/nsNavHistory.cpp
toolkit/components/satchel/nsFormFillController.cpp
toolkit/content/widgets/autocomplete.xml
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -154,16 +154,17 @@
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMXULRadioGroupElement.h"
 #include "nsIDOMXULRelatedElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIBrowser.h"
+#include "nsIAutoCompletePopup.h"
 
 #include "nsISpeculativeConnect.h"
 #include "nsIIOService.h"
 
 #include "DOMMatrix.h"
 
 using mozilla::gfx::Matrix4x4;
 
@@ -4079,16 +4080,22 @@ Element::AsXULSelectControlItem() {
 }
 
 already_AddRefed<nsIBrowser> Element::AsBrowser() {
   nsCOMPtr<nsIBrowser> value;
   GetCustomInterface(getter_AddRefs(value));
   return value.forget();
 }
 
+already_AddRefed<nsIAutoCompletePopup> Element::AsAutoCompletePopup() {
+  nsCOMPtr<nsIAutoCompletePopup> value;
+  GetCustomInterface(getter_AddRefs(value));
+  return value.forget();
+}
+
 MOZ_DEFINE_MALLOC_SIZE_OF(ServoElementMallocSizeOf)
 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoElementMallocEnclosingSizeOf)
 
 void Element::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
                                      size_t* aNodeSize) const {
   FragmentOrElement::AddSizeOfExcludingThis(aSizes, aNodeSize);
   *aNodeSize += mAttrs.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
 
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -67,16 +67,17 @@ class nsIDOMXULContainerItemElement;
 class nsIDOMXULControlElement;
 class nsIDOMXULMenuListElement;
 class nsIDOMXULMultiSelectControlElement;
 class nsIDOMXULRadioGroupElement;
 class nsIDOMXULRelatedElement;
 class nsIDOMXULSelectControlElement;
 class nsIDOMXULSelectControlItemElement;
 class nsIBrowser;
+class nsIAutoCompletePopup;
 
 namespace mozilla {
 class DeclarationBlock;
 struct MutationClosureData;
 class TextEditor;
 namespace css {
 struct URLValue;
 }  // namespace css
@@ -1586,16 +1587,17 @@ class Element : public FragmentOrElement
   already_AddRefed<nsIDOMXULMenuListElement> AsXULMenuList();
   already_AddRefed<nsIDOMXULMultiSelectControlElement>
   AsXULMultiSelectControl();
   already_AddRefed<nsIDOMXULRadioGroupElement> AsXULRadioGroup();
   already_AddRefed<nsIDOMXULRelatedElement> AsXULRelated();
   already_AddRefed<nsIDOMXULSelectControlElement> AsXULSelectControl();
   already_AddRefed<nsIDOMXULSelectControlItemElement> AsXULSelectControlItem();
   already_AddRefed<nsIBrowser> AsBrowser();
+  already_AddRefed<nsIAutoCompletePopup> AsAutoCompletePopup();
 
  protected:
   /*
    * Named-bools for use with SetAttrAndNotify to make call sites easier to
    * read.
    */
   static const bool kFireMutationEvent = true;
   static const bool kDontFireMutationEvent = false;
--- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp
@@ -92,18 +92,18 @@ nsAutoCompleteController::GetInput(nsIAu
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::SetInitiallySelectedIndex(int32_t aSelectedIndex) {
   // First forward to the popup.
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
   NS_ENSURE_STATE(input);
-  nsCOMPtr<nsIAutoCompletePopup> popup;
-  input->GetPopup(getter_AddRefs(popup));
+
+  nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
   NS_ENSURE_STATE(popup);
   popup->SetSelectedIndex(aSelectedIndex);
 
   // Now take care of internal stuff.
   bool completeSelection;
   if (NS_SUCCEEDED(input->GetCompleteSelectedIndex(&completeSelection)) &&
       completeSelection) {
     mCompletedSelectionIndex = aSelectedIndex;
@@ -289,19 +289,17 @@ nsAutoCompleteController::HandleEnter(bo
   *_retval = false;
   if (!mInput) return NS_OK;
 
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
 
   // allow the event through unless there is something selected in the popup
   input->GetPopupOpen(_retval);
   if (*_retval) {
-    nsCOMPtr<nsIAutoCompletePopup> popup;
-    input->GetPopup(getter_AddRefs(popup));
-
+    nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
     if (popup) {
       int32_t selectedIndex;
       popup->GetSelectedIndex(&selectedIndex);
       *_retval = selectedIndex >= 0;
     }
   }
 
   // Stop the search, and handle the enter.
@@ -398,18 +396,17 @@ nsAutoCompleteController::HandleKeyNavig
     // See https://bugzilla.mozilla.org/show_bug.cgi?id=193544#c31
     NS_ERROR(
         "Called before attaching to the control or after detaching from the "
         "control");
     return NS_OK;
   }
 
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
-  nsCOMPtr<nsIAutoCompletePopup> popup;
-  input->GetPopup(getter_AddRefs(popup));
+  nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
 
   bool disabled;
   input->GetDisableAutoComplete(&disabled);
   NS_ENSURE_TRUE(!disabled, NS_OK);
 
   if (aKey == dom::KeyboardEvent_Binding::DOM_VK_UP ||
       aKey == dom::KeyboardEvent_Binding::DOM_VK_DOWN ||
@@ -639,18 +636,18 @@ nsAutoCompleteController::HandleDelete(b
   input->GetPopupOpen(&isOpen);
   if (!isOpen || mMatchCount == 0) {
     // Nothing left to delete, proceed as normal
     bool unused = false;
     HandleText(&unused);
     return NS_OK;
   }
 
-  nsCOMPtr<nsIAutoCompletePopup> popup;
-  input->GetPopup(getter_AddRefs(popup));
+  nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
+  NS_ENSURE_TRUE(popup, NS_ERROR_FAILURE);
 
   int32_t index, searchIndex, matchIndex;
   popup->GetSelectedIndex(&index);
   if (index == -1) {
     // No match is selected in the list
     bool unused = false;
     HandleText(&unused);
     return NS_OK;
@@ -869,18 +866,17 @@ nsresult nsAutoCompleteController::Close
   }
 
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
 
   bool isOpen = false;
   input->GetPopupOpen(&isOpen);
   if (!isOpen) return NS_OK;
 
-  nsCOMPtr<nsIAutoCompletePopup> popup;
-  input->GetPopup(getter_AddRefs(popup));
+  nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
   MOZ_ALWAYS_SUCCEEDS(input->SetPopupOpen(false));
   return popup->SetSelectedIndex(-1);
 }
 
 nsresult nsAutoCompleteController::BeforeSearches() {
   NS_ENSURE_STATE(mInput);
 
@@ -1133,18 +1129,17 @@ nsresult nsAutoCompleteController::Clear
     mTimer = nullptr;
   }
   return NS_OK;
 }
 
 nsresult nsAutoCompleteController::EnterMatch(bool aIsPopupSelection,
                                               dom::Event *aEvent) {
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
-  nsCOMPtr<nsIAutoCompletePopup> popup;
-  input->GetPopup(getter_AddRefs(popup));
+  nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
 
   bool forceComplete;
   input->GetForceComplete(&forceComplete);
 
   // Ask the popup if it wants to enter a special value into the textbox
   nsAutoString value;
   popup->GetOverrideValue(value);
@@ -1374,18 +1369,17 @@ nsresult nsAutoCompleteController::Proce
     mMatchCount += delta;
   }
 
   // Try to autocomplete the default index for this search.
   // Do this before invalidating so the binding knows about it.
   CompleteDefaultIndex(aSearchIndex);
 
   // Refresh the popup view to display the new search results
-  nsCOMPtr<nsIAutoCompletePopup> popup;
-  input->GetPopup(getter_AddRefs(popup));
+  nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
   popup->Invalidate(nsIAutoCompletePopup::INVALIDATE_REASON_NEW_RESULT);
 
   uint32_t minResults;
   input->GetMinResultsForPopup(&minResults);
 
   // Make sure the popup is open, if necessary, since we now have at least one
   // search result ready to display. Don't force the popup closed if we might
@@ -1424,18 +1418,17 @@ nsresult nsAutoCompleteController::PostS
 }
 
 nsresult nsAutoCompleteController::ClearResults(bool aIsSearching) {
   int32_t oldMatchCount = mMatchCount;
   mMatchCount = 0;
   mResults.Clear();
   if (oldMatchCount != 0) {
     if (mInput) {
-      nsCOMPtr<nsIAutoCompletePopup> popup;
-      mInput->GetPopup(getter_AddRefs(popup));
+      nsCOMPtr<nsIAutoCompletePopup> popup(GetPopup());
       NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
       // Clear the selection.
       popup->SetSelectedIndex(-1);
     }
   }
   return NS_OK;
 }
 
--- a/toolkit/components/autocomplete/nsAutoCompleteController.h
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.h
@@ -13,16 +13,17 @@
 #include "nsIAutoCompleteResult.h"
 #include "nsIAutoCompleteSearch.h"
 #include "nsINamed.h"
 #include "nsString.h"
 #include "nsITimer.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 #include "nsCycleCollectionParticipant.h"
+#include "mozilla/dom/Element.h"
 
 class nsAutoCompleteController final : public nsIAutoCompleteController,
                                        public nsIAutoCompleteObserver,
                                        public nsITimerCallback,
                                        public nsINamed {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsAutoCompleteController,
@@ -72,16 +73,38 @@ class nsAutoCompleteController final : p
   nsresult CompleteValue(nsString& aValue);
 
   nsresult GetResultAt(int32_t aIndex, nsIAutoCompleteResult** aResult,
                        int32_t* aMatchIndex);
   nsresult GetResultValueAt(int32_t aIndex, bool aGetFinalValue,
                             nsAString& _retval);
   nsresult GetResultLabelAt(int32_t aIndex, nsAString& _retval);
 
+  /**
+   * Returns autocomplete popup for the autocomplete input. nsIAutoCompleteInput
+   * can be implemented two different ways to return a popup. The first one is
+   * to return a popup object implementing nsIAutoCompletePopup interface,
+   * the second one is a DOM element representing a popup and implementing
+   * that interface.
+   */
+  already_AddRefed<nsIAutoCompletePopup> GetPopup() {
+    nsCOMPtr<nsIAutoCompletePopup> popup;
+    mInput->GetPopup(getter_AddRefs(popup));
+    if (popup) {
+      return popup.forget();
+    }
+
+    nsCOMPtr<Element> popupEl;
+    mInput->GetPopupElement(getter_AddRefs(popupEl));
+    if (popupEl) {
+      return popupEl->AsAutoCompletePopup();
+    }
+    return nullptr;
+  }
+
  private:
   nsresult GetResultValueLabelAt(int32_t aIndex, bool aGetFinalValue,
                                  bool aGetValue, nsAString& _retval);
 
   /**
    * Gets and validates the defaultComplete result and the relative
    * defaultIndex value.
    *
--- a/toolkit/components/autocomplete/nsIAutoCompleteInput.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteInput.idl
@@ -3,23 +3,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIAutoCompleteController.idl"
 
 interface nsIAutoCompletePopup;
 
 webidl Event;
+webidl Element;
 
 [scriptable, uuid(B068E70F-F82C-4C12-AD87-82E271C5C180)]
 interface nsIAutoCompleteInput : nsISupports
 {
   /*
    * The result view that will be used to display results
    */
+  readonly attribute Element popupElement;
   readonly attribute nsIAutoCompletePopup popup;
 
   /*
    * The controller.
    */
   readonly attribute nsIAutoCompleteController controller;
 
   /*
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -2269,17 +2269,27 @@ nsNavHistory::Observe(nsISupports* aSubj
     // If the source is a private window, don't add any input history.
     bool isPrivate;
     nsresult rv = input->GetInPrivateContext(&isPrivate);
     NS_ENSURE_SUCCESS(rv, rv);
     if (isPrivate) return NS_OK;
 
     nsCOMPtr<nsIAutoCompletePopup> popup;
     input->GetPopup(getter_AddRefs(popup));
-    if (!popup) return NS_OK;
+    if (!popup) {
+      nsCOMPtr<Element> popupEl;
+      input->GetPopupElement(getter_AddRefs(popupEl));
+      if (!popupEl) {
+        return NS_OK;
+      }
+      popup = popupEl->AsAutoCompletePopup();
+      if (!popup) {
+        return NS_OK;
+      }
+    }
 
     nsCOMPtr<nsIAutoCompleteController> controller;
     input->GetController(getter_AddRefs(controller));
     if (!controller) return NS_OK;
 
     // Don't bother if the popup is closed
     bool open;
     rv = popup->GetPopupOpen(&open);
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -322,16 +322,21 @@ nsFormFillController::GetFocusedInput(HT
 NS_IMETHODIMP
 nsFormFillController::GetPopup(nsIAutoCompletePopup** aPopup) {
   *aPopup = mFocusedPopup;
   NS_IF_ADDREF(*aPopup);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsFormFillController::GetPopupElement(Element** aPopup) {
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsFormFillController::GetController(nsIAutoCompleteController** aController) {
   *aController = mController;
   NS_IF_ADDREF(*aController);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFormFillController::GetPopupOpen(bool* aPopupOpen) {
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -77,16 +77,18 @@
             let popupset = document.getAnonymousElementByAttribute(this, "anonid", "popupset");
             popupset.appendChild(popup);
           }
           popup.mInput = this;
 
           return this._popup = popup;
         ]]></getter>
       </property>
+      <property name="popupElement" readonly="true"
+                onget="return this.popup;"/>
 
       <property name="controller" onget="return this.mController;" readonly="true"/>
 
       <property name="popupOpen"
                 onget="return this.popup.popupOpen;"
                 onset="if (val) this.openPopup(); else this.closePopup();"/>
 
       <property name="disableAutoComplete"