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;
}
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)
{
nsIView* view = aPresShell->GetViewManager()->GetRootView();
@ -5855,7 +5872,6 @@ PresShell::HandleEvent(nsIFrame *aFrame,
if (!captureRetarget && !isWindowLevelMouseExit) {
nsPoint eventPoint;
if (aEvent->message == NS_TOUCH_START) {
// Add any new touches to the queue
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
// 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
@ -5867,7 +5883,19 @@ PresShell::HandleEvent(nsIFrame *aFrame,
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];
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
touch->mMessage = aEvent->message;
@ -5878,9 +5906,58 @@ PresShell::HandleEvent(nsIFrame *aFrame,
// This event is a new touch. Mark it as a changedTouch and
// add it to the queue.
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 {
// This touch is an old touch, we need to ensure that is not
// marked as changed and set its target correctly
@ -5950,13 +6027,11 @@ PresShell::HandleEvent(nsIFrame *aFrame,
PresShell* shell =
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
// get the correct shell to dispatch to
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
nsTArray<nsCOMPtr<nsIDOMTouch> > &touches = touchEvent->touches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
@ -5987,6 +6062,9 @@ PresShell::HandleEvent(nsIFrame *aFrame,
shell = static_cast<PresShell*>(
contentFrame->PresContext()->PresShell());
if (shell) {
break;
}
}
break;
}
@ -6354,9 +6432,10 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
case NS_TOUCH_MOVE: {
// Check for touches that changed. Mark them add to queue
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
nsTArray<nsCOMPtr<nsIDOMTouch> >& touches = touchEvent->touches;
bool haveChanged = false;
for (uint32_t i = 0; i < touches.Length(); ++i) {
for (int32_t i = touches.Length(); i; ) {
--i;
nsIDOMTouch *touch = touches[i];
nsDOMTouch *domtouch = static_cast<nsDOMTouch*>(touch);
if (!touch) {
@ -6369,6 +6448,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
nsCOMPtr<nsIDOMTouch> oldTouch;
gCaptureTouchList.Get(id, getter_AddRefs(oldTouch));
if (!oldTouch) {
touches.RemoveElementAt(i);
continue;
}
if(domtouch->Equals(oldTouch)) {
@ -6378,6 +6458,10 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsEventStatus* aStatus)
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
oldTouch->GetTarget(getter_AddRefs(targetPtr));
if (!targetPtr) {
touches.RemoveElementAt(i);
continue;
}
domtouch->SetTarget(targetPtr);
gCaptureTouchList.Put(id, touch);
@ -6509,7 +6593,6 @@ PresShell::DispatchTouchEvent(nsEvent *aEvent,
nsPresShellEventCB* aEventCB,
bool aTouchIsNew)
{
nsresult rv = NS_OK;
// calling preventDefault on touchstart or the first touchmove for a
// point prevents mouse events
bool canPrevent = aEvent->message == NS_TOUCH_START ||
@ -6517,85 +6600,63 @@ PresShell::DispatchTouchEvent(nsEvent *aEvent,
bool preventDefault = false;
nsEventStatus tmpStatus = nsEventStatus_eIgnore;
nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
// touch events should fire on all targets
if (aEvent->message != NS_TOUCH_START) {
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
nsIDOMTouch *touch = touchEvent->touches[i];
if (!touch || !touch->mChanged) {
continue;
}
// copy the event
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
touch->GetTarget(getter_AddRefs(targetPtr));
if (!targetPtr) {
// loop over all touches and dispatch events on any that have changed
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
nsIDOMTouch *touch = touchEvent->touches[i];
if (!touch || !touch->mChanged) {
continue;
}
nsCOMPtr<nsPIDOMEventTarget> targetPtr;
touch->GetTarget(getter_AddRefs(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;
}
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) ?
true : false,
touchEvent);
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;
}
nsRefPtr<PresShell> contentPresShell;
if (doc == mDocument) {
contentPresShell = static_cast<PresShell*>(doc->GetShell());
if (contentPresShell) {
contentPresShell->PopCurrentEventInfo();
}
}
} else {
// 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);
//XXXsmaug huge hack. Pushing possibly capturing content,
// even though event target is something else.
contentPresShell->PushCurrentEventInfo(
content->GetPrimaryFrame(), content);
}
}
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);
}
nsIPresShell *presShell = doc->GetShell();
if (!presShell) {
continue;
}
nsPresContext *context = presShell->GetPresContext();
tmpStatus = nsEventStatus_eIgnore;
nsEventDispatcher::Dispatch(targetPtr, context,
&newEvent, nullptr, &tmpStatus, aEventCB);
if (nsEventStatus_eConsumeNoDefault == tmpStatus) {
preventDefault = true;
}
if (touchEvent->touches.Length() == 1) {
gPreventMouseEvents = false;
if (contentPresShell) {
contentPresShell->PopCurrentEventInfo();
}
}

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

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