Bug 1194027, add a flag to select elements to indicate if the parent process has the popup open, r=mrbkap
authorNeil Deakin <neil@mozilla.com>
Wed, 03 Aug 2016 07:45:46 -0400
changeset 333682 69b3a93aeba57617eaa4c579bea5c78f343c7d43
parent 333681 8df572afbb5dd8c060eafefcb901d476b2862b69
child 333683 7e96b394d5f04bebd40c6385da9b869851019967
push id10033
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:50:26 +0000
treeherdermozilla-aurora@5dddbefdf759 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1194027
milestone51.0a1
Bug 1194027, add a flag to select elements to indicate if the parent process has the popup open, r=mrbkap
dom/html/HTMLSelectElement.cpp
dom/html/HTMLSelectElement.h
dom/webidl/HTMLSelectElement.webidl
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsComboboxControlFrame.h
layout/forms/nsIComboboxControlFrame.h
layout/forms/nsListControlFrame.cpp
toolkit/modules/SelectContentHelper.jsm
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1880,16 +1880,38 @@ HTMLSelectElement::SetSelectionChanged(b
 void
 HTMLSelectElement::UpdateSelectedOptions()
 {
   if (mSelectedOptions) {
     mSelectedOptions->SetDirty();
   }
 }
 
+bool
+HTMLSelectElement::OpenInParentProcess()
+{
+  nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
+  nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
+  if (comboFrame) {
+    return comboFrame->IsOpenInParentProcess();
+  }
+
+  return false;
+}
+
+void
+HTMLSelectElement::SetOpenInParentProcess(bool aVal)
+{
+  nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
+  nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
+  if (comboFrame) {
+    comboFrame->SetOpenInParentProcess(aVal);
+  }
+}
+
 JSObject*
 HTMLSelectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLSelectElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -427,16 +427,19 @@ public:
   /**
    * Is this a combobox?
    */
   bool IsCombobox() const
   {
     return !Multiple() && Size() <= 1;
   }
 
+  bool OpenInParentProcess();
+  void SetOpenInParentProcess(bool aVal);
+
 protected:
   virtual ~HTMLSelectElement();
 
   friend class SafeOptionListMutation;
 
   // Helper Methods
   /**
    * Check whether the option specified by the index is selected
--- a/dom/webidl/HTMLSelectElement.webidl
+++ b/dom/webidl/HTMLSelectElement.webidl
@@ -53,8 +53,13 @@ interface HTMLSelectElement : HTMLElemen
   boolean reportValidity();
   void setCustomValidity(DOMString error);
 
 // NYI:  readonly attribute NodeList labels;
 
   // https://www.w3.org/Bugs/Public/show_bug.cgi?id=20720
   void remove();
 };
+
+partial interface HTMLSelectElement {
+  [ChromeOnly]
+  attribute boolean openInParentProcess;
+};
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -230,16 +230,17 @@ nsComboboxControlFrame::nsComboboxContro
   , mDisplayISize(0)
   , mRecentSelectedIndex(NS_SKIP_NOTIFY_INDEX)
   , mDisplayedIndex(-1)
   , mLastDropDownBeforeScreenBCoord(nscoord_MIN)
   , mLastDropDownAfterScreenBCoord(nscoord_MIN)
   , mDroppedDown(false)
   , mInRedisplayText(false)
   , mDelayedShowDropDown(false)
+  , mIsOpenInParentProcess(false)
 {
   REFLOW_COUNTER_INIT()
 }
 
 //--------------------------------------------------------------
 nsComboboxControlFrame::~nsComboboxControlFrame()
 {
   REFLOW_COUNTER_DUMP("nsCCF");
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -158,16 +158,27 @@ public:
   virtual int32_t GetIndexOfDisplayArea() override;
   /**
    * @note This method might destroy |this|.
    */
   NS_IMETHOD RedisplaySelectedText() override;
   virtual int32_t UpdateRecentIndex(int32_t aIndex) override;
   virtual void OnContentReset() override;
 
+
+  bool IsOpenInParentProcess() override
+  {
+    return mIsOpenInParentProcess;
+  }
+
+  void SetOpenInParentProcess(bool aVal) override
+  {
+    mIsOpenInParentProcess = aVal;
+  }
+
   // nsISelectControlFrame
   NS_IMETHOD AddOption(int32_t index) override;
   NS_IMETHOD RemoveOption(int32_t index) override;
   NS_IMETHOD DoneAddingChildren(bool aIsDone) override;
   NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) override;
   NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) override;
 
   //nsIRollupListener
@@ -298,16 +309,18 @@ protected:
   nscoord               mLastDropDownAfterScreenBCoord;
   // Current state of the dropdown list, true is dropped down.
   bool                  mDroppedDown;
   // See comment in HandleRedisplayTextEvent().
   bool                  mInRedisplayText;
   // Acting on ShowDropDown(true) is delayed until we're focused.
   bool                  mDelayedShowDropDown;
 
+  bool                  mIsOpenInParentProcess;
+
   // static class data member for Bug 32920
   // only one control can be focused at a time
   static nsComboboxControlFrame* sFocused;
 
 #ifdef DO_REFLOW_COUNTER
   int32_t mReflowId;
 #endif
 };
--- a/layout/forms/nsIComboboxControlFrame.h
+++ b/layout/forms/nsIComboboxControlFrame.h
@@ -16,16 +16,21 @@ class nsIComboboxControlFrame : public n
 public:
   NS_DECL_QUERYFRAME_TARGET(nsIComboboxControlFrame)
 
   /**
    * Indicates whether the list is dropped down
    */
   virtual bool IsDroppedDown() = 0;
 
+  virtual bool IsOpenInParentProcess() = 0;
+  virtual void SetOpenInParentProcess(bool aVal) = 0;
+
+  bool IsDroppedDownOrHasParentPopup() { return IsDroppedDown() || IsOpenInParentProcess(); }
+
   /**
    * Shows or hides the drop down
    */
   virtual void ShowDropDown(bool aDoDropDown) = 0;
 
   /**
    * Gets the Drop Down List
    */
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -1772,23 +1772,24 @@ nsListControlFrame::GetIndexFromDOMEvent
     MOZ_ASSERT(aCurIndex >= 0);
     return NS_OK;
   }
 
   return NS_ERROR_FAILURE;
 }
 
 static bool
-FireShowDropDownEvent(nsIContent* aContent)
+FireShowDropDownEvent(nsIContent* aContent, bool show)
 {
   if (XRE_IsContentProcess() &&
       Preferences::GetBool("browser.tabs.remote.desktopbehavior", false)) {
     nsContentUtils::DispatchChromeEvent(aContent->OwnerDoc(), aContent,
-                                        NS_LITERAL_STRING("mozshowdropdown"), true,
-                                        false);
+                                        show ? NS_LITERAL_STRING("mozshowdropdown") :
+                                               NS_LITERAL_STRING("mozhidedropdown"),
+                                        true, false);
     return true;
   }
 
   return false;
 }
 
 nsresult
 nsListControlFrame::MouseDown(nsIDOMEvent* aMouseEvent)
@@ -1843,17 +1844,17 @@ nsListControlFrame::MouseDown(nsIDOMEven
         nsCOMPtr<nsIDOMEventTarget> etarget;
         aMouseEvent->GetTarget(getter_AddRefs(etarget));
         nsCOMPtr<nsIDOMHTMLOptionElement> option = do_QueryInterface(etarget);
         if (option) {
           return NS_OK;
         }
       }
 
-      if (FireShowDropDownEvent(mContent)) {
+      if (FireShowDropDownEvent(mContent, !mComboboxFrame->IsDroppedDownOrHasParentPopup())) {
         return NS_OK;
       }
 
       if (!IgnoreMouseEventForSelection(aMouseEvent)) {
         return NS_OK;
       }
 
       if (!nsComboboxControlFrame::ToolkitHasNativePopup())
@@ -2086,17 +2087,17 @@ nsListControlFrame::Shutdown()
 void
 nsListControlFrame::DropDownToggleKey(nsIDOMEvent* aKeyEvent)
 {
   // Cocoa widgets do native popups, so don't try to show
   // dropdowns there.
   if (IsInDropDownMode() && !nsComboboxControlFrame::ToolkitHasNativePopup()) {
     aKeyEvent->PreventDefault();
     if (!mComboboxFrame->IsDroppedDown()) {
-      if (!FireShowDropDownEvent(mContent)) {
+      if (!FireShowDropDownEvent(mContent, true)) {
         mComboboxFrame->ShowDropDown(true);
       }
     } else {
       nsWeakFrame weakFrame(this);
       // mEndSelectionIndex is the last item that got selected.
       ComboboxFinish(mEndSelectionIndex);
       if (weakFrame.IsAlive()) {
         FireOnInputAndOnChange();
--- a/toolkit/modules/SelectContentHelper.jsm
+++ b/toolkit/modules/SelectContentHelper.jsm
@@ -60,31 +60,33 @@ this.SelectContentHelper.prototype = {
       // we'll poke a DeferredTask to update the parent sometime
       // in the very near future.
       this._updateTimer.arm();
     });
     this.mut.observe(this.element, {childList: true, subtree: true});
   },
 
   uninit: function() {
+    this.element.openInParentProcess = false;
     this.global.removeMessageListener("Forms:SelectDropDownItem", this);
     this.global.removeMessageListener("Forms:DismissedDropDown", this);
     this.global.removeMessageListener("Forms:MouseOver", this);
     this.global.removeMessageListener("Forms:MouseOut", this);
     this.global.removeEventListener("pagehide", this);
     this.global.removeEventListener("mozhidedropdown", this);
     this.element = null;
     this.global = null;
     this.mut.disconnect();
     this._updateTimer.disarm();
     this._updateTimer = null;
     gOpen = false;
   },
 
   showDropDown: function() {
+    this.element.openInParentProcess = true;
     let rect = this._getBoundingContentRect();
     this.global.sendAsyncMessage("Forms:ShowDropDown", {
       rect: rect,
       options: this._buildOptionList(),
       selectedIndex: this.element.selectedIndex,
       direction: getComputedDirection(this.element)
     });
     gOpen = true;