mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
Bug 967796 - Implement Pointer Enter/Leave events support. implementation for pointer's. r=smaug
This commit is contained in:
parent
f627a1c40d
commit
f82bb788b2
@ -701,7 +701,9 @@ nsIContent::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
||||
// inside chrome access only content.
|
||||
bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
|
||||
if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
|
||||
aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
|
||||
aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH ||
|
||||
aVisitor.mEvent->message == NS_POINTER_OVER ||
|
||||
aVisitor.mEvent->message == NS_POINTER_OUT) &&
|
||||
// Check if we should stop event propagation when event has just been
|
||||
// dispatched or when we're about to propagate from
|
||||
// chrome access only subtree.
|
||||
|
@ -1111,7 +1111,8 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
aEvent->message = 0;
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_MOVE: {
|
||||
case NS_MOUSE_MOVE:
|
||||
case NS_POINTER_MOVE: {
|
||||
// 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
|
||||
@ -3378,6 +3379,16 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
SetActiveManager(this, activeContent);
|
||||
}
|
||||
break;
|
||||
case NS_POINTER_CANCEL:
|
||||
case NS_POINTER_UP: {
|
||||
WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
|
||||
// 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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NS_MOUSE_BUTTON_UP:
|
||||
{
|
||||
ClearGlobalActiveContent(this);
|
||||
@ -3753,6 +3764,7 @@ nsEventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
|
||||
// as if the new presentation is resized, a new element may be hovered.
|
||||
SetContentState(nullptr, NS_EVENT_STATE_HOVER);
|
||||
}
|
||||
mPointersEnterLeaveHelper.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
@ -4042,10 +4054,10 @@ nsEventStateManager::IsHandlingUserInput()
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsEventStateManager::DispatchMouseEvent(WidgetMouseEvent* aMouseEvent,
|
||||
uint32_t aMessage,
|
||||
nsIContent* aTargetContent,
|
||||
nsIContent* aRelatedContent)
|
||||
nsEventStateManager::DispatchMouseOrPointerEvent(WidgetMouseEvent* aMouseEvent,
|
||||
uint32_t aMessage,
|
||||
nsIContent* aTargetContent,
|
||||
nsIContent* aRelatedContent)
|
||||
{
|
||||
// http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
|
||||
// "[When the mouse is locked on an element...e]vents that require the concept
|
||||
@ -4066,16 +4078,35 @@ nsEventStateManager::DispatchMouseEvent(WidgetMouseEvent* aMouseEvent,
|
||||
return mPresContext->GetPrimaryFrameFor(content);
|
||||
}
|
||||
|
||||
PROFILER_LABEL("Input", "DispatchMouseEvent");
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetMouseEvent event(aMouseEvent->mFlags.mIsTrusted, aMessage,
|
||||
aMouseEvent->widget, WidgetMouseEvent::eReal);
|
||||
event.refPoint = aMouseEvent->refPoint;
|
||||
event.modifiers = aMouseEvent->modifiers;
|
||||
event.buttons = aMouseEvent->buttons;
|
||||
event.pluginEvent = aMouseEvent->pluginEvent;
|
||||
event.relatedTarget = aRelatedContent;
|
||||
event.inputSource = aMouseEvent->inputSource;
|
||||
nsAutoPtr<WidgetPointerEvent> newPointerEvent;
|
||||
nsAutoPtr<WidgetMouseEvent> newMouseEvent;
|
||||
WidgetMouseEvent* event = nullptr;
|
||||
WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
|
||||
if (sourcePointer) {
|
||||
PROFILER_LABEL("Input", "DispatchPointerEvent");
|
||||
newPointerEvent =
|
||||
new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
|
||||
aMouseEvent->widget);
|
||||
newPointerEvent->isPrimary = sourcePointer->isPrimary;
|
||||
newPointerEvent->pointerId = sourcePointer->pointerId;
|
||||
newPointerEvent->width = sourcePointer->width;
|
||||
newPointerEvent->height = sourcePointer->height;
|
||||
newPointerEvent->inputSource = sourcePointer->inputSource;
|
||||
event = newPointerEvent.get();
|
||||
} else {
|
||||
PROFILER_LABEL("Input", "DispatchMouseEvent");
|
||||
newMouseEvent =
|
||||
new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
|
||||
aMouseEvent->widget, WidgetMouseEvent::eReal);
|
||||
event = newMouseEvent.get();
|
||||
}
|
||||
event->refPoint = aMouseEvent->refPoint;
|
||||
event->modifiers = aMouseEvent->modifiers;
|
||||
event->buttons = aMouseEvent->buttons;
|
||||
event->pluginEvent = aMouseEvent->pluginEvent;
|
||||
event->relatedTarget = aRelatedContent;
|
||||
event->inputSource = aMouseEvent->inputSource;
|
||||
|
||||
nsWeakFrame previousTarget = mCurrentTarget;
|
||||
|
||||
@ -4084,7 +4115,7 @@ nsEventStateManager::DispatchMouseEvent(WidgetMouseEvent* aMouseEvent,
|
||||
nsIFrame* targetFrame = nullptr;
|
||||
if (aTargetContent) {
|
||||
nsESMEventCB callback(aTargetContent);
|
||||
nsEventDispatcher::Dispatch(aTargetContent, mPresContext, &event, nullptr,
|
||||
nsEventDispatcher::Dispatch(aTargetContent, mPresContext, event, nullptr,
|
||||
&status, &callback);
|
||||
|
||||
// Although the primary frame was checked in event callback,
|
||||
@ -4101,17 +4132,18 @@ nsEventStateManager::DispatchMouseEvent(WidgetMouseEvent* aMouseEvent,
|
||||
return targetFrame;
|
||||
}
|
||||
|
||||
class MouseEnterLeaveDispatcher
|
||||
class EnterLeaveDispatcher
|
||||
{
|
||||
public:
|
||||
MouseEnterLeaveDispatcher(nsEventStateManager* aESM,
|
||||
nsIContent* aTarget, nsIContent* aRelatedTarget,
|
||||
WidgetMouseEvent* aMouseEvent, uint32_t aType)
|
||||
EnterLeaveDispatcher(nsEventStateManager* aESM,
|
||||
nsIContent* aTarget, nsIContent* aRelatedTarget,
|
||||
WidgetMouseEvent* aMouseEvent, uint32_t aType)
|
||||
: mESM(aESM), mMouseEvent(aMouseEvent), mType(aType)
|
||||
{
|
||||
nsPIDOMWindow* win =
|
||||
aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
|
||||
if (win && win->HasMouseEnterLeaveEventListeners()) {
|
||||
if (aMouseEvent->AsPointerEvent() ? win && win->HasPointerEnterLeaveEventListeners() :
|
||||
win && win->HasMouseEnterLeaveEventListeners()) {
|
||||
mRelatedTarget = aRelatedTarget ?
|
||||
aRelatedTarget->FindFirstNonChromeOnlyAccessContent() : nullptr;
|
||||
nsINode* commonParent = nullptr;
|
||||
@ -4131,17 +4163,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
~MouseEnterLeaveDispatcher()
|
||||
~EnterLeaveDispatcher()
|
||||
{
|
||||
if (mType == NS_MOUSEENTER) {
|
||||
if (mType == NS_MOUSEENTER ||
|
||||
mType == NS_POINTER_ENTER) {
|
||||
for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
|
||||
mESM->DispatchMouseEvent(mMouseEvent, mType, mTargets[i],
|
||||
mRelatedTarget);
|
||||
mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i],
|
||||
mRelatedTarget);
|
||||
}
|
||||
} else {
|
||||
for (int32_t i = 0; i < mTargets.Count(); ++i) {
|
||||
mESM->DispatchMouseEvent(mMouseEvent, mType, mTargets[i],
|
||||
mRelatedTarget);
|
||||
mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i],
|
||||
mRelatedTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4197,17 +4230,20 @@ nsEventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
|
||||
// hover state itself, and we have optimizations for hover switching between
|
||||
// two nearby elements both deep in the DOM tree that would be defeated by
|
||||
// switching the hover state to null here.
|
||||
if (!aMovingInto) {
|
||||
bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
|
||||
if (!aMovingInto && !isPointer) {
|
||||
// Unset :hover
|
||||
SetContentState(nullptr, NS_EVENT_STATE_HOVER);
|
||||
}
|
||||
|
||||
MouseEnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement, aMovingInto,
|
||||
aMouseEvent, NS_MOUSELEAVE);
|
||||
EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
|
||||
aMovingInto, aMouseEvent,
|
||||
isPointer ? NS_POINTER_LEAVE :
|
||||
NS_MOUSELEAVE);
|
||||
|
||||
// Fire mouseout
|
||||
DispatchMouseEvent(aMouseEvent, NS_MOUSE_EXIT_SYNTH,
|
||||
wrapper->mLastOverElement, aMovingInto);
|
||||
DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : NS_MOUSE_EXIT_SYNTH,
|
||||
wrapper->mLastOverElement, aMovingInto);
|
||||
|
||||
wrapper->mLastOverFrame = nullptr;
|
||||
wrapper->mLastOverElement = nullptr;
|
||||
@ -4252,11 +4288,14 @@ nsEventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
return;
|
||||
|
||||
// Remember mLastOverElement as the related content for the
|
||||
// DispatchMouseEvent() call below, since NotifyMouseOut() resets it, bug 298477.
|
||||
// DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
|
||||
nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
|
||||
|
||||
MouseEnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
|
||||
aMouseEvent, NS_MOUSEENTER);
|
||||
bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
|
||||
EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
|
||||
aMouseEvent,
|
||||
isPointer ? NS_POINTER_ENTER :
|
||||
NS_MOUSEENTER);
|
||||
|
||||
NotifyMouseOut(aMouseEvent, aContent);
|
||||
|
||||
@ -4264,11 +4303,16 @@ nsEventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
// to that element while the first mouseOver is still ongoing.
|
||||
wrapper->mFirstOverEventElement = aContent;
|
||||
|
||||
SetContentState(aContent, NS_EVENT_STATE_HOVER);
|
||||
if (!isPointer) {
|
||||
SetContentState(aContent, NS_EVENT_STATE_HOVER);
|
||||
}
|
||||
|
||||
// Fire mouseover
|
||||
wrapper->mLastOverFrame = DispatchMouseEvent(aMouseEvent, NS_MOUSE_ENTER_SYNTH,
|
||||
aContent, lastOverElement);
|
||||
wrapper->mLastOverFrame =
|
||||
DispatchMouseOrPointerEvent(aMouseEvent,
|
||||
isPointer ? NS_POINTER_OVER :
|
||||
NS_MOUSE_ENTER_SYNTH,
|
||||
aContent, lastOverElement);
|
||||
wrapper->mLastOverElement = aContent;
|
||||
|
||||
// Turn recursion protection back off
|
||||
@ -4376,6 +4420,9 @@ nsEventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
|
||||
// Update the last known refPoint with the current refPoint.
|
||||
sLastRefPoint = aMouseEvent->refPoint;
|
||||
|
||||
}
|
||||
case NS_POINTER_MOVE:
|
||||
{
|
||||
// Get the target content target (mousemove target == mouseover target)
|
||||
nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
|
||||
if (!targetElement) {
|
||||
@ -4389,17 +4436,18 @@ nsEventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_POINTER_LEAVE:
|
||||
case NS_MOUSE_EXIT:
|
||||
{
|
||||
// This is actually the window mouse exit event. We're not moving
|
||||
// This is actually the window mouse exit or pointer leave event. We're not moving
|
||||
// into any new element.
|
||||
|
||||
OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
|
||||
if (helper->mLastOverFrame &&
|
||||
nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
|
||||
nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
|
||||
// the MouseOut event widget doesn't have same top widget with
|
||||
// mLastMouseOverFrame, it's a spurious event for mLastMouseOverFrame
|
||||
// the Mouse/PointerOut event widget doesn't have same top widget with
|
||||
// mLastOverFrame, it's a spurious event for mLastOverFrame
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4419,10 +4467,21 @@ nsEventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
|
||||
OverOutElementsWrapper*
|
||||
nsEventStateManager::GetWrapperByEventID(WidgetMouseEvent* aEvent)
|
||||
{
|
||||
if (!mMouseEnterLeaveHelper) {
|
||||
mMouseEnterLeaveHelper = new OverOutElementsWrapper();
|
||||
WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
|
||||
if (!pointer) {
|
||||
MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr);
|
||||
if (!mMouseEnterLeaveHelper) {
|
||||
mMouseEnterLeaveHelper = new OverOutElementsWrapper();
|
||||
}
|
||||
return mMouseEnterLeaveHelper;
|
||||
}
|
||||
return mMouseEnterLeaveHelper.get();
|
||||
nsRefPtr<OverOutElementsWrapper> helper;
|
||||
if (!mPointersEnterLeaveHelper.Get(pointer->pointerId, getter_AddRefs(helper))) {
|
||||
helper = new OverOutElementsWrapper();
|
||||
mPointersEnterLeaveHelper.Put(pointer->pointerId, helper);
|
||||
}
|
||||
|
||||
return helper;
|
||||
}
|
||||
|
||||
void
|
||||
@ -5135,6 +5194,7 @@ nsEventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent
|
||||
|
||||
// See bug 292146 for why we want to null this out
|
||||
ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
|
||||
mPointersEnterLeaveHelper.Enumerate(&nsEventStateManager::ResetLastOverForContent, aContent);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -25,7 +25,7 @@ class nsIDocShell;
|
||||
class nsIDocShellTreeItem;
|
||||
class imgIContainer;
|
||||
class nsDOMDataTransfer;
|
||||
class MouseEnterLeaveDispatcher;
|
||||
class EnterLeaveDispatcher;
|
||||
class nsIMarkupDocumentViewer;
|
||||
class nsIScrollableFrame;
|
||||
class nsITimer;
|
||||
@ -234,7 +234,7 @@ public:
|
||||
static nsWeakPtr sPointerLockedDoc;
|
||||
|
||||
protected:
|
||||
friend class MouseEnterLeaveDispatcher;
|
||||
friend class EnterLeaveDispatcher;
|
||||
|
||||
/**
|
||||
* Prefs class capsules preference management.
|
||||
@ -272,14 +272,14 @@ protected:
|
||||
nsIFrame* aTargetFrame,
|
||||
nsEventStatus* aStatus);
|
||||
/**
|
||||
* Turn a GUI mouse event into a mouse event targeted at the specified
|
||||
* Turn a GUI mouse/pointer event into a mouse/pointer event targeted at the specified
|
||||
* content. This returns the primary frame for the content (or null
|
||||
* if it goes away during the event).
|
||||
*/
|
||||
nsIFrame* DispatchMouseEvent(mozilla::WidgetMouseEvent* aMouseEvent,
|
||||
uint32_t aMessage,
|
||||
nsIContent* aTargetContent,
|
||||
nsIContent* aRelatedContent);
|
||||
nsIFrame* DispatchMouseOrPointerEvent(mozilla::WidgetMouseEvent* aMouseEvent,
|
||||
uint32_t aMessage,
|
||||
nsIContent* aTargetContent,
|
||||
nsIContent* aRelatedContent);
|
||||
/**
|
||||
* Synthesize DOM and frame mouseover and mouseout events from this
|
||||
* MOUSE_MOVE or MOUSE_EXIT event.
|
||||
|
@ -536,6 +536,7 @@ public:
|
||||
, tiltY(0)
|
||||
, isPrimary(true)
|
||||
{
|
||||
UpdateFlags();
|
||||
}
|
||||
|
||||
WidgetPointerEvent(const WidgetMouseEvent& aEvent)
|
||||
@ -548,6 +549,19 @@ public:
|
||||
, isPrimary(true)
|
||||
{
|
||||
eventStructType = NS_POINTER_EVENT;
|
||||
UpdateFlags();
|
||||
}
|
||||
|
||||
void UpdateFlags()
|
||||
{
|
||||
switch (message) {
|
||||
case NS_POINTER_ENTER:
|
||||
case NS_POINTER_LEAVE:
|
||||
mFlags.mBubbles = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
|
||||
|
Loading…
Reference in New Issue
Block a user