Fix APZ target confirmations arriving before dependent layer transactions. (bug 1154130, r=kats)

This commit is contained in:
David Anderson 2015-04-14 12:24:32 -04:00
Родитель 9972a1194a
Коммит c99aec898f
15 изменённых файлов: 155 добавлений и 79 удалений

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

@ -799,22 +799,6 @@ TabChild::Create(nsIContentChild* aManager,
return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
}
class TabChildSetTargetAPZCCallback : public SetTargetAPZCCallback {
public:
explicit TabChildSetTargetAPZCCallback(TabChild* aTabChild)
: mTabChild(do_GetWeakReference(static_cast<nsITabChild*>(aTabChild)))
{}
void Run(uint64_t aInputBlockId, const nsTArray<ScrollableLayerGuid>& aTargets) const override {
if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(mTabChild)) {
static_cast<TabChild*>(tabChild.get())->SendSetTargetAPZC(aInputBlockId, aTargets);
}
}
private:
nsWeakPtr mTabChild;
};
class TabChildSetAllowedTouchBehaviorCallback : public SetAllowedTouchBehaviorCallback {
public:
explicit TabChildSetAllowedTouchBehaviorCallback(TabChild* aTabChild)
@ -865,7 +849,6 @@ TabChild::TabChild(nsIContentChild* aManager,
, mOrientation(eScreenOrientation_PortraitPrimary)
, mUpdateHitRegion(false)
, mIgnoreKeyPressEvent(false)
, mSetTargetAPZCCallback(new TabChildSetTargetAPZCCallback(this))
, mSetAllowedTouchBehaviorCallback(new TabChildSetAllowedTouchBehaviorCallback(this))
, mHasValidInnerSize(false)
, mDestroyed(false)
@ -2192,7 +2175,7 @@ TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
if (gfxPrefs::AsyncPanZoomEnabled()) {
nsCOMPtr<nsIDocument> document(GetDocument());
APZCCallbackHelper::SendSetTargetAPZCNotification(WebWidget(), document, aEvent, aGuid,
aInputBlockId, mSetTargetAPZCCallback);
aInputBlockId);
}
WidgetWheelEvent event(aEvent);
@ -2387,7 +2370,7 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
}
nsCOMPtr<nsIDocument> document = GetDocument();
APZCCallbackHelper::SendSetTargetAPZCNotification(WebWidget(), document,
localEvent, aGuid, aInputBlockId, mSetTargetAPZCCallback);
localEvent, aGuid, aInputBlockId);
}
// Dispatch event to content (potentially a long-running operation)

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

@ -619,7 +619,6 @@ private:
bool mIgnoreKeyPressEvent;
nsRefPtr<APZEventState> mAPZEventState;
nsRefPtr<SetTargetAPZCCallback> mSetTargetAPZCCallback;
nsRefPtr<SetAllowedTouchBehaviorCallback> mSetAllowedTouchBehaviorCallback;
bool mHasValidInnerSize;
bool mDestroyed;

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

@ -8,6 +8,8 @@
#include "ContentHelper.h"
#include "gfxPlatform.h" // For gfxPlatform::UseTiling
#include "mozilla/dom/TabParent.h"
#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/ShadowLayers.h"
#include "nsIScrollableFrame.h"
#include "nsLayoutUtils.h"
#include "nsIDOMElement.h"
@ -565,14 +567,29 @@ PrepareForSetTargetAPZCNotification(nsIWidget* aWidget,
scrollAncestor, nsLayoutUtils::RepaintMode::Repaint);
}
static void
SendLayersDependentApzcTargetConfirmation(nsIPresShell* aShell, uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets)
{
LayerManager* lm = aShell->GetLayerManager();
if (!lm) {
return;
}
LayerTransactionChild* shadow = lm->AsShadowForwarder()->GetShadowManager();
if (!shadow) {
return;
}
shadow->SendSetConfirmedTargetAPZC(aInputBlockId, aTargets);
}
class DisplayportSetListener : public nsAPostRefreshObserver {
public:
DisplayportSetListener(const nsRefPtr<SetTargetAPZCCallback>& aCallback,
nsIPresShell* aPresShell,
DisplayportSetListener(nsIPresShell* aPresShell,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets)
: mCallback(aCallback)
, mPresShell(aPresShell)
: mPresShell(aPresShell)
, mInputBlockId(aInputBlockId)
, mTargets(aTargets)
{
@ -583,18 +600,17 @@ public:
}
void DidRefresh() override {
if (!mCallback) {
if (!mPresShell) {
MOZ_ASSERT_UNREACHABLE("Post-refresh observer fired again after failed attempt at unregistering it");
return;
}
APZCCH_LOG("Got refresh, sending target APZCs for input block %" PRIu64 "\n", mInputBlockId);
mCallback->Run(mInputBlockId, mTargets);
SendLayersDependentApzcTargetConfirmation(mPresShell, mInputBlockId, mTargets);
if (!mPresShell->RemovePostRefreshObserver(this)) {
MOZ_ASSERT_UNREACHABLE("Unable to unregister post-refresh observer! Leaking it instead of leaving garbage registered");
// Graceful handling, just in case...
mCallback = nullptr;
mPresShell = nullptr;
return;
}
@ -603,7 +619,6 @@ public:
}
private:
nsRefPtr<SetTargetAPZCCallback> mCallback;
nsRefPtr<nsIPresShell> mPresShell;
uint64_t mInputBlockId;
nsTArray<ScrollableLayerGuid> mTargets;
@ -612,21 +627,21 @@ private:
// Sends a SetTarget notification for APZC, given one or more previous
// calls to PrepareForAPZCSetTargetNotification().
static void
SendSetTargetAPZCNotificationHelper(nsIPresShell* aShell,
SendSetTargetAPZCNotificationHelper(nsIWidget* aWidget,
nsIPresShell* aShell,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets,
bool aWaitForRefresh,
const nsRefPtr<SetTargetAPZCCallback>& aCallback)
bool aWaitForRefresh)
{
bool waitForRefresh = aWaitForRefresh;
if (waitForRefresh) {
APZCCH_LOG("At least one target got a new displayport, need to wait for refresh\n");
waitForRefresh = aShell->AddPostRefreshObserver(
new DisplayportSetListener(aCallback, aShell, aInputBlockId, aTargets));
new DisplayportSetListener(aShell, aInputBlockId, aTargets));
}
if (!waitForRefresh) {
APZCCH_LOG("Sending target APZCs for input block %" PRIu64 "\n", aInputBlockId);
aCallback->Run(aInputBlockId, aTargets);
aWidget->SetConfirmedTargetAPZC(aInputBlockId, aTargets);
} else {
APZCCH_LOG("Successfully registered post-refresh observer\n");
}
@ -637,8 +652,7 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
nsIDocument* aDocument,
const WidgetGUIEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
const nsRefPtr<SetTargetAPZCCallback>& aCallback)
uint64_t aInputBlockId)
{
if (!aWidget || !aDocument) {
return;
@ -660,8 +674,12 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
// TODO: Do other types of events need to be handled?
if (!targets.IsEmpty()) {
SendSetTargetAPZCNotificationHelper(shell, aInputBlockId, targets,
waitForRefresh, aCallback);
SendSetTargetAPZCNotificationHelper(
aWidget,
shell,
aInputBlockId,
targets,
waitForRefresh);
}
}
}

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

@ -19,17 +19,6 @@ template<class T> struct already_AddRefed;
namespace mozilla {
namespace layers {
/* A base class for callbacks to be passed to APZCCallbackHelper::SendSetTargetAPZCNotification.
* If we had something like std::function, we could just use
* std::function<void(uint64_t, const nsTArray<ScrollableLayerGuid>&)>. */
struct SetTargetAPZCCallback {
public:
NS_INLINE_DECL_REFCOUNTING(SetTargetAPZCCallback)
virtual void Run(uint64_t aInputBlockId, const nsTArray<ScrollableLayerGuid>& aTargets) const = 0;
protected:
virtual ~SetTargetAPZCCallback() {}
};
/* A base class for callbacks to be passed to
* APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification. */
struct SetAllowedTouchBehaviorCallback {
@ -165,16 +154,18 @@ public:
/* Perform hit-testing on the touch points of |aEvent| to determine
* which scrollable frames they target. If any of these frames don't have
* a displayport, set one. Finally, invoke the provided callback with
* the guids of the target frames. If any displayports needed to be set,
* the callback is invoked after the next refresh, otherwise it's invoked
* right away. */
* a displayport, set one.
*
* If any displayports need to be set, the actual notification to APZ is
* sent to the compositor, which will then post a message back to APZ's
* controller thread. Otherwise, the provided widget's SetConfirmedTargetAPZC
* method is invoked immediately.
*/
static void SendSetTargetAPZCNotification(nsIWidget* aWidget,
nsIDocument* aDocument,
const WidgetGUIEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
const nsRefPtr<SetTargetAPZCCallback>& aCallback);
uint64_t aInputBlockId);
/* Figure out the allowed touch behaviors of each touch point in |aEvent|
* and send that information to the provided callback. */

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

@ -29,6 +29,7 @@
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
#include "mozilla/layers/APZThreadUtils.h" // for APZCTreeManager
#include "mozilla/layers/AsyncCompositionManager.h"
#include "mozilla/layers/BasicCompositor.h" // for BasicCompositor
#include "mozilla/layers/Compositor.h" // for Compositor
@ -1235,6 +1236,39 @@ CompositorParent::GetAPZTestData(const LayerTransactionParent* aLayerTree,
*aOutData = sIndirectLayerTrees[mRootLayerTreeID].mApzTestData;
}
class NotifyAPZConfirmedTargetTask : public Task
{
public:
explicit NotifyAPZConfirmedTargetTask(const nsRefPtr<APZCTreeManager>& aAPZCTM,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets)
: mAPZCTM(aAPZCTM),
mInputBlockId(aInputBlockId),
mTargets(aTargets)
{
}
virtual void Run() override {
mAPZCTM->SetTargetAPZC(mInputBlockId, mTargets);
}
private:
nsRefPtr<APZCTreeManager> mAPZCTM;
uint64_t mInputBlockId;
nsTArray<ScrollableLayerGuid> mTargets;
};
void
CompositorParent::SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets)
{
if (!mApzcTreeManager) {
return;
}
APZThreadUtils::RunOnControllerThread(new NotifyAPZConfirmedTargetTask(
mApzcTreeManager, aInputBlockId, aTargets));
}
void
CompositorParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints)
@ -1587,6 +1621,9 @@ public:
virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) override;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) override;
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) override;
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override;
@ -1969,6 +2006,24 @@ CrossProcessCompositorParent::GetAPZTestData(const LayerTransactionParent* aLaye
*aOutData = sIndirectLayerTrees[id].mApzTestData;
}
void
CrossProcessCompositorParent::SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets)
{
uint64_t id = aLayerTree->GetId();
MOZ_ASSERT(id != 0);
CompositorParent* parent = nullptr;
{
MonitorAutoLock lock(*sIndirectLayerTreesLock);
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(id);
if (!state || !state->mParent) {
return;
}
parent = state->mParent;
}
parent->SetConfirmedTargetAPZC(aLayerTree, aInputBlockId, aTargets);
}
AsyncCompositionManager*
CrossProcessCompositorParent::GetCompositionManager(LayerTransactionParent* aLayerTree)

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

@ -198,6 +198,9 @@ public:
override;
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) override;
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) override;
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) override { return mCompositionManager; }
/**

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

@ -805,6 +805,13 @@ LayerTransactionParent::RecvRequestProperty(const nsString& aProperty, float* aV
return true;
}
bool
LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets)
{
mShadowLayersManager->SetConfirmedTargetAPZC(this, aBlockId, aTargets);
return true;
}
bool
LayerTransactionParent::Attach(ShadowLayerParent* aLayerParent,

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

@ -139,6 +139,8 @@ protected:
const int32_t& aX, const int32_t& aY) override;
virtual bool RecvGetAPZTestData(APZTestData* aOutData) override;
virtual bool RecvRequestProperty(const nsString& aProperty, float* aValue) override;
virtual bool RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets) override;
virtual PLayerParent* AllocPLayerParent() override;
virtual bool DeallocPLayerParent(PLayerParent* actor) override;

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

@ -20,6 +20,7 @@ using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h";
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
/**
* The layers protocol is spoken between thread contexts that manage
@ -102,6 +103,10 @@ parent:
// Query a named property from the last frame
sync RequestProperty(nsString property) returns (float value);
// Tell the compositor to notify APZ that a layer has been confirmed for an
// input event.
async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
async Shutdown();

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

@ -38,6 +38,9 @@ public:
virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) { }
virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
APZTestData* aOutData) { }
virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) = 0;
};
} // layers

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

@ -483,6 +483,15 @@ PuppetWidget::ClearNativeTouchSequence(nsIObserver* aObserver)
mTabChild->SendClearNativeTouchSequence(notifier.SaveObserver());
return NS_OK;
}
void
PuppetWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) const
{
if (mTabChild) {
mTabChild->SendSetTargetAPZC(aInputBlockId, aTargets);
}
}
NS_IMETHODIMP_(bool)
PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,

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

@ -135,6 +135,8 @@ public:
NS_IMETHOD DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) override;
nsEventStatus DispatchAPZAwareEvent(WidgetInputEvent* aEvent) override;
nsEventStatus DispatchInputEvent(WidgetInputEvent* aEvent) override;
void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) const override;
NS_IMETHOD CaptureRollupEvents(nsIRollupListener* aListener,
bool aDoCapture) override

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

@ -902,25 +902,6 @@ nsBaseWidget::CreateRootContentController()
return controller.forget();
}
class ChromeProcessSetTargetAPZCCallback : public SetTargetAPZCCallback {
public:
explicit ChromeProcessSetTargetAPZCCallback(APZCTreeManager* aTreeManager)
: mTreeManager(aTreeManager)
{}
void Run(uint64_t aInputBlockId, const nsTArray<ScrollableLayerGuid>& aTargets) const override {
MOZ_ASSERT(NS_IsMainThread());
// need a local var to disambiguate between the SetTargetAPZC overloads.
void (APZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray<ScrollableLayerGuid>&)
= &APZCTreeManager::SetTargetAPZC;
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
mTreeManager.get(), setTargetApzcFunc, aInputBlockId, aTargets));
}
private:
nsRefPtr<APZCTreeManager> mTreeManager;
};
class ChromeProcessSetAllowedTouchBehaviorCallback : public SetAllowedTouchBehaviorCallback {
public:
explicit ChromeProcessSetAllowedTouchBehaviorCallback(APZCTreeManager* aTreeManager)
@ -967,7 +948,6 @@ void nsBaseWidget::ConfigureAPZCTreeManager()
mAPZC->SetDPI(GetDPI());
mAPZEventState = new APZEventState(this,
new ChromeProcessContentReceivedInputBlockCallback(mAPZC));
mSetTargetAPZCCallback = new ChromeProcessSetTargetAPZCCallback(mAPZC);
mSetAllowedTouchBehaviorCallback = new ChromeProcessSetAllowedTouchBehaviorCallback(mAPZC);
nsRefPtr<GeckoContentController> controller = CreateRootContentController();
@ -982,6 +962,17 @@ void nsBaseWidget::ConfigureAPZControllerThread()
APZThreadUtils::SetControllerThread(MessageLoop::current());
}
void
nsBaseWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) const
{
// Need to specifically bind this since it's overloaded.
void (APZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray<ScrollableLayerGuid>&)
= &APZCTreeManager::SetTargetAPZC;
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
mAPZC.get(), setTargetApzcFunc, aInputBlockId, mozilla::Move(aTargets)));
}
nsEventStatus
nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent,
const ScrollableLayerGuid& aGuid,
@ -1017,12 +1008,12 @@ nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent,
aInputBlockId, mSetAllowedTouchBehaviorCallback);
}
APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(), *aEvent,
aGuid, aInputBlockId, mSetTargetAPZCCallback);
aGuid, aInputBlockId);
}
mAPZEventState->ProcessTouchEvent(*touchEvent, aGuid, aInputBlockId, aApzResponse);
} else if (WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent()) {
APZCCallbackHelper::SendSetTargetAPZCNotification(this, GetDocument(), *aEvent,
aGuid, aInputBlockId, mSetTargetAPZCCallback);
aGuid, aInputBlockId);
mAPZEventState->ProcessWheelEvent(*wheelEvent, aGuid, aInputBlockId);
}
}

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

@ -39,7 +39,6 @@ class APZCTreeManager;
class GeckoContentController;
class APZEventState;
struct ScrollableLayerGuid;
struct SetTargetAPZCCallback;
struct SetAllowedTouchBehaviorCallback;
}
@ -95,7 +94,6 @@ protected:
typedef mozilla::layers::GeckoContentController GeckoContentController;
typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
typedef mozilla::layers::APZEventState APZEventState;
typedef mozilla::layers::SetTargetAPZCCallback SetTargetAPZCCallback;
typedef mozilla::layers::SetAllowedTouchBehaviorCallback SetAllowedTouchBehaviorCallback;
typedef mozilla::ScreenRotation ScreenRotation;
@ -238,6 +236,9 @@ public:
// Dispatch an event that must be first be routed through APZ.
nsEventStatus DispatchAPZAwareEvent(mozilla::WidgetInputEvent* aEvent) override;
void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) const override;
void NotifyWindowDestroyed();
void NotifySizeMoveDone();
void NotifyWindowMoved(int32_t aX, int32_t aY);
@ -479,7 +480,6 @@ protected:
nsRefPtr<mozilla::CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
nsRefPtr<APZCTreeManager> mAPZC;
nsRefPtr<APZEventState> mAPZEventState;
nsRefPtr<SetTargetAPZCCallback> mSetTargetAPZCCallback;
nsRefPtr<SetAllowedTouchBehaviorCallback> mSetAllowedTouchBehaviorCallback;
nsRefPtr<WidgetShutdownObserver> mShutdownObserver;
nsRefPtr<TextEventDispatcher> mTextEventDispatcher;

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

@ -53,6 +53,7 @@ class CompositorChild;
class LayerManager;
class LayerManagerComposite;
class PLayerTransactionChild;
struct ScrollableLayerGuid;
}
namespace gfx {
class DrawTarget;
@ -1767,6 +1768,13 @@ class nsIWidget : public nsISupports {
*/
virtual nsEventStatus DispatchInputEvent(mozilla::WidgetInputEvent* aEvent) = 0;
/**
* Confirm an APZ-aware event target. This should be used when APZ will
* not need a layers update to process the event.
*/
virtual void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<mozilla::layers::ScrollableLayerGuid>& aTargets) const = 0;
/**
* Enables the dropping of files to a widget (XXX this is temporary)
*