Bug 790454 - Set touch target in touchstart. r=smaug

This commit is contained in:
Wes Johnston 2012-11-02 12:59:20 -07:00
Родитель a53da3dcf1
Коммит f923e97685
2 изменённых файлов: 138 добавлений и 80 удалений

Просмотреть файл

@ -5652,6 +5652,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();
@ -5855,7 +5872,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
@ -5867,7 +5883,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;
@ -5878,9 +5906,58 @@ 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,13 +6027,11 @@ PresShell::HandleEvent(nsIFrame *aFrame,
PresShell* shell = PresShell* shell =
static_cast<PresShell*>(frame->PresContext()->PresShell()); static_cast<PresShell*>(frame->PresContext()->PresShell());
switch (aEvent->message) { switch (aEvent->message) {
case NS_TOUCH_MOVE: case NS_TOUCH_MOVE:
case NS_TOUCH_CANCEL: case NS_TOUCH_CANCEL:
case NS_TOUCH_END: { case NS_TOUCH_END: {
// Remove the changed touches // get the correct shell to dispatch to
// need to make sure we only remove touches that are ending here
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent); nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
nsTArray<nsCOMPtr<nsIDOMTouch> > &touches = touchEvent->touches; nsTArray<nsCOMPtr<nsIDOMTouch> > &touches = touchEvent->touches;
for (uint32_t i = 0; i < touches.Length(); ++i) { for (uint32_t i = 0; i < touches.Length(); ++i) {
@ -5987,6 +6062,9 @@ PresShell::HandleEvent(nsIFrame *aFrame,
shell = static_cast<PresShell*>( shell = static_cast<PresShell*>(
contentFrame->PresContext()->PresShell()); contentFrame->PresContext()->PresShell());
if (shell) {
break;
}
} }
break; break;
} }
@ -6354,9 +6432,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) {
@ -6369,6 +6448,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)) {
@ -6378,6 +6458,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);
@ -6509,7 +6593,6 @@ PresShell::DispatchTouchEvent(nsEvent *aEvent,
nsPresShellEventCB* aEventCB, nsPresShellEventCB* aEventCB,
bool aTouchIsNew) bool aTouchIsNew)
{ {
nsresult rv = NS_OK;
// calling preventDefault on touchstart or the first touchmove for a // calling preventDefault on touchstart or the first touchmove for a
// point prevents mouse events // point prevents mouse events
bool canPrevent = aEvent->message == NS_TOUCH_START || bool canPrevent = aEvent->message == NS_TOUCH_START ||
@ -6517,85 +6600,63 @@ 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;
}
nsIDocument* doc = content->OwnerDoc();
nsIContent* capturingContent = GetCapturingContent();
if (capturingContent) {
if (capturingContent->OwnerDoc() != doc) {
// 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 (doc == mDocument) {
touchEvent); contentPresShell = static_cast<PresShell*>(doc->GetShell());
newEvent.target = targetPtr;
// 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) { nsIPresShell *presShell = doc->GetShell();
nsEventDispatcher::Dispatch(mCurrentEventContent, mPresContext, if (!presShell) {
aEvent, nullptr, &tmpStatus, aEventCB); continue;
} 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 = presShell->GetPresContext();
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();
} }
} }

Просмотреть файл

@ -530,7 +530,6 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext,
static_cast<nsMouseEvent*>(aEvent)->button == static_cast<nsMouseEvent*>(aEvent)->button ==
nsMouseEvent::eMiddleButton) || nsMouseEvent::eMiddleButton) ||
(aEvent->message == NS_TOUCH_START && GetScrollToClick())) { (aEvent->message == NS_TOUCH_START && GetScrollToClick())) {
nsPoint eventPoint; nsPoint eventPoint;
if (!GetEventPoint(aEvent, eventPoint)) { if (!GetEventPoint(aEvent, eventPoint)) {
return NS_OK; return NS_OK;
@ -850,7 +849,6 @@ nsSliderFrame::StartDrag(nsIDOMEvent* aEvent)
#ifdef DEBUG_SLIDER #ifdef DEBUG_SLIDER
printf("Begin dragging\n"); printf("Begin dragging\n");
#endif #endif
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
nsGkAtoms::_true, eCaseMatters)) nsGkAtoms::_true, eCaseMatters))
return NS_OK; return NS_OK;
@ -988,7 +986,6 @@ nsSliderFrame::HandlePress(nsPresContext* aPresContext,
nsEventStatus* aEventStatus) nsEventStatus* aEventStatus)
{ {
if (aEvent->message == NS_TOUCH_START && GetScrollToClick()) { if (aEvent->message == NS_TOUCH_START && GetScrollToClick()) {
printf("Bailing for touch\n");
return NS_OK; return NS_OK;
} }