зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1127066 - Extract an APZEventState class from TabChild. r=kats
--HG-- extra : source : fc54993e0c836ca01f3900072227938e8c4b938c
This commit is contained in:
Родитель
985154a7f1
Коммит
9fd2a6c742
|
@ -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']:
|
||||
|
|
Загрузка…
Ссылка в новой задаче