mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-16 13:56:29 +00:00
Bug 1730998 - Use control
priority for RequestContentRepaint and NotifyFlushComplete, and process them in an early refresh driver runner. r=botond,smaug
Depends on D127030 Differential Revision: https://phabricator.services.mozilla.com/D127032
This commit is contained in:
parent
346c0300a6
commit
7dd944492a
@ -166,6 +166,8 @@ class GeckoContentController {
|
||||
*/
|
||||
virtual bool IsRemote() { return false; }
|
||||
|
||||
virtual PresShell* GetTopLevelPresShell() const { return nullptr; };
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
virtual ~GeckoContentController() = default;
|
||||
|
148
gfx/layers/apz/util/APZTaskRunnable.cpp
Normal file
148
gfx/layers/apz/util/APZTaskRunnable.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "APZTaskRunnable.h"
|
||||
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
namespace mozilla::layers {
|
||||
|
||||
NS_IMETHODIMP
|
||||
APZTaskRunnable::Run() {
|
||||
if (!mController) {
|
||||
mRegisteredPresShellId = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Move these variables first since below RequestContentPaint and
|
||||
// NotifyFlushComplete might spin event loop so that any new incoming requests
|
||||
// will be properly queued and run in the next refresh driver's tick.
|
||||
const bool needsFlushCompleteNotification = mNeedsFlushCompleteNotification;
|
||||
auto requests = std::move(mPendingRepaintRequestQueue);
|
||||
mPendingRepaintRequestMap.clear();
|
||||
mNeedsFlushCompleteNotification = false;
|
||||
mRegisteredPresShellId = 0;
|
||||
|
||||
// We need to process pending RepaintRequests first.
|
||||
while (!requests.empty()) {
|
||||
mController->RequestContentRepaint(requests.front());
|
||||
if (!mController) {
|
||||
return NS_OK;
|
||||
}
|
||||
requests.pop_front();
|
||||
}
|
||||
|
||||
if (needsFlushCompleteNotification) {
|
||||
// Then notify "apz-repaints-flushed" so that we can ensure that all pending
|
||||
// scroll position updates have finished when the "apz-repaints-flushed"
|
||||
// arrives.
|
||||
RefPtr<GeckoContentController> controller = mController;
|
||||
controller->NotifyFlushComplete();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void APZTaskRunnable::QueueRequest(const RepaintRequest& aRequest) {
|
||||
// If we are in test-controlled refreshes mode, process this |aRequest|
|
||||
// synchronously.
|
||||
if (IsTestControllingRefreshesEnabled()) {
|
||||
// Flush all pending requests and notification just in case the refresh
|
||||
// driver mode was changed before flushing them.
|
||||
Run();
|
||||
if (mController) {
|
||||
mController->RequestContentRepaint(aRequest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
EnsureRegisterAsEarlyRunner();
|
||||
|
||||
RepaintRequestKey key{aRequest.GetScrollId(), aRequest.GetScrollUpdateType()};
|
||||
|
||||
auto lastDiscardableRequest = mPendingRepaintRequestMap.find(key);
|
||||
// If there's an existing request with the same key, we can discard it and we
|
||||
// push the incoming one into the queue's tail so that we can ensure the order
|
||||
// of processing requests.
|
||||
if (lastDiscardableRequest != mPendingRepaintRequestMap.end()) {
|
||||
for (auto it = mPendingRepaintRequestQueue.begin();
|
||||
it != mPendingRepaintRequestQueue.end(); it++) {
|
||||
if (RepaintRequestKey{it->GetScrollId(), it->GetScrollUpdateType()} ==
|
||||
key) {
|
||||
mPendingRepaintRequestQueue.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mPendingRepaintRequestMap.insert(key);
|
||||
mPendingRepaintRequestQueue.push_back(aRequest);
|
||||
}
|
||||
|
||||
void APZTaskRunnable::QueueFlushCompleteNotification() {
|
||||
// If we are in test-controlled refreshes mode, notify apz-repaints-flushed
|
||||
// synchronously.
|
||||
if (IsTestControllingRefreshesEnabled()) {
|
||||
// Flush all pending requests and notification just in case the refresh
|
||||
// driver mode was changed before flushing them.
|
||||
Run();
|
||||
if (mController) {
|
||||
RefPtr<GeckoContentController> controller = mController;
|
||||
controller->NotifyFlushComplete();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureRegisterAsEarlyRunner();
|
||||
|
||||
mNeedsFlushCompleteNotification = true;
|
||||
}
|
||||
|
||||
bool APZTaskRunnable::IsRegistereddWithCurrentPresShell() const {
|
||||
MOZ_ASSERT(mController);
|
||||
|
||||
uint32_t current = 0;
|
||||
if (PresShell* presShell = mController->GetTopLevelPresShell()) {
|
||||
current = presShell->GetPresShellId();
|
||||
}
|
||||
return mRegisteredPresShellId == current;
|
||||
}
|
||||
|
||||
void APZTaskRunnable::EnsureRegisterAsEarlyRunner() {
|
||||
if (IsRegistereddWithCurrentPresShell()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the registered presshell id has been changed, we need to discard pending
|
||||
// requests and notification since all of them are for documents which
|
||||
// have been torn down.
|
||||
if (mRegisteredPresShellId) {
|
||||
mPendingRepaintRequestMap.clear();
|
||||
mPendingRepaintRequestQueue.clear();
|
||||
mNeedsFlushCompleteNotification = false;
|
||||
}
|
||||
|
||||
if (PresShell* presShell = mController->GetTopLevelPresShell()) {
|
||||
if (nsRefreshDriver* driver = presShell->GetRefreshDriver()) {
|
||||
driver->AddEarlyRunner(this);
|
||||
mRegisteredPresShellId = presShell->GetPresShellId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool APZTaskRunnable::IsTestControllingRefreshesEnabled() const {
|
||||
if (!mController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PresShell* presShell = mController->GetTopLevelPresShell()) {
|
||||
if (nsRefreshDriver* driver = presShell->GetRefreshDriver()) {
|
||||
return driver->IsTestControllingRefreshesEnabled();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla::layers
|
88
gfx/layers/apz/util/APZTaskRunnable.h
Normal file
88
gfx/layers/apz/util/APZTaskRunnable.h
Normal file
@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_RepaintRequestRunnable_h
|
||||
#define mozilla_layers_RepaintRequestRunnable_h
|
||||
|
||||
#include <deque>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "mozilla/layers/GeckoContentController.h"
|
||||
#include "mozilla/layers/RepaintRequest.h"
|
||||
#include "mozilla/layers/ScrollableLayerGuid.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class GeckoContentController;
|
||||
|
||||
// A runnable invoked in nsRefreshDriver::Tick as an early runnable.
|
||||
class APZTaskRunnable final : public Runnable {
|
||||
public:
|
||||
explicit APZTaskRunnable(GeckoContentController* aController)
|
||||
: Runnable("RepaintRequestRunnable"),
|
||||
mController(aController),
|
||||
mRegisteredPresShellId(0),
|
||||
mNeedsFlushCompleteNotification(false) {}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_DECL_NSIRUNNABLE
|
||||
|
||||
// Queue a RepaintRequest.
|
||||
// If there's already a RepaintRequest having the same scroll id, the old
|
||||
// one will be discarded.
|
||||
void QueueRequest(const RepaintRequest& aRequest);
|
||||
void QueueFlushCompleteNotification();
|
||||
void Revoke() {
|
||||
mController = nullptr;
|
||||
mRegisteredPresShellId = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void EnsureRegisterAsEarlyRunner();
|
||||
bool IsRegistereddWithCurrentPresShell() const;
|
||||
bool IsTestControllingRefreshesEnabled() const;
|
||||
|
||||
// Use a GeckoContentController raw pointer here since the owner of the
|
||||
// GeckoContentController instance (an APZChild instance) holds a strong
|
||||
// reference of this APZTaskRunnable instance and will call Revoke() before
|
||||
// the GeckoContentController gets destroyed in the dtor of the APZChild
|
||||
// instance.
|
||||
GeckoContentController* mController;
|
||||
|
||||
struct RepaintRequestKey {
|
||||
ScrollableLayerGuid::ViewID mScrollId;
|
||||
RepaintRequest::ScrollOffsetUpdateType mScrollUpdateType;
|
||||
bool operator==(const RepaintRequestKey& aOther) const {
|
||||
return mScrollId == aOther.mScrollId &&
|
||||
mScrollUpdateType == aOther.mScrollUpdateType;
|
||||
}
|
||||
struct HashFn {
|
||||
std::size_t operator()(const RepaintRequestKey& aKey) const {
|
||||
return HashGeneric(aKey.mScrollId, aKey.mScrollUpdateType);
|
||||
}
|
||||
};
|
||||
};
|
||||
using RepaintRequests =
|
||||
std::unordered_set<RepaintRequestKey, RepaintRequestKey::HashFn>;
|
||||
// We have an unordered_map and a deque for pending RepaintRequests. The
|
||||
// unordered_map is for quick lookup and the deque is for processing the
|
||||
// pending RepaintRequests in the order we queued.
|
||||
RepaintRequests mPendingRepaintRequestMap;
|
||||
std::deque<RepaintRequest> mPendingRepaintRequestQueue;
|
||||
// This APZTaskRunnable instance is per APZChild instance, which means its
|
||||
// lifetime is tied to the APZChild instance, thus this APZTaskRunnable
|
||||
// instance will be (re-)used for different pres shells so we'd need to
|
||||
// have to remember the pres shell which is currently tied to the APZChild
|
||||
// to deliver queued requests and notifications to the proper pres shell.
|
||||
uint32_t mRegisteredPresShellId;
|
||||
bool mNeedsFlushCompleteNotification;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_layers_RepaintRequestRunnable_h
|
@ -76,6 +76,8 @@ class ChromeProcessController : public mozilla::layers::GeckoContentController {
|
||||
const ScrollableLayerGuid::ViewID& aScrollId) override;
|
||||
void CancelAutoscroll(const ScrollableLayerGuid& aGuid) override;
|
||||
|
||||
PresShell* GetTopLevelPresShell() const override { return GetPresShell(); }
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
RefPtr<APZEventState> mAPZEventState;
|
||||
|
@ -104,5 +104,12 @@ void ContentProcessController::DispatchToRepaintThread(
|
||||
NS_DispatchToMainThread(std::move(aTask));
|
||||
}
|
||||
|
||||
PresShell* ContentProcessController::GetTopLevelPresShell() const {
|
||||
if (!mBrowser) {
|
||||
return nullptr;
|
||||
}
|
||||
return mBrowser->GetTopLevelPresShell();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
@ -76,6 +76,8 @@ class ContentProcessController final : public GeckoContentController {
|
||||
|
||||
void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) override;
|
||||
|
||||
PresShell* GetTopLevelPresShell() const override;
|
||||
|
||||
private:
|
||||
RefPtr<dom::BrowserChild> mBrowser;
|
||||
};
|
||||
|
@ -21,6 +21,10 @@ APZChild::APZChild(RefPtr<GeckoContentController> aController)
|
||||
}
|
||||
|
||||
APZChild::~APZChild() {
|
||||
if (mAPZTaskRunnable) {
|
||||
mAPZTaskRunnable->Revoke();
|
||||
mAPZTaskRunnable = nullptr;
|
||||
}
|
||||
if (mController) {
|
||||
mController->Destroy();
|
||||
mController = nullptr;
|
||||
@ -37,7 +41,9 @@ mozilla::ipc::IPCResult APZChild::RecvRequestContentRepaint(
|
||||
const RepaintRequest& aRequest) {
|
||||
MOZ_ASSERT(mController->IsRepaintThread());
|
||||
|
||||
mController->RequestContentRepaint(aRequest);
|
||||
EnsureAPZTaskRunnable();
|
||||
|
||||
mAPZTaskRunnable->QueueRequest(aRequest);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@ -70,8 +76,10 @@ mozilla::ipc::IPCResult APZChild::RecvNotifyAPZStateChange(
|
||||
|
||||
mozilla::ipc::IPCResult APZChild::RecvNotifyFlushComplete() {
|
||||
MOZ_ASSERT(mController->IsRepaintThread());
|
||||
EnsureAPZTaskRunnable();
|
||||
|
||||
mAPZTaskRunnable->QueueFlushCompleteNotification();
|
||||
|
||||
mController->NotifyFlushComplete();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define mozilla_layers_APZChild_h
|
||||
|
||||
#include "mozilla/layers/PAPZChild.h"
|
||||
#include "mozilla/layers/APZTaskRunnable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -60,7 +61,16 @@ class APZChild final : public PAPZChild {
|
||||
mozilla::ipc::IPCResult RecvDestroy();
|
||||
|
||||
private:
|
||||
void EnsureAPZTaskRunnable() {
|
||||
if (!mAPZTaskRunnable) {
|
||||
mAPZTaskRunnable = new APZTaskRunnable(mController);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<GeckoContentController> mController;
|
||||
// A runnable invoked in a nsRefreshDriver's tick to update multiple
|
||||
// RepaintRequests and notify a "apz-repaints-flushed" at the same time.
|
||||
RefPtr<APZTaskRunnable> mAPZTaskRunnable;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -51,6 +51,7 @@ parent:
|
||||
child:
|
||||
async LayerTransforms(MatrixMessage[] aTransforms);
|
||||
|
||||
[Priority=control]
|
||||
async RequestContentRepaint(RepaintRequest request);
|
||||
|
||||
async UpdateOverscrollVelocity(ScrollableLayerGuid aGuid, float aX, float aY, bool aIsRootContent);
|
||||
@ -61,6 +62,7 @@ child:
|
||||
|
||||
async NotifyAPZStateChange(ScrollableLayerGuid aGuid, GeckoContentController_APZStateChange aChange, int aArg);
|
||||
|
||||
[Priority=control]
|
||||
async NotifyFlushComplete();
|
||||
|
||||
async NotifyAsyncScrollbarDragInitiated(uint64_t aDragBlockId, ViewID aScrollId, ScrollDirection aDirection);
|
||||
|
@ -94,6 +94,7 @@ EXPORTS.mozilla.layers += [
|
||||
"apz/util/ActiveElementManager.h",
|
||||
"apz/util/APZCCallbackHelper.h",
|
||||
"apz/util/APZEventState.h",
|
||||
"apz/util/APZTaskRunnable.h",
|
||||
"apz/util/APZThreadUtils.h",
|
||||
"apz/util/ChromeProcessController.h",
|
||||
"apz/util/ContentProcessController.h",
|
||||
@ -320,6 +321,7 @@ UNIFIED_SOURCES += [
|
||||
"apz/util/ActiveElementManager.cpp",
|
||||
"apz/util/APZCCallbackHelper.cpp",
|
||||
"apz/util/APZEventState.cpp",
|
||||
"apz/util/APZTaskRunnable.cpp",
|
||||
"apz/util/APZThreadUtils.cpp",
|
||||
"apz/util/CheckerboardReportService.cpp",
|
||||
"apz/util/ChromeProcessController.cpp",
|
||||
|
Loading…
x
Reference in New Issue
Block a user