Bug 1026310, set the open state only once the opening transition is finished, rename the internal popup states to be clearer, fix UITour.jsm to check the showing state, r=MattN,neil

This commit is contained in:
Neil Deakin 2014-07-14 13:39:04 -04:00
Родитель 6770de9ed0
Коммит e9a4f0f8d4
6 изменённых файлов: 54 добавлений и 30 удалений

Просмотреть файл

@ -842,7 +842,7 @@ this.UITour = {
highlighter.style.width = highlightWidth + "px"; highlighter.style.width = highlightWidth + "px";
// Close a previous highlight so we can relocate the panel. // Close a previous highlight so we can relocate the panel.
if (highlighter.parentElement.state == "open") { if (highlighter.parentElement.state == "showing" || highlighter.parentElement.state == "open") {
highlighter.parentElement.hidePopup(); highlighter.parentElement.hidePopup();
} }
/* The "overlap" position anchors from the top-left but we want to centre highlights at their /* The "overlap" position anchors from the top-left but we want to centre highlights at their
@ -909,7 +909,7 @@ this.UITour = {
let tooltipIcon = document.getElementById("UITourTooltipIcon"); let tooltipIcon = document.getElementById("UITourTooltipIcon");
let tooltipButtons = document.getElementById("UITourTooltipButtons"); let tooltipButtons = document.getElementById("UITourTooltipButtons");
if (tooltip.state == "open") { if (tooltip.state == "showing" || tooltip.state == "open") {
tooltip.hidePopup(); tooltip.hidePopup();
} }

Просмотреть файл

@ -333,6 +333,12 @@ nsMenuPopupFrame::GetShadowStyle()
NS_IMETHODIMP nsXULPopupShownEvent::Run() NS_IMETHODIMP nsXULPopupShownEvent::Run()
{ {
nsMenuPopupFrame* popup = do_QueryFrame(mPopup->GetPrimaryFrame());
// Set the state to visible if the popup is still open.
if (popup && popup->IsOpen()) {
popup->SetPopupState(ePopupShown);
}
WidgetMouseEvent event(true, NS_XUL_POPUP_SHOWN, nullptr, WidgetMouseEvent event(true, NS_XUL_POPUP_SHOWN, nullptr,
WidgetMouseEvent::eReal); WidgetMouseEvent::eReal);
return EventDispatcher::Dispatch(mPopup, mPresContext, &event); return EventDispatcher::Dispatch(mPopup, mPresContext, &event);
@ -486,8 +492,11 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu,
rect.x = rect.y = 0; rect.x = rect.y = 0;
viewManager->ResizeView(view, rect); viewManager->ResizeView(view, rect);
if (mPopupState == ePopupOpening) {
mPopupState = ePopupVisible;
}
viewManager->SetViewVisibility(view, nsViewVisibility_kShow); viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
mPopupState = ePopupOpenAndVisible;
nsContainerFrame::SyncFrameViewProperties(pc, this, nullptr, view, 0); nsContainerFrame::SyncFrameViewProperties(pc, this, nullptr, view, 0);
} }
@ -774,7 +783,7 @@ nsMenuPopupFrame::ShowPopup(bool aIsContextMenu, bool aSelectFirstItem)
InvalidateFrameSubtree(); InvalidateFrameSubtree();
if (mPopupState == ePopupShowing) { if (mPopupState == ePopupShowing) {
mPopupState = ePopupOpen; mPopupState = ePopupOpening;
mIsOpenChanged = true; mIsOpenChanged = true;
nsMenuFrame* menuFrame = do_QueryFrame(GetParent()); nsMenuFrame* menuFrame = do_QueryFrame(GetParent());
@ -1980,12 +1989,13 @@ nsMenuPopupFrame::MoveToAnchor(nsIContent* aAnchorContent,
int32_t aXPos, int32_t aYPos, int32_t aXPos, int32_t aYPos,
bool aAttributesOverride) bool aAttributesOverride)
{ {
NS_ASSERTION(mPopupState == ePopupOpenAndVisible, "popup must be open to move it"); NS_ASSERTION(IsVisible(), "popup must be visible to move it");
nsPopupState oldstate = mPopupState;
InitializePopup(aAnchorContent, mTriggerContent, aPosition, InitializePopup(aAnchorContent, mTriggerContent, aPosition,
aXPos, aYPos, aAttributesOverride); aXPos, aYPos, aAttributesOverride);
// InitializePopup changed the state so reset it. // InitializePopup changed the state so reset it.
mPopupState = ePopupOpenAndVisible; mPopupState = oldstate;
// Pass false here so that flipping and adjusting to fit on the screen happen. // Pass false here so that flipping and adjusting to fit on the screen happen.
SetPopupPosition(nullptr, false, false); SetPopupPosition(nullptr, false, false);

Просмотреть файл

@ -27,10 +27,15 @@ class nsIWidget;
// state changes as follows: // state changes as follows:
// ePopupClosed - initial state // ePopupClosed - initial state
// ePopupShowing - during the period when the popupshowing event fires // ePopupShowing - during the period when the popupshowing event fires
// ePopupOpen - between the popupshowing event and being visible. Creation // ePopupOpening - between the popupshowing event and being visible. Creation
// of the child frames, layout and reflow occurs in this state. // of the child frames, layout and reflow occurs in this
// ePopupOpenAndVisible - layout is done and the popup's view and widget are // state. The popup is stored in the popup manager's list of
// made visible. The popupshown event fires. // open popups during this state.
// ePopupVisible - layout is done and the popup's view and widget are made
// visible. The popup is visible on screen but may be
// transitioning. The popupshown event has not yet fired.
// ePopupShown - the popup has been shown and is fully ready. This state is
// assigned just before the popupshown event fires.
// When closing a popup: // When closing a popup:
// ePopupHidden - during the period when the popuphiding event fires and // ePopupHidden - during the period when the popuphiding event fires and
// the popup is removed. // the popup is removed.
@ -42,9 +47,11 @@ enum nsPopupState {
// popupshowing event has been fired. // popupshowing event has been fired.
ePopupShowing, ePopupShowing,
// state while a popup is open but the widget is not yet visible // state while a popup is open but the widget is not yet visible
ePopupOpen, ePopupOpening,
// state while a popup is visible and waiting for the popupshown event
ePopupVisible,
// state while a popup is open and visible on screen // state while a popup is open and visible on screen
ePopupOpenAndVisible, ePopupShown,
// state from when a popup is requested to be hidden to when it is closed. // state from when a popup is requested to be hidden to when it is closed.
ePopupHiding, ePopupHiding,
// state which indicates that the popup was hidden without firing the // state which indicates that the popup was hidden without firing the
@ -251,7 +258,11 @@ public:
nsPopupType PopupType() const { return mPopupType; } nsPopupType PopupType() const { return mPopupType; }
bool IsMenu() MOZ_OVERRIDE { return mPopupType == ePopupTypeMenu; } bool IsMenu() MOZ_OVERRIDE { return mPopupType == ePopupTypeMenu; }
bool IsOpen() MOZ_OVERRIDE { return mPopupState == ePopupOpen || mPopupState == ePopupOpenAndVisible; } bool IsOpen() MOZ_OVERRIDE { return mPopupState == ePopupOpening ||
mPopupState == ePopupVisible ||
mPopupState == ePopupShown; }
bool IsVisible() { return mPopupState == ePopupVisible ||
mPopupState == ePopupShown; }
bool IsMouseTransparent() { return mMouseTransparent; } bool IsMouseTransparent() { return mMouseTransparent; }

Просмотреть файл

@ -128,7 +128,7 @@ nsPopupBoxObject::MoveToAnchor(nsIDOMElement* aAnchorElement,
nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement)); nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame()); nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
if (menuPopupFrame && menuPopupFrame->PopupState() == ePopupOpenAndVisible) { if (menuPopupFrame && menuPopupFrame->IsVisible()) {
menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride); menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride);
} }
} }
@ -226,13 +226,14 @@ nsPopupBoxObject::GetPopupState(nsAString& aState)
nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
if (menuPopupFrame) { if (menuPopupFrame) {
switch (menuPopupFrame->PopupState()) { switch (menuPopupFrame->PopupState()) {
case ePopupShowing: case ePopupShown:
case ePopupOpen:
aState.AssignLiteral("showing");
break;
case ePopupOpenAndVisible:
aState.AssignLiteral("open"); aState.AssignLiteral("open");
break; break;
case ePopupShowing:
case ePopupOpening:
case ePopupVisible:
aState.AssignLiteral("showing");
break;
case ePopupHiding: case ePopupHiding:
case ePopupInvisible: case ePopupInvisible:
aState.AssignLiteral("hiding"); aState.AssignLiteral("hiding");
@ -284,13 +285,9 @@ nsPopupBoxObject::GetOuterScreenRect(nsIDOMClientRect** aRect)
NS_ADDREF(*aRect = rect); NS_ADDREF(*aRect = rect);
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
if (!menuPopupFrame)
return NS_OK;
// Return an empty rectangle if the popup is not open. // Return an empty rectangle if the popup is not open.
nsPopupState state = menuPopupFrame->PopupState(); nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
if (state != ePopupOpen && state != ePopupOpenAndVisible) if (!menuPopupFrame || !menuPopupFrame->IsOpen())
return NS_OK; return NS_OK;
nsView* view = menuPopupFrame->GetView(); nsView* view = menuPopupFrame->GetView();

Просмотреть файл

@ -394,7 +394,7 @@ nsMenuPopupFrame* GetPopupToMoveOrResize(nsIFrame* aFrame)
return nullptr; return nullptr;
// no point moving or resizing hidden popups // no point moving or resizing hidden popups
if (menuPopupFrame->PopupState() != ePopupOpenAndVisible) if (!menuPopupFrame->IsVisible())
return nullptr; return nullptr;
nsIWidget* widget = menuPopupFrame->GetWidget(); nsIWidget* widget = menuPopupFrame->GetWidget();
@ -1390,7 +1390,11 @@ nsXULPopupManager::FirePopupHidingEvent(nsIContent* aPopup,
// from hiding. // from hiding.
if (status == nsEventStatus_eConsumeNoDefault && if (status == nsEventStatus_eConsumeNoDefault &&
!popupFrame->IsInContentShell()) { !popupFrame->IsInContentShell()) {
popupFrame->SetPopupState(ePopupOpenAndVisible); // XXXndeakin
// If an attempt was made to hide this popup before the popupshown event
// fired, then ePopupShown is set here even though it should be
// ePopupVisible. This probably isn't worth the hassle of handling.
popupFrame->SetPopupState(ePopupShown);
} }
else { else {
// If the popup has an animate attribute and it is not set to false, assume // If the popup has an animate attribute and it is not set to false, assume
@ -1503,10 +1507,9 @@ nsXULPopupManager::GetVisiblePopups(nsTArray<nsIFrame *>& aPopups)
nsMenuChainItem* item = mPopups; nsMenuChainItem* item = mPopups;
for (int32_t list = 0; list < 2; list++) { for (int32_t list = 0; list < 2; list++) {
while (item) { while (item) {
// Skip panels which are not open and visible as well as popups that // Skip panels which are not visible as well as popups that
// are transparent to mouse events. // are transparent to mouse events.
if (item->Frame()->PopupState() == ePopupOpenAndVisible && if (item->Frame()->IsVisible() && !item->Frame()->IsMouseTransparent()) {
!item->Frame()->IsMouseTransparent()) {
aPopups.AppendElement(item->Frame()); aPopups.AppendElement(item->Frame());
} }

Просмотреть файл

@ -186,10 +186,12 @@ function nextTest()
transitions++; transitions++;
// Two properties transition so continue on the second one finishing. // Two properties transition so continue on the second one finishing.
if (!(transitions % 2)) { if (!(transitions % 2)) {
is($("animatepanel").state, "open", "state is open after transitionend");
ok(animatedPopupShown, "popupshown now fired") ok(animatedPopupShown, "popupshown now fired")
SimpleTest.executeSoon(() => runNextTest.next()); SimpleTest.executeSoon(() => runNextTest.next());
} }
else { else {
is($("animatepanel").state, "showing", "state is showing during transitionend");
ok(!animatedPopupShown, "popupshown not fired yet") ok(!animatedPopupShown, "popupshown not fired yet")
} }
} }
@ -197,6 +199,7 @@ function nextTest()
// Check that the transition occurs for an arrow panel with animate="true" // Check that the transition occurs for an arrow panel with animate="true"
window.addEventListener("transitionend", transitionEnded, false); window.addEventListener("transitionend", transitionEnded, false);
$("animatepanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start"); $("animatepanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
is($("animatepanel").state, "showing", "state is showing");
yield; yield;
window.removeEventListener("transitionend", transitionEnded, false); window.removeEventListener("transitionend", transitionEnded, false);