Bug 1127066 - Extract an APZEventState class from TabChild. r=kats

--HG--
extra : source : fc54993e0c836ca01f3900072227938e8c4b938c
This commit is contained in:
Botond Ballo 2015-02-09 14:05:18 -05:00
Родитель 985154a7f1
Коммит 9fd2a6c742
7 изменённых файлов: 456 добавлений и 286 удалений

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

@ -20,9 +20,9 @@
#include "mozilla/plugins/PluginWidgetChild.h"
#include "mozilla/ipc/DocumentRendererChild.h"
#include "mozilla/ipc/FileDescriptorUtils.h"
#include "mozilla/layers/ActiveElementManager.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/APZEventState.h"
#include "mozilla/layers/CompositorChild.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/ShadowLayers.h"
@ -115,54 +115,9 @@ static const CSSSize kDefaultViewportSize(980, 480);
static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
static int32_t sActiveDurationMs = 10;
static bool sActiveDurationMsSet = false;
typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
static TabChildMap* sTabChildren;
class TabChild::DelayedFireSingleTapEvent MOZ_FINAL : public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
DelayedFireSingleTapEvent(nsIWidget* aWidget,
LayoutDevicePoint& aPoint,
nsITimer* aTimer)
: mWidget(do_GetWeakReference(aWidget))
, mPoint(aPoint)
// Hold the reference count until we are called back.
, mTimer(aTimer)
{
}
NS_IMETHODIMP Notify(nsITimer*) MOZ_OVERRIDE
{
nsCOMPtr<nsIWidget> widget = do_QueryReferent(mWidget);
if (widget) {
APZCCallbackHelper::FireSingleTapEvent(mPoint, widget);
}
mTimer = nullptr;
return NS_OK;
}
void ClearTimer() {
mTimer = nullptr;
}
private:
~DelayedFireSingleTapEvent()
{
}
nsWeakPtr mWidget;
LayoutDevicePoint mPoint;
nsCOMPtr<nsITimer> mTimer;
};
NS_IMPL_ISUPPORTS(TabChild::DelayedFireSingleTapEvent,
nsITimerCallback)
class TabChild::DelayedFireContextMenuEvent MOZ_FINAL : public nsITimerCallback
{
public:
@ -865,6 +820,20 @@ private:
nsWeakPtr mTabChild;
};
class TabChildContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback {
public:
explicit TabChildContentReceivedInputBlockCallback(TabChild* aTabChild)
: mTabChild(do_GetWeakReference(static_cast<nsITabChild*>(aTabChild)))
{}
void Run(const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) const MOZ_OVERRIDE {
if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(mTabChild)) {
static_cast<TabChild*>(tabChild.get())->SendContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
}
}
private:
nsWeakPtr mTabChild;
};
TabChild::TabChild(nsIContentChild* aManager,
const TabId& aTabId,
@ -884,12 +853,7 @@ TabChild::TabChild(nsIContentChild* aManager,
, mTriedBrowserInit(false)
, mOrientation(eScreenOrientation_PortraitPrimary)
, mUpdateHitRegion(false)
, mPendingTouchPreventedResponse(false)
, mPendingTouchPreventedBlockId(0)
, mTouchEndCancelled(false)
, mEndTouchIsClick(false)
, mIgnoreKeyPressEvent(false)
, mActiveElementManager(new ActiveElementManager())
, mSetTargetAPZCCallback(new TabChildSetTargetAPZCCallback(this))
, mHasValidInnerSize(false)
, mDestroyed(false)
@ -899,13 +863,6 @@ TabChild::TabChild(nsIContentChild* aManager,
, mIPCOpen(true)
, mParentIsActive(false)
{
if (!sActiveDurationMsSet) {
Preferences::AddIntVarCache(&sActiveDurationMs,
"ui.touch_activation.duration_ms",
sActiveDurationMs);
sActiveDurationMsSet = true;
}
// preloaded TabChild should not be added to child map
if (mUniqueId) {
MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
@ -1164,6 +1121,9 @@ TabChild::Init()
do_QueryInterface(window->GetChromeEventHandler());
docShell->SetChromeEventHandler(chromeHandler);
mAPZEventState = new APZEventState(mWidget,
new TabChildContentReceivedInputBlockCallback(this));
return NS_OK;
}
@ -1597,17 +1557,6 @@ TabChild::HasValidInnerSize()
return mHasValidInnerSize;
}
void
TabChild::SendPendingTouchPreventedResponse(bool aPreventDefault,
const ScrollableLayerGuid& aGuid)
{
if (mPendingTouchPreventedResponse) {
MOZ_ASSERT(aGuid == mPendingTouchPreventedGuid);
SendContentReceivedInputBlock(mPendingTouchPreventedGuid, mPendingTouchPreventedBlockId, aPreventDefault);
mPendingTouchPreventedResponse = false;
}
}
void
TabChild::DestroyWindow()
{
@ -2134,40 +2083,8 @@ TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
bool
TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
{
TABC_LOG("Handling single tap at %s on %s with %p %p %d\n",
Stringify(aPoint).c_str(), Stringify(aGuid).c_str(), mGlobal.get(),
mTabChildGlobal.get(), mTouchEndCancelled);
if (!mGlobal || !mTabChildGlobal) {
return true;
}
if (mTouchEndCancelled) {
return true;
}
LayoutDevicePoint currentPoint =
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
* mWidget->GetDefaultScale();;
if (!mActiveElementManager->ActiveElementUsesStyle()) {
// If the active element isn't visually affected by the :active style, we
// have no need to wait the extra sActiveDurationMs to make the activation
// visually obvious to the user.
APZCCallbackHelper::FireSingleTapEvent(currentPoint, mWidget);
return true;
}
TABC_LOG("Active element uses style, scheduling timer for click event\n");
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
nsRefPtr<DelayedFireSingleTapEvent> callback =
new DelayedFireSingleTapEvent(mWidget, currentPoint, timer);
nsresult rv = timer->InitWithCallback(callback,
sActiveDurationMs,
nsITimer::TYPE_ONE_SHOT);
if (NS_FAILED(rv)) {
// Make |callback| not hold the timer, so they will both be destructed when
// we leave the scope of this function.
callback->ClearTimer();
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessSingleTap(aPoint, aGuid, GetPresShellResolution());
}
return true;
}
@ -2175,37 +2092,10 @@ TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid&
bool
TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId)
{
TABC_LOG("Handling long tap at %s with %p %p\n",
Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get());
if (!mGlobal || !mTabChildGlobal) {
return true;
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessLongTap(GetDOMWindowUtils(), aPoint, aGuid,
aInputBlockId, GetPresShellResolution());
}
SendPendingTouchPreventedResponse(false, aGuid);
bool eventHandled =
DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution()),
2, 1, 0, true,
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
TABC_LOG("Contextmenu event handled: %d\n", eventHandled);
// If no one handle context menu, fire MOZLONGTAP event
if (!eventHandled) {
LayoutDevicePoint currentPoint =
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, GetPresShellResolution())
* mWidget->GetDefaultScale();
int time = 0;
nsEventStatus status =
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
eventHandled = (status == nsEventStatus_eConsumeNoDefault);
TABC_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
}
SendContentReceivedInputBlock(aGuid, aInputBlockId, eventHandled);
return true;
}
@ -2221,64 +2111,7 @@ TabChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
const APZStateChange& aChange,
const int& aArg)
{
switch (aChange)
{
case APZStateChange::TransformBegin:
{
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
if (scrollbarMediator) {
scrollbarMediator->ScrollbarActivityStarted();
}
nsCOMPtr<nsIDocument> doc = GetDocument();
if (doc) {
nsCOMPtr<nsIDocShell> docshell(doc->GetDocShell());
if (docshell && sf) {
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
nsdocshell->NotifyAsyncPanZoomStarted(sf->GetScrollPositionCSSPixels());
}
}
break;
}
case APZStateChange::TransformEnd:
{
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
if (scrollbarMediator) {
scrollbarMediator->ScrollbarActivityStopped();
}
nsCOMPtr<nsIDocument> doc = GetDocument();
if (doc) {
nsCOMPtr<nsIDocShell> docshell(doc->GetDocShell());
if (docshell && sf) {
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
nsdocshell->NotifyAsyncPanZoomStopped(sf->GetScrollPositionCSSPixels());
}
}
break;
}
case APZStateChange::StartTouch:
{
mActiveElementManager->HandleTouchStart(aArg);
break;
}
case APZStateChange::StartPanning:
{
mActiveElementManager->HandlePanStart();
break;
}
case APZStateChange::EndTouch:
{
mEndTouchIsClick = aArg;
break;
}
default:
// APZStateChange has a 'sentinel' value, and the compiler complains
// if an enumerator is not handled and there is no 'default' case.
break;
}
mAPZEventState->ProcessAPZStateChange(GetDocument(), aViewId, aChange, aArg);
return true;
}
@ -2318,8 +2151,8 @@ TabChild::RecvMouseEvent(const nsString& aType,
const int32_t& aModifiers,
const bool& aIgnoreRootScrollFrame)
{
DispatchMouseEvent(aType, CSSPoint(aX, aY), aButton, aClickCount, aModifiers,
aIgnoreRootScrollFrame, nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN);
APZCCallbackHelper::DispatchMouseEvent(GetDOMWindowUtils(), aType, CSSPoint(aX, aY),
aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN);
return true;
}
@ -2348,7 +2181,7 @@ TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
APZCCallbackHelper::DispatchWidgetEvent(event);
if (IsAsyncPanZoomEnabled()) {
SendContentReceivedInputBlock(aGuid, aInputBlockId, event.mFlags.mDefaultPrevented);
mAPZEventState->ProcessWheelEvent(event, aGuid, aInputBlockId);
}
return true;
}
@ -2467,13 +2300,15 @@ TabChild::FireContextMenuEvent()
}
MOZ_ASSERT(mTapHoldTimer && mActivePointerId >= 0);
bool defaultPrevented = DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
mGestureDownPoint / CSSToLayoutDeviceScale(scale),
2 /* Right button */,
1 /* Click count */,
0 /* Modifiers */,
true /* Ignore root scroll frame */,
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
bool defaultPrevented = APZCCallbackHelper::DispatchMouseEvent(
GetDOMWindowUtils(),
NS_LITERAL_STRING("contextmenu"),
mGestureDownPoint / CSSToLayoutDeviceScale(scale),
2 /* Right button */,
1 /* Click count */,
0 /* Modifiers */,
true /* Ignore root scroll frame */,
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
// Fire a click event if someone didn't call preventDefault() on the context
// menu event.
@ -2533,49 +2368,7 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
return true;
}
if (aEvent.message == NS_TOUCH_START && localEvent.touches.Length() > 0) {
mActiveElementManager->SetTargetElement(localEvent.touches[0]->GetTarget());
}
bool isTouchPrevented = nsIPresShell::gPreventMouseEvents ||
localEvent.mFlags.mMultipleActionsPrevented;
switch (aEvent.message) {
case NS_TOUCH_START: {
mTouchEndCancelled = false;
if (mPendingTouchPreventedResponse) {
// We can enter here if we get two TOUCH_STARTs in a row and didn't
// respond to the first one. Respond to it now.
SendContentReceivedInputBlock(mPendingTouchPreventedGuid, mPendingTouchPreventedBlockId, false);
mPendingTouchPreventedResponse = false;
}
if (isTouchPrevented) {
SendContentReceivedInputBlock(aGuid, aInputBlockId, isTouchPrevented);
} else {
mPendingTouchPreventedResponse = true;
mPendingTouchPreventedGuid = aGuid;
mPendingTouchPreventedBlockId = aInputBlockId;
}
break;
}
case NS_TOUCH_END:
if (isTouchPrevented) {
mTouchEndCancelled = true;
mEndTouchIsClick = false;
}
// fall through
case NS_TOUCH_CANCEL:
mActiveElementManager->HandleTouchEnd(mEndTouchIsClick);
// fall through
case NS_TOUCH_MOVE: {
SendPendingTouchPreventedResponse(isTouchPrevented, aGuid);
break;
}
default:
NS_WARNING("Unknown touch event type");
}
mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId);
return true;
}
@ -3121,24 +2914,6 @@ TabChild::NotifyPainted()
}
}
bool
TabChild::DispatchMouseEvent(const nsString& aType,
const CSSPoint& aPoint,
const int32_t& aButton,
const int32_t& aClickCount,
const int32_t& aModifiers,
const bool& aIgnoreRootScrollFrame,
const unsigned short& aInputSourceArg)
{
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
NS_ENSURE_TRUE(utils, true);
bool defaultPrevented = false;
utils->SendMouseEvent(aType, aPoint.x, aPoint.y, aButton, aClickCount, aModifiers,
aIgnoreRootScrollFrame, 0, aInputSourceArg, false, 4, &defaultPrevented);
return defaultPrevented;
}
void
TabChild::MakeVisible()
{

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

@ -45,7 +45,7 @@ class RenderFrameChild;
}
namespace layers {
class ActiveElementManager;
class APZEventState;
struct SetTargetAPZCCallback;
}
@ -252,7 +252,7 @@ class TabChild MOZ_FINAL : public TabChildBase,
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
typedef mozilla::layers::ActiveElementManager ActiveElementManager;
typedef mozilla::layers::APZEventState APZEventState;
typedef mozilla::layers::SetTargetAPZCCallback SetTargetAPZCCallback;
public:
@ -437,17 +437,6 @@ public:
void RequestNativeKeyBindings(mozilla::widget::AutoCacheNativeKeyCommands* aAutoCache,
WidgetKeyboardEvent* aEvent);
/** Return a boolean indicating if the page has called preventDefault on
* the event.
*/
bool DispatchMouseEvent(const nsString& aType,
const CSSPoint& aPoint,
const int32_t& aButton,
const int32_t& aClickCount,
const int32_t& aModifiers,
const bool& aIgnoreRootScrollFrame,
const unsigned short& aInputSourceArg);
/**
* Signal to this TabChild that it should be made visible:
* activated widget, retained layer tree, etc. (Respectively,
@ -542,7 +531,6 @@ private:
nsresult Init();
class DelayedFireSingleTapEvent;
class DelayedFireContextMenuEvent;
// Notify others that our TabContext has been updated. (At the moment, this
@ -596,9 +584,6 @@ private:
bool HasValidInnerSize();
void SendPendingTouchPreventedResponse(bool aPreventDefault,
const ScrollableLayerGuid& aGuid);
// Get the pres shell resolution of the document in this tab.
float GetPresShellResolution() const;
@ -637,15 +622,9 @@ private:
bool mTriedBrowserInit;
ScreenOrientation mOrientation;
bool mUpdateHitRegion;
bool mPendingTouchPreventedResponse;
ScrollableLayerGuid mPendingTouchPreventedGuid;
uint64_t mPendingTouchPreventedBlockId;
bool mTouchEndCancelled;
bool mEndTouchIsClick;
bool mIgnoreKeyPressEvent;
nsRefPtr<ActiveElementManager> mActiveElementManager;
nsRefPtr<APZEventState> mAPZEventState;
nsRefPtr<SetTargetAPZCCallback> mSetTargetAPZCCallback;
bool mHasValidInnerSize;
bool mDestroyed;

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

@ -419,6 +419,25 @@ APZCCallbackHelper::DispatchSynthesizedMouseEvent(uint32_t aMsg,
return DispatchWidgetEvent(event);
}
bool
APZCCallbackHelper::DispatchMouseEvent(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
const nsString& aType,
const CSSPoint& aPoint,
int32_t aButton,
int32_t aClickCount,
int32_t aModifiers,
bool aIgnoreRootScrollFrame,
unsigned short aInputSourceArg)
{
NS_ENSURE_TRUE(aUtils, true);
bool defaultPrevented = false;
aUtils->SendMouseEvent(aType, aPoint.x, aPoint.y, aButton, aClickCount, aModifiers,
aIgnoreRootScrollFrame, 0, aInputSourceArg, false, 4, &defaultPrevented);
return defaultPrevented;
}
void
APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint,
nsIWidget* aWidget)

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

@ -125,6 +125,17 @@ public:
const LayoutDevicePoint& aRefPoint,
nsIWidget* aWidget);
/* Dispatch a mouse event with the given parameters.
* Return whether or not any listeners have called preventDefault on the event. */
static bool DispatchMouseEvent(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
const nsString& aType,
const CSSPoint& aPoint,
int32_t aButton,
int32_t aClickCount,
int32_t aModifiers,
bool aIgnoreRootScrollFrame,
unsigned short aInputSourceArg);
/* Fire a single-tap event at the given point. The event is dispatched
* via the given widget. */
static void FireSingleTapEvent(const LayoutDevicePoint& aPoint,

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

@ -0,0 +1,294 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "APZEventState.h"
#include "ActiveElementManager.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/Preferences.h"
#include "nsCOMPtr.h"
#include "nsDocShell.h"
#include "nsITimer.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIWidget.h"
#define APZES_LOG(...)
// #define APZES_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
namespace mozilla {
namespace layers {
static int32_t sActiveDurationMs = 10;
static bool sActiveDurationMsSet = false;
APZEventState::APZEventState(nsIWidget* aWidget,
const nsRefPtr<ContentReceivedInputBlockCallback>& aCallback)
: mWidget(aWidget)
, mActiveElementManager(new ActiveElementManager())
, mContentReceivedInputBlockCallback(aCallback)
, mPendingTouchPreventedResponse(false)
, mPendingTouchPreventedBlockId(0)
, mEndTouchIsClick(false)
, mTouchEndCancelled(false)
{
if (!sActiveDurationMsSet) {
Preferences::AddIntVarCache(&sActiveDurationMs,
"ui.touch_activation.duration_ms",
sActiveDurationMs);
sActiveDurationMsSet = true;
}
}
APZEventState::~APZEventState()
{}
class DelayedFireSingleTapEvent MOZ_FINAL : public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
DelayedFireSingleTapEvent(nsIWidget* aWidget,
LayoutDevicePoint& aPoint,
nsITimer* aTimer)
: mWidget(do_GetWeakReference(aWidget))
, mPoint(aPoint)
// Hold the reference count until we are called back.
, mTimer(aTimer)
{
}
NS_IMETHODIMP Notify(nsITimer*) MOZ_OVERRIDE
{
if (nsCOMPtr<nsIWidget> widget = do_QueryReferent(mWidget)) {
APZCCallbackHelper::FireSingleTapEvent(mPoint, widget);
}
mTimer = nullptr;
return NS_OK;
}
void ClearTimer() {
mTimer = nullptr;
}
private:
~DelayedFireSingleTapEvent()
{
}
nsWeakPtr mWidget;
LayoutDevicePoint mPoint;
nsCOMPtr<nsITimer> mTimer;
};
NS_IMPL_ISUPPORTS(DelayedFireSingleTapEvent, nsITimerCallback)
void
APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
const ScrollableLayerGuid& aGuid,
float aPresShellResolution)
{
APZES_LOG("Handling single tap at %s on %s with %d\n",
Stringify(aPoint).c_str(), Stringify(aGuid).c_str(), mTouchEndCancelled);
if (mTouchEndCancelled) {
return;
}
LayoutDevicePoint currentPoint =
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, aPresShellResolution)
* mWidget->GetDefaultScale();;
if (!mActiveElementManager->ActiveElementUsesStyle()) {
// If the active element isn't visually affected by the :active style, we
// have no need to wait the extra sActiveDurationMs to make the activation
// visually obvious to the user.
APZCCallbackHelper::FireSingleTapEvent(currentPoint, mWidget);
return;
}
APZES_LOG("Active element uses style, scheduling timer for click event\n");
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
nsRefPtr<DelayedFireSingleTapEvent> callback =
new DelayedFireSingleTapEvent(mWidget, currentPoint, timer);
nsresult rv = timer->InitWithCallback(callback,
sActiveDurationMs,
nsITimer::TYPE_ONE_SHOT);
if (NS_FAILED(rv)) {
// Make |callback| not hold the timer, so they will both be destructed when
// we leave the scope of this function.
callback->ClearTimer();
}
}
void
APZEventState::ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
const CSSPoint& aPoint,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
float aPresShellResolution)
{
APZES_LOG("Handling long tap at %s\n", Stringify(aPoint).c_str());
SendPendingTouchPreventedResponse(false, aGuid);
bool eventHandled =
APZCCallbackHelper::DispatchMouseEvent(aUtils, NS_LITERAL_STRING("contextmenu"),
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, aPresShellResolution),
2, 1, 0, true,
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
APZES_LOG("Contextmenu event handled: %d\n", eventHandled);
// If no one handle context menu, fire MOZLONGTAP event
if (!eventHandled) {
LayoutDevicePoint currentPoint =
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid, aPresShellResolution)
* mWidget->GetDefaultScale();
int time = 0;
nsEventStatus status =
APZCCallbackHelper::DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
eventHandled = (status == nsEventStatus_eConsumeNoDefault);
APZES_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
}
mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, eventHandled);
}
void
APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId)
{
if (aEvent.message == NS_TOUCH_START && aEvent.touches.Length() > 0) {
mActiveElementManager->SetTargetElement(aEvent.touches[0]->GetTarget());
}
bool isTouchPrevented = nsIPresShell::gPreventMouseEvents ||
aEvent.mFlags.mMultipleActionsPrevented;
switch (aEvent.message) {
case NS_TOUCH_START: {
mTouchEndCancelled = false;
if (mPendingTouchPreventedResponse) {
// We can enter here if we get two TOUCH_STARTs in a row and didn't
// respond to the first one. Respond to it now.
mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid,
mPendingTouchPreventedBlockId, false);
mPendingTouchPreventedResponse = false;
}
if (isTouchPrevented) {
mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, isTouchPrevented);
} else {
mPendingTouchPreventedResponse = true;
mPendingTouchPreventedGuid = aGuid;
mPendingTouchPreventedBlockId = aInputBlockId;
}
break;
}
case NS_TOUCH_END:
if (isTouchPrevented) {
mTouchEndCancelled = true;
mEndTouchIsClick = false;
}
// fall through
case NS_TOUCH_CANCEL:
mActiveElementManager->HandleTouchEnd(mEndTouchIsClick);
// fall through
case NS_TOUCH_MOVE: {
SendPendingTouchPreventedResponse(isTouchPrevented, aGuid);
break;
}
default:
NS_WARNING("Unknown touch event type");
}
}
void
APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId)
{
mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, aEvent.mFlags.mDefaultPrevented);
}
void
APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
ViewID aViewId,
APZStateChange aChange,
int aArg)
{
switch (aChange)
{
case APZStateChange::TransformBegin:
{
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
if (scrollbarMediator) {
scrollbarMediator->ScrollbarActivityStarted();
}
if (aDocument) {
nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
if (docshell && sf) {
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
nsdocshell->NotifyAsyncPanZoomStarted(sf->GetScrollPositionCSSPixels());
}
}
break;
}
case APZStateChange::TransformEnd:
{
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
if (scrollbarMediator) {
scrollbarMediator->ScrollbarActivityStopped();
}
if (aDocument) {
nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
if (docshell && sf) {
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
nsdocshell->NotifyAsyncPanZoomStopped(sf->GetScrollPositionCSSPixels());
}
}
break;
}
case APZStateChange::StartTouch:
{
mActiveElementManager->HandleTouchStart(aArg);
break;
}
case APZStateChange::StartPanning:
{
mActiveElementManager->HandlePanStart();
break;
}
case APZStateChange::EndTouch:
{
mEndTouchIsClick = aArg;
break;
}
default:
// APZStateChange has a 'sentinel' value, and the compiler complains
// if an enumerator is not handled and there is no 'default' case.
break;
}
}
void
APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault,
const ScrollableLayerGuid& aGuid)
{
if (mPendingTouchPreventedResponse) {
MOZ_ASSERT(aGuid == mPendingTouchPreventedGuid);
mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid,
mPendingTouchPreventedBlockId, aPreventDefault);
mPendingTouchPreventedResponse = false;
}
}
}
}

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

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_APZEventState_h
#define mozilla_layers_APZEventState_h
#include <stdint.h>
#include "FrameMetrics.h" // for ScrollableLayerGuid
#include "Units.h"
#include "mozilla/EventForwards.h"
#include "mozilla/layers/GeckoContentController.h" // for APZStateChange
#include "nsCOMPtr.h"
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
#include "nsRefPtr.h"
class nsIDOMWindowUtils;
class nsIWidget;
namespace mozilla {
namespace layers {
class ActiveElementManager;
struct ContentReceivedInputBlockCallback {
public:
NS_INLINE_DECL_REFCOUNTING(ContentReceivedInputBlockCallback);
virtual void Run(const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
bool aPreventDefault) const = 0;
protected:
virtual ~ContentReceivedInputBlockCallback() {}
};
/**
* A content-side component that keeps track of state for handling APZ
* gestures and sending APZ notifications.
*/
class APZEventState {
typedef GeckoContentController::APZStateChange APZStateChange;
typedef FrameMetrics::ViewID ViewID;
public:
APZEventState(nsIWidget* aWidget,
const nsRefPtr<ContentReceivedInputBlockCallback>& aCallback);
NS_INLINE_DECL_REFCOUNTING(APZEventState);
void ProcessSingleTap(const CSSPoint& aPoint,
const ScrollableLayerGuid& aGuid,
float aPresShellResolution);
void ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
const CSSPoint& aPoint,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
float aPresShellResolution);
void ProcessTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
void ProcessWheelEvent(const WidgetWheelEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
void ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
ViewID aViewId,
APZStateChange aChange,
int aArg);
private:
~APZEventState();
void SendPendingTouchPreventedResponse(bool aPreventDefault,
const ScrollableLayerGuid& aGuid);
private:
nsCOMPtr<nsIWidget> mWidget;
nsRefPtr<ActiveElementManager> mActiveElementManager;
nsRefPtr<ContentReceivedInputBlockCallback> mContentReceivedInputBlockCallback;
bool mPendingTouchPreventedResponse;
ScrollableLayerGuid mPendingTouchPreventedGuid;
uint64_t mPendingTouchPreventedBlockId;
bool mEndTouchIsClick;
bool mTouchEndCancelled;
};
}
}
#endif /* mozilla_layers_APZEventState_h */

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

@ -92,6 +92,7 @@ EXPORTS.mozilla.layers += [
'apz/testutil/APZTestData.h',
'apz/util/ActiveElementManager.h',
'apz/util/APZCCallbackHelper.h',
'apz/util/APZEventState.h',
'apz/util/APZThreadUtils.h',
'apz/util/ChromeProcessController.h',
'apz/util/InputAPZContext.h',
@ -227,6 +228,7 @@ UNIFIED_SOURCES += [
'apz/testutil/APZTestData.cpp',
'apz/util/ActiveElementManager.cpp',
'apz/util/APZCCallbackHelper.cpp',
'apz/util/APZEventState.cpp',
'apz/util/APZThreadUtils.cpp',
'apz/util/ChromeProcessController.cpp',
'apz/util/InputAPZContext.cpp',
@ -355,6 +357,10 @@ MSVC_ENABLE_PGO = True
include('/ipc/chromium/chromium-config.mozbuild')
LOCAL_INCLUDES += [
'/docshell/base', # for nsDocShell.h
]
FINAL_LIBRARY = 'xul'
if CONFIG['MOZ_DEBUG']: