Bug 1461299: Make ESM not point to unbound NAC in the hover / active chain. r=smaug

MozReview-Commit-ID: 8mL7Yv3TwQM
This commit is contained in:
Emilio Cobos Álvarez 2018-05-14 14:49:40 +02:00
parent f4898626f9
commit cf0ce82b71
5 changed files with 60 additions and 35 deletions

View File

@ -5368,6 +5368,51 @@ EventStateManager::ResetLastOverForContent(
}
}
void
EventStateManager::RemoveNodeFromChainIfNeeded(EventStates aState,
nsIContent* aContentRemoved)
{
MOZ_ASSERT(aState == NS_EVENT_STATE_HOVER || aState == NS_EVENT_STATE_ACTIVE);
if (!aContentRemoved->IsElement() ||
!aContentRemoved->AsElement()->State().HasState(aState)) {
return;
}
nsCOMPtr<nsIContent>& leaf =
aState == NS_EVENT_STATE_HOVER ? mHoverContent : mActiveContent;
MOZ_ASSERT(leaf);
// XBL Likes to unbind content without notifying, thus the
// NODE_IS_ANONYMOUS_ROOT check...
MOZ_ASSERT(nsContentUtils::ContentIsFlattenedTreeDescendantOf(
leaf, aContentRemoved) ||
leaf->SubtreeRoot()->HasFlag(NODE_IS_ANONYMOUS_ROOT));
nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
MOZ_ASSERT_IF(newLeaf,
newLeaf->IsElement() &&
newLeaf->AsElement()->State().HasState(aState));
if (aContentRemoved->IsRootOfNativeAnonymousSubtree()) {
// We don't update the removed content's state here, since removing NAC
// happens from layout and we don't really want to notify at that point or
// what not.
//
// Also, NAC is not observable and NAC being removed will go away soon.
leaf = newLeaf;
} else {
SetContentState(newLeaf, aState);
}
MOZ_ASSERT(leaf == newLeaf);
}
void
EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent)
{
MOZ_ASSERT(aContent->IsRootOfAnonymousSubtree());
RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_HOVER, aContent);
RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_ACTIVE, aContent);
}
void
EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
{
@ -5392,29 +5437,8 @@ EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
if (fm)
fm->ContentRemoved(aDocument, aContent);
if (aContent->IsElement() &&
aContent->AsElement()->State().HasState(NS_EVENT_STATE_HOVER)) {
MOZ_ASSERT(mHoverContent);
// XBL Likes to unbind content without notifying, thus the
// NODE_IS_ANONYMOUS_ROOT check...
MOZ_ASSERT(nsContentUtils::ContentIsFlattenedTreeDescendantOf(mHoverContent,
aContent) ||
mHoverContent->SubtreeRoot()->HasFlag(NODE_IS_ANONYMOUS_ROOT));
// Since hover is hierarchical, set the current hover to the
// content's parent node.
SetContentState(aContent->GetFlattenedTreeParent(), NS_EVENT_STATE_HOVER);
}
if (aContent->IsElement() &&
aContent->AsElement()->State().HasState(NS_EVENT_STATE_ACTIVE)) {
MOZ_ASSERT(mActiveContent);
MOZ_ASSERT(nsContentUtils::ContentIsFlattenedTreeDescendantOf(mActiveContent,
aContent) ||
mHoverContent->SubtreeRoot()->HasFlag(NODE_IS_ANONYMOUS_ROOT));
// Active is hierarchical, so set the current active to the
// content's parent node.
SetContentState(aContent->GetFlattenedTreeParent(), NS_EVENT_STATE_ACTIVE);
}
RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_HOVER, aContent);
RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_ACTIVE, aContent);
if (sDragOverContent &&
sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&

View File

@ -148,6 +148,8 @@ public:
* affect the return value.
*/
bool SetContentState(nsIContent* aContent, EventStates aState);
void NativeAnonymousContentRemoved(nsIContent* aAnonContent);
void ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
bool EventStatusOK(WidgetGUIEvent* aEvent);
@ -1087,6 +1089,13 @@ protected:
void HandleQueryContentEvent(WidgetQueryContentEvent* aEvent);
private:
// Removes a node from the :hover / :active chain if needed, notifying if the
// node is not a NAC subtree.
//
// Only meant to be called from ContentRemoved and
// NativeAnonymousContentRemoved.
void RemoveNodeFromChainIfNeeded(EventStates aState,
nsIContent* aContentRemoved);
bool IsEventOutsideDragThreshold(WidgetInputEvent* aEvent) const;

View File

@ -259,14 +259,6 @@ nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
}
}
void
nsFrameManager::DestroyAnonymousContent(already_AddRefed<nsIContent> aContent)
{
if (nsCOMPtr<nsIContent> content = aContent) {
content->UnbindFromTree();
}
}
void
nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
{

View File

@ -93,8 +93,6 @@ public:
void RestoreFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);
void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
protected:

View File

@ -246,8 +246,10 @@ nsReflowStatus::UpdateTruncated(const ReflowInput& aReflowInput,
nsIFrame::DestroyAnonymousContent(nsPresContext* aPresContext,
already_AddRefed<nsIContent>&& aContent)
{
aPresContext->PresShell()->FrameConstructor()
->DestroyAnonymousContent(Move(aContent));
if (nsCOMPtr<nsIContent> content = aContent) {
aPresContext->EventStateManager()->NativeAnonymousContentRemoved(content);
content->UnbindFromTree();
}
}
// Formerly the nsIFrameDebug interface