mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1326290 - Correct sequencing of layer transaction and StartAsyncScrollbarDrag messages. r=kats
In cases where a mouse click that starts a scrollbar drag is also what layerizes the scroll frame, the StartAsyncScrollbarDrag message needs to arrive after the layer transaction. This patch ensures it does. MozReview-Commit-ID: A02qRb6yWxg --HG-- extra : rebase_source : 3517e8c8a578a0bd257a80bb8cb81303d171bb6c
This commit is contained in:
parent
70f69c9c9a
commit
e8cc185f9d
@ -1595,14 +1595,18 @@ TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
|
||||
// actually go through the APZ code and so their mHandledByAPZ flag is false.
|
||||
// Since thos events didn't go through APZ, we don't need to send notifications
|
||||
// for them.
|
||||
bool pendingLayerization = false;
|
||||
if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
|
||||
nsCOMPtr<nsIDocument> document(GetDocument());
|
||||
APZCCallbackHelper::SendSetTargetAPZCNotification(
|
||||
pendingLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification(
|
||||
mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
|
||||
}
|
||||
|
||||
nsEventStatus unused;
|
||||
InputAPZContext context(aGuid, aInputBlockId, unused);
|
||||
if (pendingLayerization) {
|
||||
context.SetPendingLayerization();
|
||||
}
|
||||
|
||||
WidgetMouseEvent localEvent(aEvent);
|
||||
localEvent.mWidget = mPuppetWidget;
|
||||
|
@ -746,7 +746,7 @@ SendSetTargetAPZCNotificationHelper(nsIWidget* aWidget,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
|
||||
nsIDocument* aDocument,
|
||||
const WidgetGUIEvent& aEvent,
|
||||
@ -754,7 +754,7 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
|
||||
uint64_t aInputBlockId)
|
||||
{
|
||||
if (!aWidget || !aDocument) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (aInputBlockId == sLastTargetAPZCNotificationInputBlock) {
|
||||
// We have already confirmed the target APZC for a previous event of this
|
||||
@ -763,7 +763,7 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
|
||||
// race the original confirmation (which needs to go through a layers
|
||||
// transaction).
|
||||
APZCCH_LOG("Not resending target APZC confirmation for input block %" PRIu64 "\n", aInputBlockId);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
sLastTargetAPZCNotificationInputBlock = aInputBlockId;
|
||||
if (nsIPresShell* shell = aDocument->GetShell()) {
|
||||
@ -795,8 +795,11 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget,
|
||||
Move(targets),
|
||||
waitForRefresh);
|
||||
}
|
||||
|
||||
return waitForRefresh;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -139,8 +139,12 @@ public:
|
||||
* 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.
|
||||
*
|
||||
* Returns true if any displayports need to be set. (A caller may be
|
||||
* interested to know this, because they may need to delay certain actions
|
||||
* until after the displayport comes into effect.)
|
||||
*/
|
||||
static void SendSetTargetAPZCNotification(nsIWidget* aWidget,
|
||||
static bool SendSetTargetAPZCNotification(nsIWidget* aWidget,
|
||||
nsIDocument* aDocument,
|
||||
const WidgetGUIEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
|
@ -12,6 +12,7 @@ ScrollableLayerGuid InputAPZContext::sGuid;
|
||||
uint64_t InputAPZContext::sBlockId = 0;
|
||||
nsEventStatus InputAPZContext::sApzResponse = nsEventStatus_eIgnore;
|
||||
bool InputAPZContext::sRoutedToChildProcess = false;
|
||||
bool InputAPZContext::sPendingLayerization = false;
|
||||
|
||||
/*static*/ ScrollableLayerGuid
|
||||
InputAPZContext::GetTargetLayerGuid()
|
||||
@ -37,6 +38,12 @@ InputAPZContext::SetRoutedToChildProcess()
|
||||
sRoutedToChildProcess = true;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
InputAPZContext::SetPendingLayerization()
|
||||
{
|
||||
sPendingLayerization = true;
|
||||
}
|
||||
|
||||
InputAPZContext::InputAPZContext(const ScrollableLayerGuid& aGuid,
|
||||
const uint64_t& aBlockId,
|
||||
const nsEventStatus& aApzResponse)
|
||||
@ -44,11 +51,13 @@ InputAPZContext::InputAPZContext(const ScrollableLayerGuid& aGuid,
|
||||
, mOldBlockId(sBlockId)
|
||||
, mOldApzResponse(sApzResponse)
|
||||
, mOldRoutedToChildProcess(sRoutedToChildProcess)
|
||||
, mOldPendingLayerization(sPendingLayerization)
|
||||
{
|
||||
sGuid = aGuid;
|
||||
sBlockId = aBlockId;
|
||||
sApzResponse = aApzResponse;
|
||||
sRoutedToChildProcess = false;
|
||||
sPendingLayerization = false;
|
||||
}
|
||||
|
||||
InputAPZContext::~InputAPZContext()
|
||||
@ -57,13 +66,20 @@ InputAPZContext::~InputAPZContext()
|
||||
sBlockId = mOldBlockId;
|
||||
sApzResponse = mOldApzResponse;
|
||||
sRoutedToChildProcess = mOldRoutedToChildProcess;
|
||||
sPendingLayerization = mOldPendingLayerization;
|
||||
}
|
||||
|
||||
bool
|
||||
/*static*/ bool
|
||||
InputAPZContext::WasRoutedToChildProcess()
|
||||
{
|
||||
return sRoutedToChildProcess;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
InputAPZContext::HavePendingLayerization()
|
||||
{
|
||||
return sPendingLayerization;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
@ -23,25 +23,29 @@ private:
|
||||
static uint64_t sBlockId;
|
||||
static nsEventStatus sApzResponse;
|
||||
static bool sRoutedToChildProcess;
|
||||
static bool sPendingLayerization;
|
||||
|
||||
public:
|
||||
static ScrollableLayerGuid GetTargetLayerGuid();
|
||||
static uint64_t GetInputBlockId();
|
||||
static nsEventStatus GetApzResponse();
|
||||
static void SetRoutedToChildProcess();
|
||||
static void SetPendingLayerization();
|
||||
|
||||
InputAPZContext(const ScrollableLayerGuid& aGuid,
|
||||
const uint64_t& aBlockId,
|
||||
const nsEventStatus& aApzResponse);
|
||||
~InputAPZContext();
|
||||
|
||||
bool WasRoutedToChildProcess();
|
||||
static bool WasRoutedToChildProcess();
|
||||
static bool HavePendingLayerization();
|
||||
|
||||
private:
|
||||
ScrollableLayerGuid mOldGuid;
|
||||
uint64_t mOldBlockId;
|
||||
nsEventStatus mOldApzResponse;
|
||||
bool mOldRoutedToChildProcess;
|
||||
bool mOldPendingLayerization;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsRefreshDriver.h" // for nsAPostRefreshObserver
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
@ -929,6 +930,43 @@ nsSliderMediator::HandleEvent(nsIDOMEvent* aEvent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class AsyncScrollbarDragStarter : public nsAPostRefreshObserver {
|
||||
public:
|
||||
AsyncScrollbarDragStarter(nsIPresShell* aPresShell,
|
||||
nsIWidget* aWidget,
|
||||
const AsyncDragMetrics& aDragMetrics)
|
||||
: mPresShell(aPresShell)
|
||||
, mWidget(aWidget)
|
||||
, mDragMetrics(aDragMetrics)
|
||||
{
|
||||
}
|
||||
virtual ~AsyncScrollbarDragStarter() {}
|
||||
|
||||
void DidRefresh() override {
|
||||
if (!mPresShell) {
|
||||
MOZ_ASSERT_UNREACHABLE("Post-refresh observer fired again after failed attempt at unregistering it");
|
||||
return;
|
||||
}
|
||||
|
||||
mWidget->StartAsyncScrollbarDrag(mDragMetrics);
|
||||
|
||||
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...
|
||||
mPresShell = nullptr;
|
||||
mWidget = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<nsIPresShell> mPresShell;
|
||||
RefPtr<nsIWidget> mWidget;
|
||||
AsyncDragMetrics mDragMetrics;
|
||||
};
|
||||
|
||||
bool
|
||||
nsSliderFrame::StartAPZDrag(WidgetGUIEvent* aEvent)
|
||||
{
|
||||
@ -974,8 +1012,9 @@ nsSliderFrame::StartAPZDrag(WidgetGUIEvent* aEvent)
|
||||
scrollFrameAsScrollable->GetScrollPortRect().TopLeft();
|
||||
CSSRect sliderTrackCSS = CSSRect::FromAppUnits(sliderTrack);
|
||||
|
||||
nsIPresShell* shell = PresContext()->PresShell();
|
||||
uint64_t inputblockId = InputAPZContext::GetInputBlockId();
|
||||
uint32_t presShellId = PresContext()->PresShell()->GetPresShellId();
|
||||
uint32_t presShellId = shell->GetPresShellId();
|
||||
AsyncDragMetrics dragMetrics(scrollTargetId, presShellId, inputblockId,
|
||||
NSAppUnitsToFloatPixels(mDragStart,
|
||||
float(AppUnitsPerCSSPixel())),
|
||||
@ -989,7 +1028,15 @@ nsSliderFrame::StartAPZDrag(WidgetGUIEvent* aEvent)
|
||||
|
||||
// When we start an APZ drag, we wont get mouse events for the drag.
|
||||
// APZ will consume them all and only notify us of the new scroll position.
|
||||
this->GetNearestWidget()->StartAsyncScrollbarDrag(dragMetrics);
|
||||
bool waitForRefresh = InputAPZContext::HavePendingLayerization();
|
||||
nsIWidget* widget = this->GetNearestWidget();
|
||||
if (waitForRefresh) {
|
||||
waitForRefresh = shell->AddPostRefreshObserver(
|
||||
new AsyncScrollbarDragStarter(shell, widget, dragMetrics));
|
||||
}
|
||||
if (!waitForRefresh) {
|
||||
widget->StartAsyncScrollbarDrag(dragMetrics);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user