bug 1249664 - Save the combobox's dropped-down state across frame reconstruction r?dbaron
We already restore the scroll-position state of the list control frame (via
nsHTMLScrollFrame), so the combobox control frame needs to add a suffix to
its state key so it doesn't overlap.
MozReview-Commit-ID: Eq0X0FCOciZ
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -14,16 +14,17 @@
#include "nsGkAtoms.h"
#include "nsCSSAnonBoxes.h"
#include "nsHTMLParts.h"
#include "nsIFormControl.h"
#include "nsNameSpaceManager.h"
#include "nsIListControlFrame.h"
#include "nsPIDOMWindow.h"
#include "nsIPresShell.h"
+#include "nsPresState.h"
#include "nsContentList.h"
#include "nsView.h"
#include "nsViewManager.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMNode.h"
#include "nsISelectControlFrame.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
@@ -311,24 +312,25 @@ nsComboboxControlFrame::ShowPopup(bool a
viewManager->ResizeView(view, rect);
viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
} else {
viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
nsRect emptyRect(0, 0, 0, 0);
viewManager->ResizeView(view, emptyRect);
}
- // fire a popup dom event
- nsEventStatus status = nsEventStatus_eIgnore;
- WidgetMouseEvent event(true, aShowPopup ? eXULPopupShowing : eXULPopupHiding,
- nullptr, WidgetMouseEvent::eReal);
+ // fire a popup dom event if it is safe to do so
+ nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
+ if (shell && nsContentUtils::IsSafeToRunScript()) {
+ nsEventStatus status = nsEventStatus_eIgnore;
+ WidgetMouseEvent event(true, aShowPopup ? eXULPopupShowing : eXULPopupHiding,
+ nullptr, WidgetMouseEvent::eReal);
- nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
- if (shell)
shell->HandleDOMEventWithTarget(mContent, &event, &status);
+ }
}
bool
nsComboboxControlFrame::ShowList(bool aShowList)
{
nsView* view = mDropdownFrame->GetView();
if (aShowList) {
NS_ASSERTION(!view->HasWidget(),
@@ -442,17 +444,17 @@ nsComboboxControlFrame::ReflowDropdown(n
// both sets of mComputedBorderPadding.
nscoord forcedISize = aReflowState.ComputedISize() +
aReflowState.ComputedLogicalBorderPadding().IStartEnd(wm) -
kidReflowState.ComputedLogicalBorderPadding().IStartEnd(wm);
kidReflowState.SetComputedISize(std::max(kidReflowState.ComputedISize(),
forcedISize));
// ensure we start off hidden
- if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
+ if (!mDroppedDown && GetStateBits() & NS_FRAME_FIRST_REFLOW) {
nsView* view = mDropdownFrame->GetView();
nsViewManager* viewManager = view->GetViewManager();
viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
nsRect emptyRect(0, 0, 0, 0);
viewManager->ResizeView(view, emptyRect);
}
// Allow the child to move/size/change-visibility its view if it's currently
@@ -1647,34 +1649,47 @@ nsComboboxControlFrame::OnContentReset()
//--------------------------------------------------------
// nsIStatefulFrame
//--------------------------------------------------------
NS_IMETHODIMP
nsComboboxControlFrame::SaveState(nsPresState** aState)
{
- if (!mListControlFrame)
- return NS_ERROR_FAILURE;
-
- nsIStatefulFrame* stateful = do_QueryFrame(mListControlFrame);
- return stateful->SaveState(aState);
+ MOZ_ASSERT(!(*aState));
+ (*aState) = new nsPresState();
+ (*aState)->SetDroppedDown(mDroppedDown);
+ return NS_OK;
}
NS_IMETHODIMP
nsComboboxControlFrame::RestoreState(nsPresState* aState)
{
- if (!mListControlFrame)
+ if (!aState) {
return NS_ERROR_FAILURE;
-
- nsIStatefulFrame* stateful = do_QueryFrame(mListControlFrame);
- NS_ASSERTION(stateful, "Must implement nsIStatefulFrame");
- return stateful->RestoreState(aState);
+ }
+ ShowList(aState->GetDroppedDown()); // might destroy us
+ return NS_OK;
}
+// Append a suffix so that the state key for the combobox is different
+// from the state key the list control uses to sometimes save the scroll
+// position for the same Element
+NS_IMETHODIMP
+nsComboboxControlFrame::GenerateStateKey(nsIContent* aContent,
+ nsIDocument* aDocument,
+ nsACString& aKey)
+{
+ nsresult rv = nsContentUtils::GenerateStateKey(aContent, aDocument, aKey);
+ if (NS_FAILED(rv) || aKey.IsEmpty()) {
+ return rv;
+ }
+ aKey.Append("CCF");
+ return NS_OK;
+}
// Fennec uses a custom combobox built-in widget.
//
/* static */
bool
nsComboboxControlFrame::ToolkitHasNativePopup()
{
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -199,16 +199,19 @@ public:
virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) override
{ return 0; }
virtual nsIWidget* GetRollupWidget() override;
//nsIStatefulFrame
NS_IMETHOD SaveState(nsPresState** aState) override;
NS_IMETHOD RestoreState(nsPresState* aState) override;
+ NS_IMETHOD GenerateStateKey(nsIContent* aContent,
+ nsIDocument* aDocument,
+ nsACString& aKey) override;
static bool ToolkitHasNativePopup();
protected:
friend class RedisplayTextEvent;
friend class nsAsyncResize;
friend class nsResizeDropdownAtFinalPosition;