зеркало из https://github.com/mozilla/gecko-dev.git
Bug 790454 - Find target for touch during touchstart. r=smaug
This commit is contained in:
Родитель
2200a5623c
Коммит
3360f6f087
|
@ -5651,6 +5651,23 @@ AppendToTouchList(const uint32_t& aKey, nsCOMPtr<nsIDOMTouch>& aData, void *aTou
|
||||||
return PL_DHASH_NEXT;
|
return PL_DHASH_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PLDHashOperator
|
||||||
|
FindAnyTarget(const uint32_t& aKey, nsCOMPtr<nsIDOMTouch>& aData,
|
||||||
|
void* aAnyTarget)
|
||||||
|
{
|
||||||
|
if (aData) {
|
||||||
|
nsCOMPtr<nsIDOMEventTarget> target;
|
||||||
|
aData->GetTarget(getter_AddRefs(target));
|
||||||
|
if (target) {
|
||||||
|
nsCOMPtr<nsIContent>* content =
|
||||||
|
static_cast<nsCOMPtr<nsIContent>*>(aAnyTarget);
|
||||||
|
*content = do_QueryInterface(target);
|
||||||
|
return PL_DHASH_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
|
nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
|
||||||
{
|
{
|
||||||
nsIView* view = aPresShell->GetViewManager()->GetRootView();
|
nsIView* view = aPresShell->GetViewManager()->GetRootView();
|
||||||
|
@ -5854,7 +5871,6 @@ PresShell::HandleEvent(nsIFrame *aFrame,
|
||||||
if (!captureRetarget && !isWindowLevelMouseExit) {
|
if (!captureRetarget && !isWindowLevelMouseExit) {
|
||||||
nsPoint eventPoint;
|
nsPoint eventPoint;
|
||||||
if (aEvent->message == NS_TOUCH_START) {
|
if (aEvent->message == NS_TOUCH_START) {
|
||||||
// Add any new touches to the queue
|
|
||||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
||||||
// if there is only one touch in this touchstart event, assume that it is
|
// if there is only one touch in this touchstart event, assume that it is
|
||||||
// the start of a new touch session and evict any old touches in the
|
// the start of a new touch session and evict any old touches in the
|
||||||
|
@ -5866,7 +5882,19 @@ PresShell::HandleEvent(nsIFrame *aFrame,
|
||||||
EvictTouchPoint(touches[i]);
|
EvictTouchPoint(touches[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
|
// if this is a continuing session, ensure that all these events are
|
||||||
|
// in the same document by taking the target of the events already in
|
||||||
|
// the capture list
|
||||||
|
nsCOMPtr<nsIContent> anyTarget;
|
||||||
|
if (gCaptureTouchList.Count() > 0) {
|
||||||
|
gCaptureTouchList.Enumerate(&FindAnyTarget, &anyTarget);
|
||||||
|
} else {
|
||||||
|
gPreventMouseEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any new touches to the queue
|
||||||
|
for (int32_t i = touchEvent->touches.Length(); i; ) {
|
||||||
|
--i;
|
||||||
nsIDOMTouch *touch = touchEvent->touches[i];
|
nsIDOMTouch *touch = touchEvent->touches[i];
|
||||||
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
|
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
|
||||||
touch->mMessage = aEvent->message;
|
touch->mMessage = aEvent->message;
|
||||||
|
@ -5877,9 +5905,59 @@ PresShell::HandleEvent(nsIFrame *aFrame,
|
||||||
// This event is a new touch. Mark it as a changedTouch and
|
// This event is a new touch. Mark it as a changedTouch and
|
||||||
// add it to the queue.
|
// add it to the queue.
|
||||||
touch->mChanged = true;
|
touch->mChanged = true;
|
||||||
gCaptureTouchList.Put(id, touch);
|
|
||||||
|
|
||||||
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touch->mRefPoint, frame);
|
// find the target for this touch
|
||||||
|
uint32_t flags = 0;
|
||||||
|
eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
|
||||||
|
touch->mRefPoint,
|
||||||
|
frame);
|
||||||
|
nsIFrame* target =
|
||||||
|
FindFrameTargetedByInputEvent(aEvent->eventStructType,
|
||||||
|
frame,
|
||||||
|
eventPoint,
|
||||||
|
flags);
|
||||||
|
if (target && !anyTarget) {
|
||||||
|
target->GetContentForEvent(aEvent, getter_AddRefs(anyTarget));
|
||||||
|
while (anyTarget && !anyTarget->IsElement()) {
|
||||||
|
anyTarget = anyTarget->GetParent();
|
||||||
|
}
|
||||||
|
domtouch->SetTarget(anyTarget);
|
||||||
|
gCaptureTouchList.Put(id, touch);
|
||||||
|
} else {
|
||||||
|
nsIFrame* newTargetFrame = nullptr;
|
||||||
|
for (nsIFrame* f = target; f;
|
||||||
|
f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
|
||||||
|
if (f->PresContext()->Document() == anyTarget->OwnerDoc()) {
|
||||||
|
newTargetFrame = f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// We must be in a subdocument so jump directly to the root frame.
|
||||||
|
// GetParentOrPlaceholderForCrossDoc gets called immediately to
|
||||||
|
// jump up to the containing document.
|
||||||
|
f = f->PresContext()->GetPresShell()->GetRootFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we couldn't find a target frame in the same document as
|
||||||
|
// anyTarget, remove the touch from the capture touch list, as
|
||||||
|
// well as the event->touches array. touchmove events that aren't
|
||||||
|
// in the captured touch list will be discarded
|
||||||
|
if (!newTargetFrame) {
|
||||||
|
touchEvent->touches.RemoveElementAt(i);
|
||||||
|
} else {
|
||||||
|
target = newTargetFrame;
|
||||||
|
nsCOMPtr<nsIContent> targetContent;
|
||||||
|
target->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
|
||||||
|
while (targetContent && !targetContent->IsElement()) {
|
||||||
|
targetContent = targetContent->GetParent();
|
||||||
|
}
|
||||||
|
touch->SetTarget(targetContent);
|
||||||
|
gCaptureTouchList.Put(id, touch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
frame = target;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// This touch is an old touch, we need to ensure that is not
|
// This touch is an old touch, we need to ensure that is not
|
||||||
// marked as changed and set its target correctly
|
// marked as changed and set its target correctly
|
||||||
|
@ -5950,47 +6028,6 @@ PresShell::HandleEvent(nsIFrame *aFrame,
|
||||||
PresShell* shell =
|
PresShell* shell =
|
||||||
static_cast<PresShell*>(frame->PresContext()->PresShell());
|
static_cast<PresShell*>(frame->PresContext()->PresShell());
|
||||||
|
|
||||||
switch (aEvent->message) {
|
|
||||||
case NS_TOUCH_MOVE:
|
|
||||||
case NS_TOUCH_CANCEL:
|
|
||||||
case NS_TOUCH_END: {
|
|
||||||
// Remove the changed touches
|
|
||||||
// need to make sure we only remove touches that are ending here
|
|
||||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
|
||||||
nsTArray<nsCOMPtr<nsIDOMTouch> > &touches = touchEvent->touches;
|
|
||||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
|
||||||
nsIDOMTouch *touch = touches[i];
|
|
||||||
if (!touch) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t id;
|
|
||||||
touch->GetIdentifier(&id);
|
|
||||||
nsCOMPtr<nsIDOMTouch> oldTouch;
|
|
||||||
gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
|
|
||||||
if (!oldTouch) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
|
|
||||||
oldTouch->GetTarget(getter_AddRefs(targetPtr));
|
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
|
|
||||||
if (!content) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIFrame* contentFrame = content->GetPrimaryFrame();
|
|
||||||
if (!contentFrame) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
shell = static_cast<PresShell*>(
|
|
||||||
contentFrame->PresContext()->PresShell());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have an active EventStateManager which isn't the
|
// Check if we have an active EventStateManager which isn't the
|
||||||
// EventStateManager of the current PresContext.
|
// EventStateManager of the current PresContext.
|
||||||
// If that is the case, and mouse is over some ancestor document,
|
// If that is the case, and mouse is over some ancestor document,
|
||||||
|
@ -6353,9 +6390,10 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
|
||||||
case NS_TOUCH_MOVE: {
|
case NS_TOUCH_MOVE: {
|
||||||
// Check for touches that changed. Mark them add to queue
|
// Check for touches that changed. Mark them add to queue
|
||||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
||||||
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
|
nsTArray<nsCOMPtr<nsIDOMTouch> >& touches = touchEvent->touches;
|
||||||
bool haveChanged = false;
|
bool haveChanged = false;
|
||||||
for (uint32_t i = 0; i < touches.Length(); ++i) {
|
for (int32_t i = touches.Length(); i; ) {
|
||||||
|
--i;
|
||||||
nsIDOMTouch *touch = touches[i];
|
nsIDOMTouch *touch = touches[i];
|
||||||
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
|
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
|
||||||
if (!touch) {
|
if (!touch) {
|
||||||
|
@ -6368,6 +6406,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
|
||||||
nsCOMPtr<nsIDOMTouch> oldTouch;
|
nsCOMPtr<nsIDOMTouch> oldTouch;
|
||||||
gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
|
gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
|
||||||
if (!oldTouch) {
|
if (!oldTouch) {
|
||||||
|
touches.RemoveElementAt(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(domtouch->Equals(oldTouch)) {
|
if(domtouch->Equals(oldTouch)) {
|
||||||
|
@ -6377,6 +6416,10 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
|
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
|
||||||
oldTouch->GetTarget(getter_AddRefs(targetPtr));
|
oldTouch->GetTarget(getter_AddRefs(targetPtr));
|
||||||
|
if (!targetPtr) {
|
||||||
|
touches.RemoveElementAt(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
domtouch->SetTarget(targetPtr);
|
domtouch->SetTarget(targetPtr);
|
||||||
|
|
||||||
gCaptureTouchList.Put(id, touch);
|
gCaptureTouchList.Put(id, touch);
|
||||||
|
@ -6516,85 +6559,56 @@ PresShell::DispatchTouchEvent(nsEvent *aEvent,
|
||||||
bool preventDefault = false;
|
bool preventDefault = false;
|
||||||
nsEventStatus tmpStatus = nsEventStatus_eIgnore;
|
nsEventStatus tmpStatus = nsEventStatus_eIgnore;
|
||||||
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
|
||||||
// touch events should fire on all targets
|
|
||||||
if (aEvent->message != NS_TOUCH_START) {
|
// loop over all touches and dispatch events on any that have changed
|
||||||
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
|
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
|
||||||
nsIDOMTouch *touch = touchEvent->touches[i];
|
nsIDOMTouch *touch = touchEvent->touches[i];
|
||||||
if (!touch || !touch->mChanged) {
|
if (!touch || !touch->mChanged) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// copy the event
|
|
||||||
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
|
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
|
||||||
touch->GetTarget(getter_AddRefs(targetPtr));
|
touch->GetTarget(getter_AddRefs(targetPtr));
|
||||||
if (!targetPtr) {
|
nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr);
|
||||||
|
if (!content) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIContent* capturingContent = GetCapturingContent();
|
||||||
|
if (capturingContent) {
|
||||||
|
if (capturingContent->OwnerDoc() != content->OwnerDoc()) {
|
||||||
|
// Wrong document, don't dispatch anything.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
content = capturingContent;
|
||||||
|
}
|
||||||
|
// copy the event
|
||||||
|
nsTouchEvent newEvent(NS_IS_TRUSTED_EVENT(touchEvent) ?
|
||||||
|
true : false,
|
||||||
|
touchEvent);
|
||||||
|
newEvent.target = targetPtr;
|
||||||
|
|
||||||
nsTouchEvent newEvent(NS_IS_TRUSTED_EVENT(touchEvent) ?
|
nsRefPtr<PresShell> contentPresShell;
|
||||||
true : false,
|
if (content->OwnerDoc() == mDocument) {
|
||||||
touchEvent);
|
contentPresShell = static_cast<PresShell*>
|
||||||
newEvent.target = targetPtr;
|
(content->OwnerDoc()->GetShell());
|
||||||
|
|
||||||
// If someone is capturing, all touch events are filtered to their target
|
|
||||||
nsCOMPtr<nsIContent> content = GetCapturingContent();
|
|
||||||
|
|
||||||
// if no one is capturing, set the capturing target
|
|
||||||
if (!content) {
|
|
||||||
content = do_QueryInterface(targetPtr);
|
|
||||||
}
|
|
||||||
nsRefPtr<PresShell> contentPresShell;
|
|
||||||
if (content && content->OwnerDoc() == mDocument) {
|
|
||||||
contentPresShell = static_cast<PresShell*>
|
|
||||||
(content->OwnerDoc()->GetShell());
|
|
||||||
if (contentPresShell) {
|
|
||||||
contentPresShell->PushCurrentEventInfo(
|
|
||||||
content->GetPrimaryFrame(), content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nsPresContext *context = nsContentUtils::GetContextForContent(content);
|
|
||||||
if (!context) {
|
|
||||||
context = mPresContext;
|
|
||||||
}
|
|
||||||
tmpStatus = nsEventStatus_eIgnore;
|
|
||||||
nsEventDispatcher::Dispatch(targetPtr, context,
|
|
||||||
&newEvent, nullptr, &tmpStatus, aEventCB);
|
|
||||||
if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
|
|
||||||
preventDefault = true;
|
|
||||||
}
|
|
||||||
if (contentPresShell) {
|
if (contentPresShell) {
|
||||||
contentPresShell->PopCurrentEventInfo();
|
//XXXsmaug huge hack. Pushing possibly capturing content,
|
||||||
}
|
// even though event target is something else.
|
||||||
}
|
contentPresShell->PushCurrentEventInfo(
|
||||||
} else {
|
content->GetPrimaryFrame(), content);
|
||||||
// touchevents need to have the target attribute set on each touch
|
|
||||||
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
|
|
||||||
nsIDOMTouch *touch = touchEvent->touches[i];
|
|
||||||
if (touch->mChanged) {
|
|
||||||
touch->SetTarget(mCurrentEventContent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mCurrentEventContent) {
|
|
||||||
nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext,
|
|
||||||
aEvent, nullptr, &tmpStatus, aEventCB);
|
|
||||||
} else {
|
|
||||||
nsCOMPtr<nsIContent> targetContent;
|
|
||||||
rv = mCurrentEventFrame->GetContentForEvent(aEvent,
|
|
||||||
getter_AddRefs(targetContent));
|
|
||||||
if (NS_SUCCEEDED(rv) && targetContent) {
|
|
||||||
nsEventDispatcher::Dispatch(targetContent, mPresContext, aEvent,
|
|
||||||
nullptr, &tmpStatus, aEventCB);
|
|
||||||
} else if (mDocument) {
|
|
||||||
nsEventDispatcher::Dispatch(mDocument, mPresContext, aEvent,
|
|
||||||
nullptr, &tmpStatus, nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nsPresContext *context = nsContentUtils::GetContextForContent(content);
|
||||||
|
tmpStatus = nsEventStatus_eIgnore;
|
||||||
|
nsEventDispatcher::Dispatch(targetPtr, context,
|
||||||
|
&newEvent, nullptr, &tmpStatus, aEventCB);
|
||||||
if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
|
if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
|
||||||
preventDefault = true;
|
preventDefault = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (touchEvent->touches.Length() == 1) {
|
if (contentPresShell) {
|
||||||
gPreventMouseEvents = false;
|
contentPresShell->PopCurrentEventInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче