Bug 610545, check for a transition earlier to avoid assertion if a panel is opened while it is closing, r=neil

This commit is contained in:
Neil Deakin 2014-04-08 08:45:52 -04:00
parent 77a876d7d3
commit b6f3539dc4
2 changed files with 43 additions and 52 deletions

View File

@ -950,12 +950,15 @@ public:
{
mContent->RemoveSystemEventListener(NS_LITERAL_STRING("transitionend"), this, false);
nsMenuPopupFrame* popupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
// Now hide the popup. There could be other properties transitioning, but
// we'll assume they all end at the same time and just hide the popup upon
// the first one ending.
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) {
pm->HidePopupFrame(mContent, mDeselectMenu);
if (pm && popupFrame) {
pm->HidePopupCallback(mContent, popupFrame, nullptr, nullptr,
popupFrame->PopupType(), mDeselectMenu);
}
return NS_OK;
@ -970,8 +973,7 @@ nsXULPopupManager::HidePopupCallback(nsIContent* aPopup,
nsIContent* aNextPopup,
nsIContent* aLastPopup,
nsPopupType aPopupType,
bool aDeselectMenu,
bool aIsRollup)
bool aDeselectMenu)
{
if (mCloseTimer && mTimerMenu == aPopupFrame) {
mCloseTimer->Cancel();
@ -1007,31 +1009,18 @@ nsXULPopupManager::HidePopupCallback(nsIContent* aPopup,
delete item;
// If the popup has an animate attribute and it is not set to false, assume
// that it has a closing transition and wait for it to finish. The transition
// may still occur either way, but the view will be hidden and you won't be
// able to see it. If there is a next popup, indicating that mutliple popups
// are rolling up, don't wait and hide the popup right away since the effect
// would likely be undesirable. This also does a quick check to see if the
// popup has a transition defined, and skips the wait if not.
if (!aNextPopup && aPopup->HasAttr(kNameSpaceID_None, nsGkAtoms::animate) &&
aPopupFrame->StyleDisplay()->mTransitionPropertyCount > 0) {
nsAutoString animate;
aPopup->GetAttr(kNameSpaceID_None, nsGkAtoms::animate, animate);
nsWeakFrame weakFrame(aPopupFrame);
aPopupFrame->HidePopup(aDeselectMenu, ePopupClosed);
ENSURE_TRUE(weakFrame.IsAlive());
// If animate="false" then don't transition at all. If animate="cancel",
// only show the transition if cancelling the popup or rolling up.
// Otherwise, always show the transition.
if (!animate.EqualsLiteral("false") &&
(!animate.EqualsLiteral("cancel") || aIsRollup)) {
nsCOMPtr<TransitionEnder> ender = new TransitionEnder(aPopup, aDeselectMenu);
aPopup->AddSystemEventListener(NS_LITERAL_STRING("transitionend"),
ender, false, false);
return;
}
}
HidePopupFrame(aPopup, aDeselectMenu);
// send the popuphidden event synchronously. This event has no default
// behaviour.
nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, NS_XUL_POPUP_HIDDEN, nullptr,
WidgetMouseEvent::eReal);
EventDispatcher::Dispatch(aPopup, aPopupFrame->PresContext(),
&event, nullptr, &status);
ENSURE_TRUE(weakFrame.IsAlive());
// if there are more popups to close, look for the next one
if (aNextPopup && aPopup != aLastPopup) {
@ -1073,26 +1062,6 @@ nsXULPopupManager::HidePopupCallback(nsIContent* aPopup,
}
}
void
nsXULPopupManager::HidePopupFrame(nsIContent* aPopup, bool aDeselectMenu)
{
nsMenuPopupFrame* popupFrame = do_QueryFrame(aPopup->GetPrimaryFrame());
if (!popupFrame)
return;
nsWeakFrame weakFrame(popupFrame);
popupFrame->HidePopup(aDeselectMenu, ePopupClosed);
ENSURE_TRUE(weakFrame.IsAlive());
// send the popuphidden event synchronously. This event has no default
// behaviour.
nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, NS_XUL_POPUP_HIDDEN, nullptr,
WidgetMouseEvent::eReal);
EventDispatcher::Dispatch(aPopup, popupFrame->PresContext(),
&event, nullptr, &status);
}
void
nsXULPopupManager::HidePopup(nsIFrame* aFrame)
{
@ -1397,8 +1366,32 @@ nsXULPopupManager::FirePopupHidingEvent(nsIContent* aPopup,
popupFrame->SetPopupState(ePopupOpenAndVisible);
}
else {
// If the popup has an animate attribute and it is not set to false, assume
// that it has a closing transition and wait for it to finish. The transition
// may still occur either way, but the view will be hidden and you won't be
// able to see it. If there is a next popup, indicating that mutliple popups
// are rolling up, don't wait and hide the popup right away since the effect
// would likely be undesirable. This also does a quick check to see if the
// popup has a transition defined, and skips the wait if not.
if (!aNextPopup && aPopup->HasAttr(kNameSpaceID_None, nsGkAtoms::animate) &&
popupFrame->StyleDisplay()->mTransitionPropertyCount > 0) {
nsAutoString animate;
aPopup->GetAttr(kNameSpaceID_None, nsGkAtoms::animate, animate);
// If animate="false" then don't transition at all. If animate="cancel",
// only show the transition if cancelling the popup or rolling up.
// Otherwise, always show the transition.
if (!animate.EqualsLiteral("false") &&
(!animate.EqualsLiteral("cancel") || aIsRollup)) {
nsCOMPtr<TransitionEnder> ender = new TransitionEnder(aPopup, aDeselectMenu);
aPopup->AddSystemEventListener(NS_LITERAL_STRING("transitionend"),
ender, false, false);
return;
}
}
HidePopupCallback(aPopup, popupFrame, aNextPopup, aLastPopup,
aPopupType, aDeselectMenu, aIsRollup);
aPopupType, aDeselectMenu);
}
}
}

View File

@ -640,9 +640,7 @@ protected:
nsIContent* aNextPopup,
nsIContent* aLastPopup,
nsPopupType aPopupType,
bool aDeselectMenu,
bool aIsRollup);
void HidePopupFrame(nsIContent* aPopup, bool aDeselectMenu);
bool aDeselectMenu);
/**
* Fire a popupshowing event on the popup and then open the popup.