author | Stone Shih <sshih@mozilla.com> |
Fri, 08 Sep 2017 11:01:22 +0800 | |
changeset 383624 | 5b0935d488462ccbc30e58a0140ad28743a1e18e |
parent 383623 | c60d8a8d46dfa4e4489370474ef1220ec41c8e4b |
child 383625 | 0c8a91346605eafd3d28572f8430ed7559f25731 |
push id | 95601 |
push user | sshih@mozilla.com |
push date | Fri, 29 Sep 2017 02:39:02 +0000 |
treeherder | mozilla-inbound@5b0935d48846 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | masayuki |
bugs | 1316251 |
milestone | 58.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -611,16 +611,18 @@ EventStateManager::PreHandleEvent(nsPres if (touchEvent->mMessage == eTouchMove) { GenerateDragGesture(aPresContext, touchEvent); } else { mInTouchDrag = false; StopTrackingDragGesture(); } } + PointerEventHandler::UpdateActivePointerState(mouseEvent); + switch (aEvent->mMessage) { case eContextMenu: if (sIsPointerLocked) { return NS_ERROR_DOM_INVALID_STATE_ERR; } break; case eMouseTouchDrag: mInTouchDrag = true; @@ -705,16 +707,20 @@ EventStateManager::PreHandleEvent(nsPres GenerateMouseEnterExit(mouseEvent); //This is a window level mouse exit event and should stop here aEvent->mMessage = eVoidEvent; break; } MOZ_FALLTHROUGH; case eMouseMove: case ePointerDown: + if (aEvent->mMessage == ePointerDown) { + PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent); + } + MOZ_FALLTHROUGH; case ePointerMove: { // on the Mac, GenerateDragGesture() may not return until the drag // has completed and so |aTargetFrame| may have been deleted (moving // a bookmark, for example). If this is the case, however, we know // that ClearFrameRefs() has been called and it cleared out // |mCurrentTarget|. As a result, we should pass |mCurrentTarget| // into UpdateCursor(). GenerateDragGesture(aPresContext, mouseEvent); @@ -3192,25 +3198,38 @@ EventStateManager::PostHandleEvent(nsPre } } } } SetActiveManager(this, activeContent); } break; case ePointerCancel: { - if(WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { - GenerateMouseEnterExit(mouseEvent); + if(WidgetMouseEvent* pointerEvent = aEvent->AsPointerEvent()) { + // Implicitly releasing capture for given pointer. ePointerLostCapture + // should be send after ePointerUp or ePointerCancel. + PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent); + GenerateMouseEnterExit(pointerEvent); + // After UP/Cancel Touch pointers become invalid so we can remove relevant + // helper from Table. Mouse/Pen pointers are valid all the time (not only + // between down/up) + if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { + mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId); + GenerateMouseEnterExit(pointerEvent); + } } - // After firing the pointercancel event, a user agent must also fire a - // pointerout event followed by a pointerleave event. - MOZ_FALLTHROUGH; + break; } case ePointerUp: { WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent(); + + // Implicitly releasing capture for given pointer. ePointerLostCapture + // should be send after ePointerUp or ePointerCancel. + PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent); + // After UP/Cancel Touch pointers become invalid so we can remove relevant helper from Table // Mouse/Pen pointers are valid all the time (not only between down/up) if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId); GenerateMouseEnterExit(pointerEvent); } break; } @@ -5056,17 +5075,19 @@ EventStateManager::ResetLastOverForConte if (aElemWrapper && aElemWrapper->mLastOverElement && nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement, aContent)) { aElemWrapper->mLastOverElement = nullptr; } } void -EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent) +EventStateManager::ContentRemoved(nsIDocument* aDocument, + nsIContent* aMaybeContainer, + nsIContent* aContent) { /* * Anchor and area elements when focused or hovered might make the UI to show * the current link. We want to make sure that the UI gets informed when they * are actually removed from the DOM. */ if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) && (aContent->AsElement()->State().HasAtLeastOneOfStates(NS_EVENT_STATE_FOCUS | @@ -5099,16 +5120,18 @@ EventStateManager::ContentRemoved(nsIDoc } if (sDragOverContent && sDragOverContent->OwnerDoc() == aContent->OwnerDoc() && nsContentUtils::ContentIsDescendantOf(sDragOverContent, aContent)) { sDragOverContent = nullptr; } + PointerEventHandler::ReleaseIfCaptureByDescendant(aContent); + // See bug 292146 for why we want to null this out ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent); for (auto iter = mPointersEnterLeaveHelper.Iter(); !iter.Done(); iter.Next()) { ResetLastOverForContent(iter.Key(), iter.Data(), aContent); } }
--- a/dom/events/EventStateManager.h +++ b/dom/events/EventStateManager.h @@ -135,17 +135,19 @@ public: * @return Whether the content was able to change all states. Returns false * if a resulting DOM event causes the content node passed in * to not change states. Note, the frame for the content may * change as a result of the content state change, because of * frame reconstructions that may occur, but this does not * affect the return value. */ bool SetContentState(nsIContent* aContent, EventStates aState); - void ContentRemoved(nsIDocument* aDocument, nsIContent* aContent); + void ContentRemoved(nsIDocument* aDocument, nsIContent* aMaybeContainer, + nsIContent* aContent); + bool EventStatusOK(WidgetGUIEvent* aEvent); /** * EventStateManager stores IMEContentObserver while it's observing contents. * Following mehtods are called by IMEContentObserver when it starts to * observe or stops observing the content. */ void OnStartToObserveContent(IMEContentObserver* aIMEContentObserver);
--- a/dom/events/PointerEventHandler.cpp +++ b/dom/events/PointerEventHandler.cpp @@ -84,29 +84,26 @@ PointerEventHandler::IsPointerEventEnabl /* static */ bool PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled() { return sPointerEventEnabled && sPointerEventImplicitCapture; } /* static */ void -PointerEventHandler::UpdateActivePointerState(WidgetGUIEvent* aEvent) +PointerEventHandler::UpdateActivePointerState(WidgetMouseEvent* aEvent) { - if (!IsPointerEventEnabled()) { + if (!IsPointerEventEnabled() || !aEvent) { return; } switch (aEvent->mMessage) { case eMouseEnterIntoWidget: // In this case we have to know information about available mouse pointers - if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { - sActivePointersIds->Put(mouseEvent->pointerId, - new PointerInfo(false, mouseEvent->inputSource, - true)); - } + sActivePointersIds->Put(aEvent->pointerId, + new PointerInfo(false, aEvent->inputSource, true)); break; case ePointerDown: // In this case we switch pointer to active state if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { sActivePointersIds->Put(pointerEvent->pointerId, new PointerInfo(true, pointerEvent->inputSource, pointerEvent->mIsPrimary)); } @@ -122,19 +119,17 @@ PointerEventHandler::UpdateActivePointer } else { sActivePointersIds->Remove(pointerEvent->pointerId); } } break; case eMouseExitFromWidget: // In this case we have to remove information about disappeared mouse // pointers - if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { - sActivePointersIds->Remove(mouseEvent->pointerId); - } + sActivePointersIds->Remove(aEvent->pointerId); break; default: break; } } /* static */ void PointerEventHandler::SetPointerCaptureById(uint32_t aPointerId, @@ -213,16 +208,55 @@ PointerEventHandler::CheckPointerCapture captureInfo->mOverrideContent = pendingContent; if (captureInfo->Empty()) { sPointerCaptureList->Remove(aEvent->pointerId); } } } +/* static */ void +PointerEventHandler::ImplicitlyCapturePointer(nsIFrame* aFrame, + WidgetEvent* aEvent) +{ + MOZ_ASSERT(aEvent->mMessage == ePointerDown); + if (!aFrame || !IsPointerEventEnabled() || + !IsPointerEventImplicitCaptureForTouchEnabled()) { + return; + } + WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent(); + NS_WARNING_ASSERTION(pointerEvent, + "Call ImplicitlyCapturePointer with non-pointer event"); + if (pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { + // We only implicitly capture the pointer for touch device. + return; + } + nsCOMPtr<nsIContent> target; + aFrame->GetContentForEvent(aEvent, getter_AddRefs(target)); + while (target && !target->IsElement()) { + target = target->GetParent(); + } + if (NS_WARN_IF(!target)) { + return; + } + SetPointerCaptureById(pointerEvent->pointerId, target); +} + +/* static */ void +PointerEventHandler::ImplicitlyReleasePointerCapture(WidgetEvent* aEvent) +{ + MOZ_ASSERT(aEvent); + if (aEvent->mMessage != ePointerUp && aEvent->mMessage != ePointerCancel) { + return; + } + WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent(); + ReleasePointerCaptureById(pointerEvent->pointerId); + CheckPointerCaptureState(pointerEvent); +} + /* static */ nsIContent* PointerEventHandler::GetPointerCapturingContent(uint32_t aPointerId) { PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId); if (pointerCaptureInfo) { return pointerCaptureInfo->mOverrideContent; } return nullptr;
--- a/dom/events/PointerEventHandler.h +++ b/dom/events/PointerEventHandler.h @@ -54,17 +54,17 @@ public: // Return the preference value of pointer event enabled. static bool IsPointerEventEnabled(); // Return the preference value of implicit capture. static bool IsPointerEventImplicitCaptureForTouchEnabled(); // Called in ESM::PreHandleEvent to update current active pointers in a hash // table. - static void UpdateActivePointerState(WidgetGUIEvent* aEvent); + static void UpdateActivePointerState(WidgetMouseEvent* aEvent); // Got/release pointer capture of the specified pointer by the content. static void SetPointerCaptureById(uint32_t aPointerId, nsIContent* aContent); static void ReleasePointerCaptureById(uint32_t aPointerId); // Get the pointer captured info of the specified pointer. static PointerCaptureInfo* GetPointerCaptureInfo(uint32_t aPointerId); @@ -73,16 +73,20 @@ public: // aActiveState is additional information, which shows state of pointer like // button state for mouse. static bool GetPointerInfo(uint32_t aPointerId, bool& aActiveState); // CheckPointerCaptureState checks cases, when got/lostpointercapture events // should be fired. static void CheckPointerCaptureState(WidgetPointerEvent* aEvent); + // Implicitly get and release capture of current pointer for touch. + static void ImplicitlyCapturePointer(nsIFrame* aFrame, WidgetEvent* aEvent); + static void ImplicitlyReleasePointerCapture(WidgetEvent* aEvent); + /** * GetPointerCapturingFrame returns a target frame of aEvent. If the event is * a mouse or pointer event (except mousedown and pointerdown), the pointer * may be captured by a content. This method returns the capturing content's * primary frame. Otherwise, aFrameUnderCursor. * * @param aFrameUnderCursor A frame under cursor. * @param aEvent A mouse event or pointer event which may be
--- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -4433,17 +4433,18 @@ PresShell::ContentRemoved(nsIDocument *a // Notify the ESM that the content has been removed, so that // it can clean up any state related to the content. // XXX_jwir3: There is no null check for aDocument necessary, since, even // though by nsIMutationObserver, aDocument could be null, the // precondition check that mDocument == aDocument ensures that // aDocument will not be null (since mDocument can't be null unless // we're still intializing). - mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild); + mPresContext->EventStateManager() + ->ContentRemoved(aDocument, aMaybeContainer, aChild); nsAutoCauseReflowNotifier crNotifier(this); // Call this here so it only happens for real content mutations and // not cases when the frame constructor calls its own methods to force // frame reconstruction. nsIContent* oldNextSibling = container->GetChildAt(aIndexInContainer); @@ -4452,18 +4453,16 @@ PresShell::ContentRemoved(nsIDocument *a // After removing aChild from tree we should save information about live ancestor if (mPointerEventTarget) { MOZ_ASSERT(PointerEventHandler::IsPointerEventEnabled()); if (nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) { mPointerEventTarget = aMaybeContainer; } } - PointerEventHandler::ReleaseIfCaptureByDescendant(aChild); - mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling, nsCSSFrameConstructor::REMOVE_CONTENT); if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { MOZ_ASSERT(container == aDocument); NotifyFontSizeInflationEnabledIsDirty(); } @@ -6836,18 +6835,16 @@ PresShell::HandleEvent(nsIFrame* aFrame, // If the event is consumed, cancel APZC panning by setting // mMultipleActionsPrevented. aEvent->mFlags.mMultipleActionsPrevented = true; return NS_OK; } } } - PointerEventHandler::UpdateActivePointerState(aEvent); - if (!nsContentUtils::IsSafeToRunScript() && aEvent->IsAllowedToDispatchDOMEvent()) { if (aEvent->mClass == eCompositionEventClass) { IMEStateManager::OnCompositionEventDiscarded( aEvent->AsCompositionEvent()); } #ifdef DEBUG if (aEvent->IsIMERelatedEvent()) { @@ -7176,42 +7173,25 @@ PresShell::HandleEvent(nsIFrame* aFrame, NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(), "Unexpected document"); nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame(); if (capturingFrame) { frame = capturingFrame; } } - if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { - // Try to keep frame for following check, because - // frame can be damaged during CheckPointerCaptureState. + // Try to keep frame for following check, because frame can be damaged + // during CheckPointerCaptureState. + { AutoWeakFrame frameKeeper(frame); - // Handle pending pointer capture before any pointer events except - // gotpointercapture / lostpointercapture. - PointerEventHandler::CheckPointerCaptureState(pointerEvent); + PointerEventHandler::CheckPointerCaptureState(aEvent->AsPointerEvent()); // Prevent application crashes, in case damaged frame. if (!frameKeeper.IsAlive()) { frame = nullptr; } - // Implicit pointer capture for touch - if (frame && - PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled() && - pointerEvent->mMessage == ePointerDown && - pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { - nsCOMPtr<nsIContent> targetContent; - frame->GetContentForEvent(aEvent, getter_AddRefs(targetContent)); - while (targetContent && !targetContent->IsElement()) { - targetContent = targetContent->GetParent(); - } - if (targetContent) { - PointerEventHandler::SetPointerCaptureById(pointerEvent->pointerId, - targetContent); - } - } } frame = PointerEventHandler::GetPointerCapturingFrame(frame, aEvent); // Suppress mouse event if it's being targeted at an element inside // a document which needs events suppressed if (aEvent->mClass == eMouseEventClass && frame->PresContext()->Document()->EventHandlingSuppressed()) {