--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -34,16 +34,17 @@
#include "mozilla/dom/DOMRect.h"
#include "nsAttrValue.h"
#include "mozilla/EventForwards.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/DOMTokenListSupportedTokens.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/UniquePtr.h"
#include "Units.h"
#include "DOMIntersectionObserver.h"
class mozAutoDocUpdate;
class nsIFrame;
class nsIDOMMozNamedAttrMap;
class nsIMozBrowserFrame;
@@ -973,44 +974,44 @@ public:
void InsertAdjacentText(const nsAString& aWhere,
const nsAString& aData,
ErrorResult& aError);
void SetPointerCapture(int32_t aPointerId, ErrorResult& aError)
{
bool activeState = false;
- if (!nsIPresShell::GetPointerInfo(aPointerId, activeState)) {
+ if (!PointerEventHandler::GetPointerInfo(aPointerId, activeState)) {
aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
return;
}
if (!IsInUncomposedDoc()) {
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (!activeState) {
return;
}
- nsIPresShell::SetPointerCapturingContent(aPointerId, this);
+ PointerEventHandler::SetPointerCaptureById(aPointerId, this);
}
void ReleasePointerCapture(int32_t aPointerId, ErrorResult& aError)
{
bool activeState = false;
- if (!nsIPresShell::GetPointerInfo(aPointerId, activeState)) {
+ if (!PointerEventHandler::GetPointerInfo(aPointerId, activeState)) {
aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
return;
}
if (HasPointerCapture(aPointerId)) {
- nsIPresShell::ReleasePointerCapturingContent(aPointerId);
+ PointerEventHandler::ReleasePointerCaptureById(aPointerId);
}
}
bool HasPointerCapture(long aPointerId)
{
- nsIPresShell::PointerCaptureInfo* pointerCaptureInfo =
- nsIPresShell::GetPointerCaptureInfo(aPointerId);
+ PointerCaptureInfo* pointerCaptureInfo =
+ PointerEventHandler::GetPointerCaptureInfo(aPointerId);
if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent == this) {
return true;
}
return false;
}
void SetCapture(bool aRetargetToElement)
{
// If there is already an active capture, ignore this request. This would
new file mode 100644
--- /dev/null
+++ b/dom/events/PointerEventHandler.cpp
@@ -0,0 +1,479 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PointerEventHandler.h"
+#include "nsIFrame.h"
+#include "PointerEvent.h"
+#include "mozilla/PresShell.h"
+
+namespace mozilla {
+
+using namespace dom;
+
+static bool sPointerEventEnabled = true;
+static bool sPointerEventImplicitCapture = false;
+
+class PointerInfo final
+{
+public:
+ uint16_t mPointerType;
+ bool mActiveState;
+ bool mPrimaryState;
+ bool mPreventMouseEventByContent;
+ explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
+ bool aPrimaryState)
+ : mPointerType(aPointerType)
+ , mActiveState(aActiveState)
+ , mPrimaryState(aPrimaryState)
+ , mPreventMouseEventByContent(false)
+ {
+ }
+};
+
+// Keeps a map between pointerId and element that currently capturing pointer
+// with such pointerId. If pointerId is absent in this map then nobody is
+// capturing it. Additionally keep information about pending capturing content.
+static nsClassHashtable<nsUint32HashKey,
+ PointerCaptureInfo>* sPointerCaptureList;
+
+// Keeps information about pointers such as pointerId, activeState, pointerType,
+// primaryState
+static nsClassHashtable<nsUint32HashKey, PointerInfo>* sActivePointersIds;
+
+/* static */ void
+PointerEventHandler::Initialize()
+{
+ static bool addedPointerEventEnabled = false;
+ if (!addedPointerEventEnabled) {
+ Preferences::AddBoolVarCache(&sPointerEventEnabled,
+ "dom.w3c_pointer_events.enabled", true);
+ addedPointerEventEnabled = true;
+ }
+ static bool addedPointerEventImplicitCapture = false;
+ if (!addedPointerEventImplicitCapture) {
+ Preferences::AddBoolVarCache(&sPointerEventImplicitCapture,
+ "dom.w3c_pointer_events.implicit_capture",
+ true);
+ addedPointerEventImplicitCapture = true;
+ }
+}
+
+/* static */ void
+PointerEventHandler::InitializeStatics()
+{
+ MOZ_ASSERT(!sPointerCaptureList, "InitializeStatics called multiple times!");
+ sPointerCaptureList =
+ new nsClassHashtable<nsUint32HashKey, PointerCaptureInfo>;
+ sActivePointersIds = new nsClassHashtable<nsUint32HashKey, PointerInfo>;
+}
+
+/* static */ void
+PointerEventHandler::ReleaseStatics()
+{
+ MOZ_ASSERT(sPointerCaptureList, "ReleaseStatics called without Initialize!");
+ delete sPointerCaptureList;
+ sPointerCaptureList = nullptr;
+ delete sActivePointersIds;
+ sActivePointersIds = nullptr;
+}
+
+/* static */ bool
+PointerEventHandler::IsPointerEventEnabled()
+{
+ return sPointerEventEnabled;
+}
+
+/* static */ bool
+PointerEventHandler::IsPointerEventImplicitCaptureForTouchEnabled()
+{
+ return sPointerEventEnabled && sPointerEventImplicitCapture;
+}
+
+/* static */ void
+PointerEventHandler::UpdateActivePointerState(WidgetGUIEvent* aEvent)
+{
+ if (!IsPointerEventEnabled()) {
+ 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));
+ }
+ 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));
+ }
+ break;
+ case ePointerUp:
+ // In this case we remove information about pointer or turn off active state
+ if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
+ if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
+ sActivePointersIds->Put(pointerEvent->pointerId,
+ new PointerInfo(false,
+ pointerEvent->inputSource,
+ pointerEvent->mIsPrimary));
+ } 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);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* static */ void
+PointerEventHandler::SetPointerCaptureById(uint32_t aPointerId,
+ nsIContent* aContent)
+{
+ MOZ_ASSERT(aContent);
+ if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
+ nsIPresShell::SetCapturingContent(aContent, CAPTURE_PREVENTDRAG);
+ }
+
+ PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
+ if (pointerCaptureInfo) {
+ pointerCaptureInfo->mPendingContent = aContent;
+ } else {
+ sPointerCaptureList->Put(aPointerId, new PointerCaptureInfo(aContent));
+ }
+}
+
+/* static */ PointerCaptureInfo*
+PointerEventHandler::GetPointerCaptureInfo(uint32_t aPointerId)
+{
+ PointerCaptureInfo* pointerCaptureInfo = nullptr;
+ sPointerCaptureList->Get(aPointerId, &pointerCaptureInfo);
+ return pointerCaptureInfo;
+}
+
+/* static */ void
+PointerEventHandler::ReleasePointerCaptureById(uint32_t aPointerId)
+{
+ PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
+ if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent) {
+ if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
+ nsIPresShell::SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG);
+ }
+ pointerCaptureInfo->mPendingContent = nullptr;
+ }
+}
+
+/* static */ bool
+PointerEventHandler::GetPointerInfo(uint32_t aPointerId, bool& aActiveState)
+{
+ PointerInfo* pointerInfo = nullptr;
+ if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
+ aActiveState = pointerInfo->mActiveState;
+ return true;
+ }
+ return false;
+}
+
+/* static */ void
+PointerEventHandler::CheckPointerCaptureState(WidgetPointerEvent* aEvent)
+{
+ // Handle pending pointer capture before any pointer events except
+ // gotpointercapture / lostpointercapture.
+ if (!aEvent) {
+ return;
+ }
+ MOZ_ASSERT(IsPointerEventEnabled());
+ MOZ_ASSERT(aEvent->mClass == ePointerEventClass);
+
+ PointerCaptureInfo* captureInfo = GetPointerCaptureInfo(aEvent->pointerId);
+
+ if (captureInfo &&
+ captureInfo->mPendingContent != captureInfo->mOverrideContent) {
+ // cache captureInfo->mPendingContent since it may be changed in the pointer
+ // event listener
+ nsIContent* pendingContent = captureInfo->mPendingContent.get();
+ if (captureInfo->mOverrideContent) {
+ DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false, aEvent,
+ captureInfo->mOverrideContent);
+ }
+ if (pendingContent) {
+ DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true, aEvent,
+ pendingContent);
+ }
+
+ captureInfo->mOverrideContent = pendingContent;
+ if (captureInfo->Empty()) {
+ sPointerCaptureList->Remove(aEvent->pointerId);
+ }
+ }
+}
+
+/* static */ nsIContent*
+PointerEventHandler::GetPointerCapturingContent(uint32_t aPointerId)
+{
+ PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
+ if (pointerCaptureInfo) {
+ return pointerCaptureInfo->mOverrideContent;
+ }
+ return nullptr;
+}
+
+/* static */ void
+PointerEventHandler::ReleaseIfCaptureByDescendant(nsIContent* aContent)
+{
+ // We should check that aChild does not contain pointer capturing elements.
+ // If it does we should release the pointer capture for the elements.
+ for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
+ PointerCaptureInfo* data = iter.UserData();
+ if (data && data->mPendingContent &&
+ nsContentUtils::ContentIsDescendantOf(data->mPendingContent,
+ aContent)) {
+ ReleasePointerCaptureById(iter.Key());
+ }
+ }
+}
+
+/* static */ void
+PointerEventHandler::PreHandlePointerEventsPreventDefault(
+ WidgetPointerEvent* aPointerEvent,
+ WidgetGUIEvent* aMouseOrTouchEvent)
+{
+ if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage == ePointerDown) {
+ return;
+ }
+ PointerInfo* pointerInfo = nullptr;
+ if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
+ !pointerInfo) {
+ // The PointerInfo for active pointer should be added for normal cases. But
+ // in some cases, we may receive mouse events before adding PointerInfo in
+ // sActivePointersIds. (e.g. receive mousemove before eMouseEnterIntoWidget
+ // or change preference 'dom.w3c_pointer_events.enabled' from off to on).
+ // In these cases, we could ignore them because they are not the events
+ // between a DefaultPrevented pointerdown and the corresponding pointerup.
+ return;
+ }
+ if (!pointerInfo->mPreventMouseEventByContent) {
+ return;
+ }
+ aMouseOrTouchEvent->PreventDefault(false);
+ if (aPointerEvent->mMessage == ePointerUp) {
+ pointerInfo->mPreventMouseEventByContent = false;
+ }
+}
+
+/* static */ void
+PointerEventHandler::PostHandlePointerEventsPreventDefault(
+ WidgetPointerEvent* aPointerEvent,
+ WidgetGUIEvent* aMouseOrTouchEvent)
+{
+ if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage != ePointerDown ||
+ !aPointerEvent->DefaultPreventedByContent()) {
+ return;
+ }
+ PointerInfo* pointerInfo = nullptr;
+ if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
+ !pointerInfo) {
+ // We already added the PointerInfo for active pointer when
+ // PresShell::HandleEvent handling pointerdown event.
+#ifdef DEBUG
+ MOZ_CRASH("Got ePointerDown w/o active pointer info!!");
+#endif // #ifdef DEBUG
+ return;
+ }
+ // PreventDefault only applied for active pointers.
+ if (!pointerInfo->mActiveState) {
+ return;
+ }
+ aMouseOrTouchEvent->PreventDefault(false);
+ pointerInfo->mPreventMouseEventByContent = true;
+}
+
+/* static */ nsresult
+PointerEventHandler::DispatchPointerFromMouseOrTouch(
+ PresShell* aShell,
+ nsIFrame* aFrame,
+ WidgetGUIEvent* aEvent,
+ bool aDontRetargetEvents,
+ nsEventStatus* aStatus,
+ nsIContent** aTargetContent)
+{
+ EventMessage pointerMessage = eVoidEvent;
+ if (aEvent->mClass == eMouseEventClass) {
+ WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
+ // 1. If it is not mouse then it is likely will come as touch event
+ // 2. We don't synthesize pointer events for those events that are not
+ // dispatched to DOM.
+ if (!mouseEvent->convertToPointer ||
+ !aEvent->IsAllowedToDispatchDOMEvent()) {
+ return NS_OK;
+ }
+ int16_t button = mouseEvent->button;
+ switch (mouseEvent->mMessage) {
+ case eMouseMove:
+ button = WidgetMouseEvent::eNoButton;
+ pointerMessage = ePointerMove;
+ break;
+ case eMouseUp:
+ pointerMessage = mouseEvent->buttons ? ePointerMove : ePointerUp;
+ break;
+ case eMouseDown:
+ pointerMessage =
+ mouseEvent->buttons & ~nsContentUtils::GetButtonsFlagForButton(button) ?
+ ePointerMove : ePointerDown;
+ break;
+ default:
+ return NS_OK;
+ }
+
+ WidgetPointerEvent event(*mouseEvent);
+ event.pointerId = mouseEvent->pointerId;
+ event.inputSource = mouseEvent->inputSource;
+ event.mMessage = pointerMessage;
+ event.button = button;
+ event.buttons = mouseEvent->buttons;
+ event.pressure = event.buttons ?
+ mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
+ 0.0f;
+ event.convertToPointer = mouseEvent->convertToPointer = false;
+ PreHandlePointerEventsPreventDefault(&event, aEvent);
+ RefPtr<PresShell> shell(aShell);
+ shell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
+ aTargetContent);
+ PostHandlePointerEventsPreventDefault(&event, aEvent);
+ } else if (aEvent->mClass == eTouchEventClass) {
+ WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
+ int16_t button = WidgetMouseEvent::eLeftButton;
+ int16_t buttons = WidgetMouseEvent::eLeftButtonFlag;
+ // loop over all touches and dispatch pointer events on each touch
+ // copy the event
+ switch (touchEvent->mMessage) {
+ case eTouchMove:
+ pointerMessage = ePointerMove;
+ button = WidgetMouseEvent::eNoButton;
+ break;
+ case eTouchEnd:
+ pointerMessage = ePointerUp;
+ buttons = WidgetMouseEvent::eNoButtonFlag;
+ break;
+ case eTouchStart:
+ pointerMessage = ePointerDown;
+ break;
+ case eTouchCancel:
+ case eTouchPointerCancel:
+ pointerMessage = ePointerCancel;
+ break;
+ default:
+ return NS_OK;
+ }
+
+ RefPtr<PresShell> shell(aShell);
+ for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
+ Touch* touch = touchEvent->mTouches[i];
+ if (!TouchManager::ShouldConvertTouchToPointer(touch, touchEvent)) {
+ continue;
+ }
+
+ WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
+ touchEvent->mWidget);
+ event.mIsPrimary = i == 0;
+ event.pointerId = touch->Identifier();
+ event.mRefPoint = touch->mRefPoint;
+ event.mModifiers = touchEvent->mModifiers;
+ event.mWidth = touch->RadiusX(CallerType::System);
+ event.mHeight = touch->RadiusY(CallerType::System);
+ event.tiltX = touch->tiltX;
+ event.tiltY = touch->tiltY;
+ event.mTime = touchEvent->mTime;
+ event.mTimeStamp = touchEvent->mTimeStamp;
+ event.mFlags = touchEvent->mFlags;
+ event.button = button;
+ event.buttons = buttons;
+ event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
+ event.convertToPointer = touch->convertToPointer = false;
+ PreHandlePointerEventsPreventDefault(&event, aEvent);
+ shell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
+ aTargetContent);
+ PostHandlePointerEventsPreventDefault(&event, aEvent);
+ }
+ }
+ return NS_OK;
+}
+
+/* static */ uint16_t
+PointerEventHandler::GetPointerType(uint32_t aPointerId)
+{
+ PointerInfo* pointerInfo = nullptr;
+ if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
+ return pointerInfo->mPointerType;
+ }
+ return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
+}
+
+/* static */ bool
+PointerEventHandler::GetPointerPrimaryState(uint32_t aPointerId)
+{
+ PointerInfo* pointerInfo = nullptr;
+ if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
+ return pointerInfo->mPrimaryState;
+ }
+ return false;
+}
+
+/* static */ void
+PointerEventHandler::DispatchGotOrLostPointerCaptureEvent(
+ bool aIsGotCapture,
+ const WidgetPointerEvent* aPointerEvent,
+ nsIContent* aCaptureTarget)
+{
+ nsIDocument* targetDoc = aCaptureTarget->OwnerDoc();
+ nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
+ if (NS_WARN_IF(!shell)) {
+ return;
+ }
+
+ if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) {
+ // If the capturing element was removed from the DOM tree, fire
+ // ePointerLostCapture at the document.
+ PointerEventInit init;
+ init.mPointerId = aPointerEvent->pointerId;
+ init.mBubbles = true;
+ init.mComposed = true;
+ ConvertPointerTypeToString(aPointerEvent->inputSource, init.mPointerType);
+ init.mIsPrimary = aPointerEvent->mIsPrimary;
+ RefPtr<PointerEvent> event;
+ event = PointerEvent::Constructor(aCaptureTarget,
+ NS_LITERAL_STRING("lostpointercapture"),
+ init);
+ bool dummy;
+ targetDoc->DispatchEvent(event->InternalDOMEvent(), &dummy);
+ return;
+ }
+ nsEventStatus status = nsEventStatus_eIgnore;
+ WidgetPointerEvent localEvent(aPointerEvent->IsTrusted(),
+ aIsGotCapture ? ePointerGotCapture :
+ ePointerLostCapture,
+ aPointerEvent->mWidget);
+ localEvent.AssignPointerEventData(*aPointerEvent, true);
+ nsresult rv = shell->HandleEventWithTarget(
+ &localEvent,
+ aCaptureTarget->GetPrimaryFrame(),
+ aCaptureTarget, &status);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "DispatchGotOrLostPointerCaptureEvent failed");
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/events/PointerEventHandler.h
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_PointerEventHandler_h
+#define mozilla_PointerEventHandler_h
+
+#include "mozilla/EventForwards.h"
+
+class nsIFrame;
+class nsIContent;
+
+namespace mozilla {
+
+class PresShell;
+
+class PointerCaptureInfo final
+{
+public:
+ nsCOMPtr<nsIContent> mPendingContent;
+ nsCOMPtr<nsIContent> mOverrideContent;
+
+ explicit PointerCaptureInfo(nsIContent* aPendingContent)
+ : mPendingContent(aPendingContent)
+ {
+ MOZ_COUNT_CTOR(PointerCaptureInfo);
+ }
+
+ ~PointerCaptureInfo()
+ {
+ MOZ_COUNT_DTOR(PointerCaptureInfo);
+ }
+
+ bool Empty()
+ {
+ return !(mPendingContent || mOverrideContent);
+ }
+};
+
+class PointerEventHandler final
+{
+public:
+ // Called in PresShell::Initialize to initialize pointer event related
+ // preferences.
+ static void Initialize();
+
+ // Called in nsLayoutStatics::Initialize/Shutdown to initialize pointer event
+ // related static variables.
+ static void InitializeStatics();
+ static void ReleaseStatics();
+
+ // 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);
+
+ // 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);
+
+ // GetPointerInfo returns true if pointer with aPointerId is situated in
+ // device, false otherwise.
+ // 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);
+
+ static nsIContent* GetPointerCapturingContent(uint32_t aPointerId);
+
+ // Release pointer capture if captured by the specified content or it's
+ // descendant. This is called to handle the case that the pointer capturing
+ // content or it's parent is removed from the document.
+ static void ReleaseIfCaptureByDescendant(nsIContent* aContent);
+
+ /*
+ * This function handles the case when content had called preventDefault on
+ * the active pointer. In that case we have to prevent firing subsequent mouse
+ * to content. We check the flag PointerInfo::mPreventMouseEventByContent and
+ * call PreventDefault(false) to stop default behaviors and stop firing mouse
+ * events to content and chrome.
+ *
+ * note: mouse transition events are excluded
+ * note: we have to clean mPreventMouseEventByContent on pointerup for those
+ * devices support hover
+ * note: we don't suppress firing mouse events to chrome and system group
+ * handlers because they may implement default behaviors
+ */
+ static void PreHandlePointerEventsPreventDefault(
+ WidgetPointerEvent* aPointerEvent,
+ WidgetGUIEvent* aMouseOrTouchEvent);
+
+ /*
+ * This function handles the preventDefault behavior of pointerdown. When user
+ * preventDefault on pointerdown, We have to mark the active pointer to
+ * prevent sebsequent mouse events (except mouse transition events) and
+ * default behaviors.
+ *
+ * We add mPreventMouseEventByContent flag in PointerInfo to represent the
+ * active pointer won't firing compatible mouse events. It's set to true when
+ * content preventDefault on pointerdown
+ */
+ static void PostHandlePointerEventsPreventDefault(
+ WidgetPointerEvent* aPointerEvent,
+ WidgetGUIEvent* aMouseOrTouchEvent);
+
+ static nsresult DispatchPointerFromMouseOrTouch(PresShell* aShell,
+ nsIFrame* aFrame,
+ WidgetGUIEvent* aEvent,
+ bool aDontRetargetEvents,
+ nsEventStatus* aStatus,
+ nsIContent** aTargetContent);
+
+private:
+ // GetPointerType returns pointer type like mouse, pen or touch for pointer
+ // event with pointerId. The return value must be one of
+ // nsIDOMMouseEvent::MOZ_SOURCE_*
+ static uint16_t GetPointerType(uint32_t aPointerId);
+
+ // GetPointerPrimaryState returns state of attribute isPrimary for pointer
+ // event with pointerId
+ static bool GetPointerPrimaryState(uint32_t aPointerId);
+
+ static void DispatchGotOrLostPointerCaptureEvent(
+ bool aIsGotCapture,
+ const WidgetPointerEvent* aPointerEvent,
+ nsIContent* aCaptureTarget);
+};
+
+} // namespace mozilla
+
+#endif // mozilla_PointerEventHandler_h
--- a/dom/events/moz.build
+++ b/dom/events/moz.build
@@ -57,16 +57,17 @@ EXPORTS.mozilla.dom += [
'KeyboardEvent.h',
'MessageEvent.h',
'MouseEvent.h',
'MouseScrollEvent.h',
'MutationEvent.h',
'NotifyPaintEvent.h',
'PaintRequest.h',
'PointerEvent.h',
+ 'PointerEventHandler.h',
'ScrollAreaEvent.h',
'SimpleGestureEvent.h',
'StorageEvent.h',
'TextClause.h',
'Touch.h',
'TouchEvent.h',
'TransitionEvent.h',
'UIEvent.h',
@@ -106,16 +107,17 @@ UNIFIED_SOURCES += [
'KeyboardEvent.cpp',
'MessageEvent.cpp',
'MouseEvent.cpp',
'MouseScrollEvent.cpp',
'MutationEvent.cpp',
'NotifyPaintEvent.cpp',
'PaintRequest.cpp',
'PointerEvent.cpp',
+ 'PointerEventHandler.cpp',
'ScrollAreaEvent.cpp',
'SimpleGestureEvent.cpp',
'StorageEvent.cpp',
'TextClause.cpp',
'TextComposition.cpp',
'Touch.cpp',
'TouchEvent.cpp',
'TransitionEvent.cpp',
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -36,17 +36,17 @@
#include "gfxContext.h"
#include "gfxPrefs.h"
#include "gfxUserFontSet.h"
#include "nsPresContext.h"
#include "nsIContent.h"
#include "nsIContentIterator.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
-#include "mozilla/dom/PointerEvent.h"
+#include "mozilla/dom/PointerEventHandler.h"
#include "nsIDocument.h"
#include "nsAnimationManager.h"
#include "nsNameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
#include "nsFrame.h"
#include "FrameLayerBuilder.h"
#include "nsViewManager.h"
#include "nsView.h"
#include "nsCRTGlue.h"
@@ -210,27 +210,16 @@ using namespace mozilla::layout;
using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
typedef FrameMetrics::ViewID ViewID;
CapturingContentInfo nsIPresShell::gCaptureInfo =
{ false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
false /* mPreventDrag */ };
nsIContent* nsIPresShell::gKeyDownTarget;
-// Keeps a map between pointerId and element that currently capturing pointer
-// with such pointerId. If pointerId is absent in this map then nobody is
-// capturing it. Additionally keep information about pending capturing content.
-static nsClassHashtable<nsUint32HashKey,
- nsIPresShell::PointerCaptureInfo>* sPointerCaptureList;
-
-// Keeps information about pointers such as pointerId, activeState, pointerType,
-// primaryState
-static nsClassHashtable<nsUint32HashKey,
- nsIPresShell::PointerInfo>* sActivePointersIds;
-
// RangePaintInfo is used to paint ranges to offscreen buffers
struct RangePaintInfo {
RefPtr<nsRange> mRange;
nsDisplayListBuilder mBuilder;
nsDisplayList mList;
// offset of builder's reference frame to the root frame
nsPoint mRootOffset;
@@ -707,18 +696,16 @@ nsIPresShell::FrameSelection()
RefPtr<nsFrameSelection> ret = mSelection;
return ret.forget();
}
//----------------------------------------------------------------------
static bool sSynthMouseMove = true;
static uint32_t sNextPresShellId;
-static bool sPointerEventEnabled = true;
-static bool sPointerEventImplicitCapture = false;
static bool sAccessibleCaretEnabled = false;
static bool sAccessibleCaretOnTouch = false;
/* static */ bool
PresShell::AccessibleCaretEnabled(nsIDocShell* aDocShell)
{
static bool initialized = false;
if (!initialized) {
@@ -837,29 +824,17 @@ PresShell::PresShell()
mScrollPositionClampingScrollPortSizeSet = false;
static bool addedSynthMouseMove = false;
if (!addedSynthMouseMove) {
Preferences::AddBoolVarCache(&sSynthMouseMove,
"layout.reflow.synthMouseMove", true);
addedSynthMouseMove = true;
}
- static bool addedPointerEventEnabled = false;
- if (!addedPointerEventEnabled) {
- Preferences::AddBoolVarCache(&sPointerEventEnabled,
- "dom.w3c_pointer_events.enabled", true);
- addedPointerEventEnabled = true;
- }
- static bool addedPointerEventImplicitCapture = false;
- if (!addedPointerEventImplicitCapture) {
- Preferences::AddBoolVarCache(&sPointerEventImplicitCapture,
- "dom.w3c_pointer_events.implicit_capture",
- true);
- addedPointerEventImplicitCapture = true;
- }
+ PointerEventHandler::Initialize();
mPaintingIsFrozen = false;
mHasCSSBackgroundColor = true;
mIsLastChromeOnlyEscapeKeyConsumed = false;
mHasReceivedPaintMessage = false;
}
NS_IMPL_ISUPPORTS(PresShell, nsIPresShell, nsIDocumentObserver,
nsISelectionController,
@@ -4476,25 +4451,17 @@ PresShell::ContentRemoved(nsIDocument *a
// After removing aChild from tree we should save information about live ancestor
if (mPointerEventTarget) {
if (nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
mPointerEventTarget = aMaybeContainer;
}
}
- // We should check that aChild does not contain pointer capturing elements.
- // If it does we should release the pointer capture for the elements.
- for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
- nsIPresShell::PointerCaptureInfo* data = iter.UserData();
- if (data && data->mPendingContent &&
- nsContentUtils::ContentIsDescendantOf(data->mPendingContent, aChild)) {
- nsIPresShell::ReleasePointerCapturingContent(iter.Key());
- }
- }
+ PointerEventHandler::ReleaseIfCaptureByDescendant(aChild);
mFrameConstructor->ContentRemoved(aMaybeContainer, aChild, oldNextSibling,
nsCSSFrameConstructor::REMOVE_CONTENT);
if (aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
MOZ_ASSERT(container == aDocument);
NotifyFontSizeInflationEnabledIsDirty();
}
@@ -6494,168 +6461,16 @@ nsIPresShell::SetCapturingContent(nsICon
// CAPTURE_POINTERLOCK is the same as CAPTURE_RETARGETTOELEMENT & CAPTURE_IGNOREALLOWED
gCaptureInfo.mRetargetToElement = ((aFlags & CAPTURE_RETARGETTOELEMENT) != 0) ||
((aFlags & CAPTURE_POINTERLOCK) != 0);
gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0;
gCaptureInfo.mPointerLock = (aFlags & CAPTURE_POINTERLOCK) != 0;
}
}
-/* static */ void
-nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId,
- nsIContent* aContent)
-{
- MOZ_ASSERT(aContent != nullptr);
-
- if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
- SetCapturingContent(aContent, CAPTURE_PREVENTDRAG);
- }
-
- PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
- if (pointerCaptureInfo) {
- pointerCaptureInfo->mPendingContent = aContent;
- } else {
- sPointerCaptureList->Put(aPointerId, new PointerCaptureInfo(aContent));
- }
-}
-
-/* static */ nsIPresShell::PointerCaptureInfo*
-nsIPresShell::GetPointerCaptureInfo(uint32_t aPointerId)
-{
- PointerCaptureInfo* pointerCaptureInfo = nullptr;
- sPointerCaptureList->Get(aPointerId, &pointerCaptureInfo);
- return pointerCaptureInfo;
-}
-
-/* static */ void
-nsIPresShell::ReleasePointerCapturingContent(uint32_t aPointerId)
-{
- PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
- if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent) {
- if (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == GetPointerType(aPointerId)) {
- SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG);
- }
- pointerCaptureInfo->mPendingContent = nullptr;
- }
-}
-
-/* static */ nsIContent*
-nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId)
-{
- PointerCaptureInfo* pointerCaptureInfo = GetPointerCaptureInfo(aPointerId);
- if (pointerCaptureInfo) {
- return pointerCaptureInfo->mOverrideContent;
- }
- return nullptr;
-}
-
-/* static */ void
-nsIPresShell::CheckPointerCaptureState(const WidgetPointerEvent* aPointerEvent)
-{
- PointerCaptureInfo* captureInfo =
- GetPointerCaptureInfo(aPointerEvent->pointerId);
-
- if (captureInfo &&
- captureInfo->mPendingContent != captureInfo->mOverrideContent) {
- // cache captureInfo->mPendingContent since it may be changed in the pointer
- // event listener
- nsIContent* pendingContent = captureInfo->mPendingContent.get();
- if (captureInfo->mOverrideContent) {
- DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ false,
- aPointerEvent,
- captureInfo->mOverrideContent);
- }
- if (pendingContent) {
- DispatchGotOrLostPointerCaptureEvent(/* aIsGotCapture */ true,
- aPointerEvent, pendingContent);
- }
-
- captureInfo->mOverrideContent = pendingContent;
- if (captureInfo->Empty()) {
- sPointerCaptureList->Remove(aPointerEvent->pointerId);
- }
- }
-}
-
-/* static */ uint16_t
-nsIPresShell::GetPointerType(uint32_t aPointerId)
-{
- PointerInfo* pointerInfo = nullptr;
- if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
- return pointerInfo->mPointerType;
- }
- return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
-}
-
-/* static */ bool
-nsIPresShell::GetPointerPrimaryState(uint32_t aPointerId)
-{
- PointerInfo* pointerInfo = nullptr;
- if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
- return pointerInfo->mPrimaryState;
- }
- return false;
-}
-
-/* static */ bool
-nsIPresShell::GetPointerInfo(uint32_t aPointerId, bool& aActiveState)
-{
- PointerInfo* pointerInfo = nullptr;
- if (sActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
- aActiveState = pointerInfo->mActiveState;
- return true;
- }
- return false;
-}
-
-void
-PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
-{
- 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));
- }
- 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));
- }
- break;
- case ePointerUp:
- // In this case we remove information about pointer or turn off active state
- if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
- if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
- sActivePointersIds->Put(pointerEvent->pointerId,
- new PointerInfo(false,
- pointerEvent->inputSource,
- pointerEvent->mIsPrimary));
- } 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);
- }
- break;
- default:
- break;
- }
-}
-
nsIContent*
PresShell::GetCurrentEventContent()
{
if (mCurrentEventContent &&
mCurrentEventContent->GetComposedDoc() != mDocument) {
mCurrentEventContent = nullptr;
mCurrentEventFrame = nullptr;
}
@@ -6919,200 +6734,16 @@ FlushThrottledStyles(nsIDocument *aDocum
presContext->RestyleManager()->UpdateOnlyAnimationStyles();
}
}
aDocument->EnumerateSubDocuments(FlushThrottledStyles, nullptr);
return true;
}
-/*
- * This function handles the preventDefault behavior of pointerdown. When user
- * preventDefault on pointerdown, We have to mark the active pointer to prevent
- * sebsequent mouse events (except mouse transition events) and default
- * behaviors.
- *
- * We add mPreventMouseEventByContent flag in PointerInfo to represent the
- * active pointer won't firing compatible mouse events. It's set to true when
- * content preventDefault on pointerdown
- */
-static void
-PostHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
- WidgetGUIEvent* aMouseOrTouchEvent)
-{
- if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage != ePointerDown ||
- !aPointerEvent->DefaultPreventedByContent()) {
- return;
- }
- nsIPresShell::PointerInfo* pointerInfo = nullptr;
- if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
- !pointerInfo) {
- // We already added the PointerInfo for active pointer when
- // PresShell::HandleEvent handling pointerdown event.
-#ifdef DEBUG
- MOZ_CRASH("Got ePointerDown w/o active pointer info!!");
-#endif // #ifdef DEBUG
- return;
- }
- // PreventDefault only applied for active pointers.
- if (!pointerInfo->mActiveState) {
- return;
- }
- aMouseOrTouchEvent->PreventDefault(false);
- pointerInfo->mPreventMouseEventByContent = true;
-}
-
-/*
- * This function handles the case when content had called preventDefault on the
- * active pointer. In that case we have to prevent firing subsequent mouse
- * to content. We check the flag PointerInfo::mPreventMouseEventByContent and
- * call PreventDefault(false) to stop default behaviors and stop firing mouse
- * events to content and chrome.
- *
- * note: mouse transition events are excluded
- * note: we have to clean mPreventMouseEventByContent on pointerup for those
- * devices support hover
- * note: we don't suppress firing mouse events to chrome and system group
- * handlers because they may implement default behaviors
- */
-static void
-PreHandlePointerEventsPreventDefault(WidgetPointerEvent* aPointerEvent,
- WidgetGUIEvent* aMouseOrTouchEvent)
-{
- if (!aPointerEvent->mIsPrimary || aPointerEvent->mMessage == ePointerDown) {
- return;
- }
- nsIPresShell::PointerInfo* pointerInfo = nullptr;
- if (!sActivePointersIds->Get(aPointerEvent->pointerId, &pointerInfo) ||
- !pointerInfo) {
- // The PointerInfo for active pointer should be added for normal cases. But
- // in some cases, we may receive mouse events before adding PointerInfo in
- // sActivePointersIds. (e.g. receive mousemove before eMouseEnterIntoWidget
- // or change preference 'dom.w3c_pointer_events.enabled' from off to on).
- // In these cases, we could ignore them because they are not the events
- // between a DefaultPrevented pointerdown and the corresponding pointerup.
- return;
- }
- if (!pointerInfo->mPreventMouseEventByContent) {
- return;
- }
- aMouseOrTouchEvent->PreventDefault(false);
- if (aPointerEvent->mMessage == ePointerUp) {
- pointerInfo->mPreventMouseEventByContent = false;
- }
-}
-
-static nsresult
-DispatchPointerFromMouseOrTouch(PresShell* aShell,
- nsIFrame* aFrame,
- WidgetGUIEvent* aEvent,
- bool aDontRetargetEvents,
- nsEventStatus* aStatus,
- nsIContent** aTargetContent)
-{
- EventMessage pointerMessage = eVoidEvent;
- if (aEvent->mClass == eMouseEventClass) {
- WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
- // 1. If it is not mouse then it is likely will come as touch event
- // 2. We don't synthesize pointer events for those events that are not
- // dispatched to DOM.
- if (!mouseEvent->convertToPointer ||
- !aEvent->IsAllowedToDispatchDOMEvent()) {
- return NS_OK;
- }
- int16_t button = mouseEvent->button;
- switch (mouseEvent->mMessage) {
- case eMouseMove:
- button = WidgetMouseEvent::eNoButton;
- pointerMessage = ePointerMove;
- break;
- case eMouseUp:
- pointerMessage = mouseEvent->buttons ? ePointerMove : ePointerUp;
- break;
- case eMouseDown:
- pointerMessage =
- mouseEvent->buttons & ~nsContentUtils::GetButtonsFlagForButton(button) ?
- ePointerMove : ePointerDown;
- break;
- default:
- return NS_OK;
- }
-
- WidgetPointerEvent event(*mouseEvent);
- event.pointerId = mouseEvent->pointerId;
- event.inputSource = mouseEvent->inputSource;
- event.mMessage = pointerMessage;
- event.button = button;
- event.buttons = mouseEvent->buttons;
- event.pressure = event.buttons ?
- mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
- 0.0f;
- event.convertToPointer = mouseEvent->convertToPointer = false;
- PreHandlePointerEventsPreventDefault(&event, aEvent);
- aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
- aTargetContent);
- PostHandlePointerEventsPreventDefault(&event, aEvent);
- } else if (aEvent->mClass == eTouchEventClass) {
- WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
- int16_t button = WidgetMouseEvent::eLeftButton;
- int16_t buttons = WidgetMouseEvent::eLeftButtonFlag;
- // loop over all touches and dispatch pointer events on each touch
- // copy the event
- switch (touchEvent->mMessage) {
- case eTouchMove:
- pointerMessage = ePointerMove;
- button = WidgetMouseEvent::eNoButton;
- break;
- case eTouchEnd:
- pointerMessage = ePointerUp;
- buttons = WidgetMouseEvent::eNoButtonFlag;
- break;
- case eTouchStart:
- pointerMessage = ePointerDown;
- break;
- case eTouchCancel:
- case eTouchPointerCancel:
- pointerMessage = ePointerCancel;
- break;
- default:
- return NS_OK;
- }
-
- for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
- mozilla::dom::Touch* touch = touchEvent->mTouches[i];
- if (!TouchManager::ShouldConvertTouchToPointer(touch, touchEvent)) {
- continue;
- }
-
- WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
- touchEvent->mWidget);
- event.mIsPrimary = i == 0;
- event.pointerId = touch->Identifier();
- event.mRefPoint = touch->mRefPoint;
- event.mModifiers = touchEvent->mModifiers;
- event.mWidth = touch->RadiusX(CallerType::System);
- event.mHeight = touch->RadiusY(CallerType::System);
- event.tiltX = touch->tiltX;
- event.tiltY = touch->tiltY;
- event.mTime = touchEvent->mTime;
- event.mTimeStamp = touchEvent->mTimeStamp;
- event.mFlags = touchEvent->mFlags;
- event.button = button;
- event.buttons = buttons;
- event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
- event.convertToPointer = touch->convertToPointer = false;
- PreHandlePointerEventsPreventDefault(&event, aEvent);
- aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus,
- aTargetContent);
- PostHandlePointerEventsPreventDefault(&event, aEvent);
- }
- }
- return NS_OK;
-}
-
bool
PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
{
bool rv =
mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
if (aEvent) {
rv &= (aEvent && aEvent->mWidget && !aEvent->mWidget->Destroyed());
}
@@ -7149,22 +6780,22 @@ PresShell::HandleEvent(nsIFrame* aFrame,
// Update the latest focus sequence number with this new sequence number
if (mAPZFocusSequenceNumber < aEvent->mFocusSequenceNumber) {
mAPZFocusSequenceNumber = aEvent->mFocusSequenceNumber;
// Schedule an empty transaction to transmit this focus update
aFrame->SchedulePaint(nsIFrame::PAINT_COMPOSITE_ONLY);
}
- if (sPointerEventEnabled) {
+ if (PointerEventHandler::IsPointerEventEnabled()) {
AutoWeakFrame weakFrame(aFrame);
nsCOMPtr<nsIContent> targetContent;
- DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents,
- aEventStatus,
- getter_AddRefs(targetContent));
+ PointerEventHandler::DispatchPointerFromMouseOrTouch(
+ this, aFrame, aEvent, aDontRetargetEvents,
+ aEventStatus, getter_AddRefs(targetContent));
if (!weakFrame.IsAlive()) {
if (targetContent) {
aFrame = targetContent->GetPrimaryFrame();
if (!aFrame) {
PushCurrentEventInfo(aFrame, targetContent);
nsresult rv = HandleEventInternal(aEvent, aEventStatus, true);
PopCurrentEventInfo();
return rv;
@@ -7204,19 +6835,17 @@ PresShell::HandleEvent(nsIFrame* aFrame,
// If the event is consumed, cancel APZC panning by setting
// mMultipleActionsPrevented.
aEvent->mFlags.mMultipleActionsPrevented = true;
return NS_OK;
}
}
}
- if (sPointerEventEnabled) {
- UpdateActivePointerState(aEvent);
- }
+ PointerEventHandler::UpdateActivePointerState(aEvent);
if (!nsContentUtils::IsSafeToRunScript() &&
aEvent->IsAllowedToDispatchDOMEvent()) {
if (aEvent->mClass == eCompositionEventClass) {
IMEStateManager::OnCompositionEventDiscarded(
aEvent->AsCompositionEvent());
}
#ifdef DEBUG
@@ -7546,53 +7175,53 @@ PresShell::HandleEvent(nsIFrame* aFrame,
NS_ASSERTION(capturingContent->GetComposedDoc() == GetDocument(),
"Unexpected document");
nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame();
if (capturingFrame) {
frame = capturingFrame;
}
}
- if (aEvent->mClass == ePointerEventClass) {
- if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
- // 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.
- CheckPointerCaptureState(pointerEvent);
- // Prevent application crashes, in case damaged frame.
- if (!frameKeeper.IsAlive()) {
- frame = nullptr;
+ if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
+ // 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);
+ // 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();
}
- // Implicit pointer capture for touch
- if (frame && sPointerEventImplicitCapture &&
- 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) {
- SetPointerCapturingContent(pointerEvent->pointerId, targetContent);
- }
+ if (targetContent) {
+ PointerEventHandler::SetPointerCaptureById(pointerEvent->pointerId,
+ targetContent);
}
}
}
// Mouse events should be fired to the same target as their mapped pointer
// events
if ((aEvent->mClass == ePointerEventClass ||
aEvent->mClass == eMouseEventClass) &&
aEvent->mMessage != ePointerDown && aEvent->mMessage != eMouseDown) {
if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
uint32_t pointerId = mouseEvent->pointerId;
nsIContent* pointerCapturingContent =
- GetPointerCapturingContent(pointerId);
+ PointerEventHandler::GetPointerCapturingContent(pointerId);
if (pointerCapturingContent) {
if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) {
frame = capturingFrame;
}
}
}
}
@@ -7685,18 +7314,17 @@ PresShell::HandleEvent(nsIFrame* aFrame,
}
}
}
}
// Before HandlePositionedEvent we should save mPointerEventTarget in some
// cases
AutoWeakFrame weakFrame;
- if (sPointerEventEnabled && aTargetContent &&
- ePointerEventClass == aEvent->mClass) {
+ if (aTargetContent && ePointerEventClass == aEvent->mClass) {
weakFrame = frame;
shell->mPointerEventTarget = frame->GetContent();
MOZ_ASSERT(!frame->GetContent() ||
shell->GetDocument() == frame->GetContent()->OwnerDoc());
}
// Prevent deletion until we're done with event handling (bug 336582) and
// swap mPointerEventTarget to *aTargetContent
@@ -7710,18 +7338,17 @@ PresShell::HandleEvent(nsIFrame* aFrame,
// now ask the subshell to dispatch it normally.
rv = shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
} else {
rv = HandlePositionedEvent(frame, aEvent, aEventStatus);
}
// After HandlePositionedEvent we should reestablish
// content (which still live in tree) in some cases
- if (sPointerEventEnabled && aTargetContent &&
- ePointerEventClass == aEvent->mClass) {
+ if (aTargetContent && ePointerEventClass == aEvent->mClass) {
if (!weakFrame.IsAlive()) {
shell->mPointerEventTarget.swap(*aTargetContent);
}
}
return rv;
}
@@ -8157,18 +7784,18 @@ PresShell::HandleEventInternal(WidgetEve
if (aEvent->mMessage == ePointerUp ||
aEvent->mMessage == ePointerCancel) {
// Implicitly releasing capture for given pointer.
// ePointerLostCapture should be send after ePointerUp or
// ePointerCancel.
WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
MOZ_ASSERT(pointerEvent);
- nsIPresShell::ReleasePointerCapturingContent(pointerEvent->pointerId);
- nsIPresShell::CheckPointerCaptureState(pointerEvent);
+ PointerEventHandler::ReleasePointerCaptureById(pointerEvent->pointerId);
+ PointerEventHandler::CheckPointerCaptureState(pointerEvent);
}
// 3. Give event to event manager for post event state changes and
// generation of synthetic events.
if (!mIsDestroying && NS_SUCCEEDED(rv)) {
rv = manager->PostHandleEvent(mPresContext, aEvent,
GetCurrentEventFrame(), aStatus);
}
@@ -8315,55 +7942,17 @@ PresShell::HandleEventInternal(WidgetEve
sLastInputCreated = aEvent->mTimeStamp;
}
sLastInputProcessed = now;
}
return rv;
}
-/* static */ void
-nsIPresShell::DispatchGotOrLostPointerCaptureEvent(
- bool aIsGotCapture,
- const WidgetPointerEvent* aPointerEvent,
- nsIContent* aCaptureTarget)
-{
- nsIDocument* targetDoc = aCaptureTarget->OwnerDoc();
- nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell();
- NS_ENSURE_TRUE_VOID(shell);
-
- if (!aIsGotCapture && !aCaptureTarget->IsInUncomposedDoc()) {
- // If the capturing element was removed from the DOM tree, fire
- // ePointerLostCapture at the document.
- PointerEventInit init;
- init.mPointerId = aPointerEvent->pointerId;
- init.mBubbles = true;
- init.mComposed = true;
- ConvertPointerTypeToString(aPointerEvent->inputSource, init.mPointerType);
- init.mIsPrimary = aPointerEvent->mIsPrimary;
- RefPtr<mozilla::dom::PointerEvent> event;
- event = PointerEvent::Constructor(aCaptureTarget,
- NS_LITERAL_STRING("lostpointercapture"),
- init);
- bool dummy;
- targetDoc->DispatchEvent(event->InternalDOMEvent(), &dummy);
- return;
- }
- nsEventStatus status = nsEventStatus_eIgnore;
- WidgetPointerEvent localEvent(aPointerEvent->IsTrusted(),
- aIsGotCapture ? ePointerGotCapture :
- ePointerLostCapture,
- aPointerEvent->mWidget);
- localEvent.AssignPointerEventData(*aPointerEvent, true);
- nsresult rv = shell->HandleEventWithTarget(
- &localEvent,
- aCaptureTarget->GetPrimaryFrame(),
- aCaptureTarget, &status);
- NS_ENSURE_SUCCESS_VOID(rv);
-}
+
nsresult
PresShell::DispatchEventToDOM(WidgetEvent* aEvent,
nsEventStatus* aStatus,
nsPresShellEventCB* aEventCB)
{
nsresult rv = NS_OK;
nsCOMPtr<nsINode> eventTarget = mCurrentEventContent.get();
@@ -10882,33 +10471,16 @@ nsIPresShell::IsAccessibilityActive()
nsAccessibilityService*
nsIPresShell::AccService()
{
return GetAccService();
}
#endif
-void nsIPresShell::InitializeStatics()
-{
- MOZ_ASSERT(!sPointerCaptureList, "InitializeStatics called multiple times!");
- sPointerCaptureList =
- new nsClassHashtable<nsUint32HashKey, PointerCaptureInfo>;
- sActivePointersIds = new nsClassHashtable<nsUint32HashKey, PointerInfo>;
-}
-
-void nsIPresShell::ReleaseStatics()
-{
- MOZ_ASSERT(sPointerCaptureList, "ReleaseStatics called without Initialize!");
- delete sPointerCaptureList;
- sPointerCaptureList = nullptr;
- delete sActivePointersIds;
- sActivePointersIds = nullptr;
-}
-
// Asks our docshell whether we're active.
void PresShell::QueryIsActive()
{
nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
if (mDocument) {
nsIDocument* displayDoc = mDocument->GetDisplayDocument();
if (displayDoc) {
// Ok, we're an external resource document -- we need to use our display
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -729,19 +729,16 @@ protected:
virtual void SysColorChanged() override { mPresContext->SysColorChanged(); }
virtual void ThemeChanged() override { mPresContext->ThemeChanged(); }
virtual void BackingScaleFactorChanged() override { mPresContext->UIResolutionChanged(); }
virtual nsIDocument* GetPrimaryContentDocument() override;
virtual void PausePainting() override;
virtual void ResumePainting() override;
- void UpdateActivePointerState(mozilla::WidgetGUIEvent* aEvent);
-
-
//////////////////////////////////////////////////////////////////////////////
// Approximate frame visibility tracking implementation.
//////////////////////////////////////////////////////////////////////////////
void UpdateApproximateFrameVisibility();
void DoUpdateApproximateFrameVisibility(bool aRemoveOnly);
void ClearApproximatelyVisibleFramesList(const Maybe<mozilla::OnNonvisible>& aNonvisibleAction
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1243,86 +1243,16 @@ public:
bool IsActive()
{
return mIsActive;
}
// mouse capturing
static CapturingContentInfo gCaptureInfo;
- class PointerCaptureInfo final
- {
- public:
- nsCOMPtr<nsIContent> mPendingContent;
- nsCOMPtr<nsIContent> mOverrideContent;
-
- explicit PointerCaptureInfo(nsIContent* aPendingContent)
- : mPendingContent(aPendingContent)
- {
- MOZ_COUNT_CTOR(PointerCaptureInfo);
- }
-
- ~PointerCaptureInfo()
- {
- MOZ_COUNT_DTOR(PointerCaptureInfo);
- }
-
- bool Empty()
- {
- return !(mPendingContent || mOverrideContent);
- }
- };
-
- class PointerInfo final
- {
- public:
- uint16_t mPointerType;
- bool mActiveState;
- bool mPrimaryState;
- bool mPreventMouseEventByContent;
- explicit PointerInfo(bool aActiveState, uint16_t aPointerType,
- bool aPrimaryState)
- : mPointerType(aPointerType)
- , mActiveState(aActiveState)
- , mPrimaryState(aPrimaryState)
- , mPreventMouseEventByContent(false)
- {
- }
- };
-
- static void DispatchGotOrLostPointerCaptureEvent(
- bool aIsGotCapture,
- const mozilla::WidgetPointerEvent* aPointerEvent,
- nsIContent* aCaptureTarget);
-
- static PointerCaptureInfo* GetPointerCaptureInfo(uint32_t aPointerId);
- static void SetPointerCapturingContent(uint32_t aPointerId,
- nsIContent* aContent);
- static void ReleasePointerCapturingContent(uint32_t aPointerId);
- static nsIContent* GetPointerCapturingContent(uint32_t aPointerId);
-
- // CheckPointerCaptureState checks cases, when got/lostpointercapture events
- // should be fired.
- static void CheckPointerCaptureState(
- const mozilla::WidgetPointerEvent* aPointerEvent);
-
- // GetPointerInfo returns true if pointer with aPointerId is situated in
- // device, false otherwise.
- // aActiveState is additional information, which shows state of pointer like
- // button state for mouse.
- static bool GetPointerInfo(uint32_t aPointerId, bool& aActiveState);
-
- // GetPointerType returns pointer type like mouse, pen or touch for pointer
- // event with pointerId
- static uint16_t GetPointerType(uint32_t aPointerId);
-
- // GetPointerPrimaryState returns state of attribute isPrimary for pointer
- // event with pointerId
- static bool GetPointerPrimaryState(uint32_t aPointerId);
-
/**
* When capturing content is set, it traps all mouse events and retargets
* them at this content node. If capturing is not allowed
* (gCaptureInfo.mAllowed is false), then capturing is not set. However, if
* the CAPTURE_IGNOREALLOWED flag is set, the allowed state is ignored and
* capturing is set regardless. To disable capture, pass null for the value
* of aContent.
*
@@ -1665,22 +1595,16 @@ public:
bool AddRefreshObserver(nsARefreshObserver* aObserver,
mozilla::FlushType aFlushType);
bool RemoveRefreshObserver(nsARefreshObserver* aObserver,
mozilla::FlushType aFlushType);
virtual bool AddPostRefreshObserver(nsAPostRefreshObserver* aObserver);
virtual bool RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver);
- /**
- * Initialize and shut down static variables.
- */
- static void InitializeStatics();
- static void ReleaseStatics();
-
// If a frame in the subtree rooted at aFrame is capturing the mouse then
// clears that capture.
static void ClearMouseCapture(nsIFrame* aFrame);
void SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight);
bool IsScrollPositionClampingScrollPortSizeSet() {
return mScrollPositionClampingScrollPortSizeSet;
}
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -119,16 +119,17 @@
#include "MediaDecoder.h"
#include "MediaPrefs.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/StaticPresData.h"
#include "mozilla/StylePrefs.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
#include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h"
#include "mozilla/dom/U2FTokenManager.h"
+#include "mozilla/dom/PointerEventHandler.h"
using namespace mozilla;
using namespace mozilla::net;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0;
@@ -254,17 +255,17 @@ nsLayoutStatics::Initialize()
AsyncLatencyLogger::InitializeStatics();
MediaManager::StartupInit();
CubebUtils::InitLibrary();
nsContentSink::InitializeStatics();
nsHtml5Module::InitializeStatics();
mozilla::dom::FallbackEncoding::Initialize();
nsLayoutUtils::Initialize();
- nsIPresShell::InitializeStatics();
+ PointerEventHandler::InitializeStatics();
TouchManager::InitializeStatics();
ContentPrincipal::InitializeStatics();
nsCORSListenerProxy::Startup();
nsWindowMemoryReporter::Init();
SVGElementFactory::Init();
@@ -395,17 +396,17 @@ nsLayoutStatics::Shutdown()
WebAudioUtils::Shutdown();
#ifdef MOZ_WEBSPEECH
nsSynthVoiceRegistry::Shutdown();
#endif
nsCORSListenerProxy::Shutdown();
- nsIPresShell::ReleaseStatics();
+ PointerEventHandler::ReleaseStatics();
TouchManager::ReleaseStatics();
nsTreeSanitizer::ReleaseStatics();
nsHtml5Module::ReleaseStatics();
mozilla::dom::FallbackEncoding::Shutdown();