Bug 1133492 - Extract some of nsPresShell into a separate TouchManager class. r=smaug

This commit is contained in:
Maksim Lebedev
2015-02-20 02:12:00 -05:00
parent ab1e214700
commit ce6cdec278
5 changed files with 261 additions and 175 deletions

View File

@@ -975,6 +975,8 @@ PresShell::Init(nsIDocument* aDocument,
// Setup our font inflation preferences.
SetupFontInflation();
mTouchManager.Init(this, mDocument);
}
#ifdef PR_LOGGING
@@ -1277,7 +1279,7 @@ PresShell::Destroy()
mHaveShutDown = true;
EvictTouches();
mTouchManager.Destroy();
}
void
@@ -6804,60 +6806,6 @@ PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent)
}
}
static void
EvictTouchPoint(nsRefPtr<dom::Touch>& aTouch,
nsIDocument* aLimitToDocument = nullptr)
{
nsCOMPtr<nsINode> node(do_QueryInterface(aTouch->mTarget));
if (node) {
nsIDocument* doc = node->GetCurrentDoc();
if (doc && (!aLimitToDocument || aLimitToDocument == doc)) {
nsIPresShell* presShell = doc->GetShell();
if (presShell) {
nsIFrame* frame = presShell->GetRootFrame();
if (frame) {
nsPoint pt(aTouch->mRefPoint.x, aTouch->mRefPoint.y);
nsCOMPtr<nsIWidget> widget = frame->GetView()->GetNearestWidget(&pt);
if (widget) {
WidgetTouchEvent event(true, NS_TOUCH_END, widget);
event.widget = widget;
event.time = PR_IntervalNow();
event.touches.AppendElement(aTouch);
nsEventStatus status;
widget->DispatchEvent(&event, status);
return;
}
}
}
}
}
if (!node || !aLimitToDocument || node->OwnerDoc() == aLimitToDocument) {
// We couldn't dispatch touchend. Remove the touch from gCaptureTouchList
// explicitly.
nsIPresShell::gCaptureTouchList->Remove(aTouch->Identifier());
}
}
static PLDHashOperator
AppendToTouchList(const uint32_t& aKey, nsRefPtr<dom::Touch>& aData, void *aTouchList)
{
WidgetTouchEvent::TouchArray* touches =
static_cast<WidgetTouchEvent::TouchArray*>(aTouchList);
aData->mChanged = false;
touches->AppendElement(aData);
return PL_DHASH_NEXT;
}
void
PresShell::EvictTouches()
{
WidgetTouchEvent::AutoTouchArray touches;
gCaptureTouchList->Enumerate(&AppendToTouchList, &touches);
for (uint32_t i = 0; i < touches.Length(); ++i) {
EvictTouchPoint(touches[i], mDocument);
}
}
static PLDHashOperator
FindAnyTarget(const uint32_t& aKey, nsRefPtr<dom::Touch>& aData,
void* aAnyTarget)
@@ -8068,125 +8016,7 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
case NS_MOUSE_BUTTON_UP:
isHandlingUserInput = true;
break;
case NS_TOUCH_START: {
isHandlingUserInput = true;
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
// 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
// queue
if (touchEvent->touches.Length() == 1) {
WidgetTouchEvent::AutoTouchArray touches;
gCaptureTouchList->Enumerate(&AppendToTouchList, (void *)&touches);
for (uint32_t i = 0; i < touches.Length(); ++i) {
EvictTouchPoint(touches[i]);
}
}
// Add any new touches to the queue
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
dom::Touch* touch = touchEvent->touches[i];
int32_t id = touch->Identifier();
if (!gCaptureTouchList->Get(id, nullptr)) {
// If it is not already in the queue, it is a new touch
touch->mChanged = true;
}
touch->mMessage = aEvent->message;
gCaptureTouchList->Put(id, touch);
}
break;
}
case NS_TOUCH_END:
isHandlingUserInput = true;
// Fall through to touchcancel code
case NS_TOUCH_CANCEL: {
// Remove the changed touches
// need to make sure we only remove touches that are ending here
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
for (uint32_t i = 0; i < touches.Length(); ++i) {
dom::Touch* touch = touches[i];
if (!touch) {
continue;
}
touch->mMessage = aEvent->message;
touch->mChanged = true;
int32_t id = touch->Identifier();
nsRefPtr<dom::Touch> oldTouch = gCaptureTouchList->GetWeak(id);
if (!oldTouch) {
continue;
}
nsCOMPtr<EventTarget> targetPtr = oldTouch->mTarget;
mCurrentEventContent = do_QueryInterface(targetPtr);
touch->SetTarget(targetPtr);
gCaptureTouchList->Remove(id);
}
// add any touches left in the touch list, but ensure changed=false
gCaptureTouchList->Enumerate(&AppendToTouchList, (void *)&touches);
break;
}
case NS_TOUCH_MOVE: {
// Check for touches that changed. Mark them add to queue
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
WidgetTouchEvent::TouchArray& touches = touchEvent->touches;
bool haveChanged = false;
for (int32_t i = touches.Length(); i; ) {
--i;
dom::Touch* touch = touches[i];
if (!touch) {
continue;
}
int32_t id = touch->Identifier();
touch->mMessage = aEvent->message;
nsRefPtr<dom::Touch> oldTouch = gCaptureTouchList->GetWeak(id);
if (!oldTouch) {
touches.RemoveElementAt(i);
continue;
}
if (!touch->Equals(oldTouch)) {
touch->mChanged = true;
haveChanged = true;
}
nsCOMPtr<dom::EventTarget> targetPtr = oldTouch->mTarget;
if (!targetPtr) {
touches.RemoveElementAt(i);
continue;
}
touch->SetTarget(targetPtr);
gCaptureTouchList->Put(id, touch);
// if we're moving from touchstart to touchmove for this touch
// we allow preventDefault to prevent mouse events
if (oldTouch->mMessage != touch->mMessage) {
touchIsNew = true;
}
}
// is nothing has changed, we should just return
if (!haveChanged) {
if (touchIsNew) {
// however, if this is the first touchmove after a touchstart,
// it is special in that preventDefault is allowed on it, so
// we must dispatch it to content even if nothing changed. we
// arbitrarily pick the first touch point to be the "changed"
// touch because firing an event with no changed events doesn't
// work.
for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
if (touchEvent->touches[i]) {
touchEvent->touches[i]->mChanged = true;
break;
}
}
} else {
if (gPreventMouseEvents) {
*aStatus = nsEventStatus_eConsumeNoDefault;
}
return NS_OK;
}
}
break;
}
case NS_DRAGDROP_DROP:
nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
if (session) {
@@ -8198,6 +8028,12 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
}
break;
}
if (!mTouchManager.PreHandleEvent(aEvent, aStatus,
touchIsNew, isHandlingUserInput,
mCurrentEventContent)) {
return NS_OK;
}
}
if (aEvent->message == NS_CONTEXTMENU) {