Bug 1176019 - Force a paint when switching to a loaded tab r?mconley
This is fairly straightforward, other than the fact that the
nomenclature gets a bit awkward with the aForce parameter on
the ForcePaint methods. I'm not sure which direction to go with
this - "aForce" seems a fairly intuitive name for what we want,
and I'm kind of inclined to say the existing ForcePaint mechanic
should be renamed to something like PaintWithInterrupt, or
PaintWithPriority.
MozReview-Commit-ID: Bj9DROug1pC
--- a/browser/modules/AsyncTabSwitcher.jsm
+++ b/browser/modules/AsyncTabSwitcher.jsm
@@ -974,16 +974,19 @@ class AsyncTabSwitcher {
this._requestingTab = true;
this.logState("requestTab " + this.tinfo(tab));
this.startTabSwitch();
this.requestedTab = tab;
if (tabState == this.STATE_LOADED) {
this.maybeVisibleTabs.clear();
+ if (tab.linkedBrowser.isRemoteBrowser) {
+ tab.linkedBrowser.forceRepaint();
+ }
}
tab.linkedBrowser.setAttribute("primary", "true");
if (this.lastPrimaryTab && this.lastPrimaryTab != tab) {
this.lastPrimaryTab.linkedBrowser.removeAttribute("primary");
}
this.lastPrimaryTab = tab;
--- a/dom/interfaces/base/nsITabParent.idl
+++ b/dom/interfaces/base/nsITabParent.idl
@@ -31,16 +31,23 @@ interface nsITabParent : nsISupports
/**
* True if layers are being rendered and the compositor has reported
* receiving them.
*/
readonly attribute boolean hasLayers;
/**
+ * Sends a message to the child ensuring that they paint as early as
+ * possible. This will send the message to paint even if renderLayers
+ * is already true.
+ */
+ void forceRepaint();
+
+ /**
* As an optimisation, setting the docshell's active state to
* inactive also triggers a layer invalidation to free up some
* potentially unhelpful memory usage. Calling preserveLayers
* will cause the layers to be preserved even for inactive
* docshells.
*/
void preserveLayers(in boolean aPreserveLayers);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5313,22 +5313,27 @@ ContentParent::SendGetFilesResponseAndFo
const GetFilesResponseResult& aResult)
{
if (mGetFilesPendingRequests.Remove(aUUID)) {
Unused << SendGetFilesResponse(aUUID, aResult);
}
}
void
-ContentParent::ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch)
+ContentParent::PaintTabWhileInterruptingJS(TabParent* aTabParent,
+ bool aForceRepaint,
+ uint64_t aLayerObserverEpoch)
{
if (!mHangMonitorActor) {
return;
}
- ProcessHangMonitor::ForcePaint(mHangMonitorActor, aTabParent, aLayerObserverEpoch);
+ ProcessHangMonitor::PaintWhileInterruptingJS(mHangMonitorActor,
+ aTabParent,
+ aForceRepaint,
+ aLayerObserverEpoch);
}
void
ContentParent::UpdateCookieStatus(nsIChannel *aChannel)
{
PNeckoParent *neckoParent = LoneManagedOrNullAsserts(ManagedPNeckoParent());
PCookieServiceParent *csParent = LoneManagedOrNullAsserts(neckoParent->ManagedPCookieServiceParent());
if (csParent) {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -634,17 +634,17 @@ public:
virtual mozilla::ipc::IPCResult
RecvClassifyLocal(const URIParams& aURI,
const nsCString& aTables,
nsresult* aRv,
nsTArray<nsCString>* aResults) override;
// Use the PHangMonitor channel to ask the child to repaint a tab.
- void ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch);
+ void PaintTabWhileInterruptingJS(TabParent* aTabParent, bool aForceRepaint, uint64_t aLayerObserverEpoch);
// This function is called when we are about to load a document from an
// HTTP(S), FTP or wyciwyg channel for a content process. It is a useful
// place to start to kick off work as early as possible in response to such
// document loads.
nsresult AboutToLoadHttpFtpWyciwygDocumentForChild(nsIChannel* aChannel);
nsresult TransmitPermissionsForPrincipal(nsIPrincipal* aPrincipal);
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -555,17 +555,17 @@ parent:
* Child informs the parent that the content is ready to handle input
* events. This is sent when the TabChild is created.
*/
async RemoteIsReadyToHandleInputEvents();
/**
* Child informs the parent that the layer tree is already available.
*/
- async ForcePaintNoOp(uint64_t aLayerObserverEpoch);
+ async PaintWhileInterruptingJSNoOp(uint64_t aLayerObserverEpoch);
/**
* Sent by the child to the parent to inform it that an update to the
* dimensions has been requested, likely through win.moveTo or resizeTo
*/
async SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy);
nested(inside_sync) sync DispatchWheelEvent(WidgetWheelEvent event);
@@ -762,21 +762,25 @@ child:
/**
* If aEnabled is true, tells the child to paint and upload layers to
* the compositor. If aEnabled is false, the child stops painting and
* clears the layers from the compositor.
*
* @param aEnabled
* True if the child should render and upload layers, false if the
* child should clear layers.
+ * @param aForceRepaint
+ * True if the child should force a paint even if it's already
+ * visible.
* @param aLayerObserverEpoch
* The layer observer epoch for this activation. This message should be
- * ignored if this epoch has already been observed (via ForcePaint).
+ * ignored if this epoch has already been observed (via
+ * PaintWhileInterruptingJS).
*/
- async RenderLayers(bool aEnabled, uint64_t aLayerObserverEpoch);
+ async RenderLayers(bool aEnabled, bool aForceRepaint, uint64_t aLayerObserverEpoch);
/**
* Notify the child that it shouldn't paint the offscreen displayport.
* This is useful to speed up interactive operations over async
* scrolling performance like resize, tabswitch, pageload.
*
* Each enable call must be matched with a disable call. The child
* will remain in the suppress mode as long as there's
--- a/dom/ipc/PProcessHangMonitor.ipdl
+++ b/dom/ipc/PProcessHangMonitor.ipdl
@@ -36,12 +36,12 @@ parent:
async ClearHang();
child:
async TerminateScript(bool aTerminateGlobal);
async BeginStartingDebugger();
async EndStartingDebugger();
- async ForcePaint(TabId tabId, uint64_t aLayerObserverEpoch);
+ async PaintWhileInterruptingJS(TabId tabId, bool forceRepaint, uint64_t aLayerObserverEpoch);
};
} // namespace mozilla
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -91,29 +91,31 @@ class HangMonitorChild
bool IsDebuggerStartupComplete();
void NotifyPluginHang(uint32_t aPluginId);
void NotifyPluginHangAsync(uint32_t aPluginId);
void ClearHang();
void ClearHangAsync();
- void ClearForcePaint(uint64_t aLayerObserverEpoch);
+ void ClearPaintWhileInterruptingJS(uint64_t aLayerObserverEpoch);
- // MaybeStartForcePaint will notify the background hang monitor of activity
- // if this is the first time calling it since ClearForcePaint. It should be
+ // MaybeStartPaintWhileInterruptingJS will notify the background hang monitor of activity
+ // if this is the first time calling it since ClearPaintWhileInterruptingJS. It should be
// callable from any thread, but you must be holding mMonitor if using it off
- // the main thread, since it could race with ClearForcePaint.
- void MaybeStartForcePaint();
+ // the main thread, since it could race with ClearPaintWhileInterruptingJS.
+ void MaybeStartPaintWhileInterruptingJS();
mozilla::ipc::IPCResult RecvTerminateScript(const bool& aTerminateGlobal) override;
mozilla::ipc::IPCResult RecvBeginStartingDebugger() override;
mozilla::ipc::IPCResult RecvEndStartingDebugger() override;
- mozilla::ipc::IPCResult RecvForcePaint(const TabId& aTabId, const uint64_t& aLayerObserverEpoch) override;
+ mozilla::ipc::IPCResult RecvPaintWhileInterruptingJS(const TabId& aTabId,
+ const bool& aForceRepaint,
+ const uint64_t& aLayerObserverEpoch) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
void InterruptCallback();
void Shutdown();
static HangMonitorChild* Get() { return sInstance; }
@@ -122,32 +124,33 @@ class HangMonitorChild
mHangMonitor->Dispatch(Move(aRunnable));
}
bool IsOnThread() { return mHangMonitor->IsOnThread(); }
private:
void ShutdownOnThread();
static Atomic<HangMonitorChild*> sInstance;
- UniquePtr<BackgroundHangMonitor> mForcePaintMonitor;
+ UniquePtr<BackgroundHangMonitor> mPaintWhileInterruptingJSMonitor;
const RefPtr<ProcessHangMonitor> mHangMonitor;
Monitor mMonitor;
// Main thread-only.
bool mSentReport;
// These fields must be accessed with mMonitor held.
bool mTerminateScript;
bool mTerminateGlobal;
bool mStartDebugger;
bool mFinishedStartingDebugger;
- bool mForcePaint;
- TabId mForcePaintTab;
- MOZ_INIT_OUTSIDE_CTOR uint64_t mForcePaintEpoch;
+ bool mPaintWhileInterruptingJS;
+ bool mPaintWhileInterruptingJSForce;
+ TabId mPaintWhileInterruptingJSTab;
+ MOZ_INIT_OUTSIDE_CTOR uint64_t mPaintWhileInterruptingJSEpoch;
JSContext* mContext;
bool mShutdownDone;
// This field is only accessed on the hang thread.
bool mIPCOpen;
// Allows us to ensure we NotifyActivity only once, allowing
// either thread to do so.
@@ -222,17 +225,19 @@ public:
mozilla::ipc::IPCResult RecvClearHang() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
void SetProcess(HangMonitoredProcess* aProcess) { mProcess = aProcess; }
void Shutdown();
- void ForcePaint(dom::TabParent* aTabParent, uint64_t aLayerObserverEpoch);
+ void PaintWhileInterruptingJS(dom::TabParent* aTabParent,
+ bool aForceRepaint,
+ uint64_t aLayerObserverEpoch);
void TerminateScript(bool aTerminateGlobal);
void BeginStartingDebugger();
void EndStartingDebugger();
void CleanupPluginHang(uint32_t aPluginId, bool aRemoveFiles);
/**
* Update the dump for the specified plugin. This method is thread-safe and
@@ -253,17 +258,17 @@ private:
void SendHangNotification(const HangData& aHangData,
const nsString& aBrowserDumpId,
bool aTakeMinidump);
void OnTakeFullMinidumpComplete(const HangData& aHangData,
const nsString& aDumpId);
void ClearHangNotification();
- void ForcePaintOnThread(TabId aTabId, uint64_t aLayerObserverEpoch);
+ void PaintWhileInterruptingJSOnThread(TabId aTabId, bool aForceRepaint, uint64_t aLayerObserverEpoch);
void ShutdownOnThread();
const RefPtr<ProcessHangMonitor> mHangMonitor;
// This field is read-only after construction.
bool mReportHangs;
@@ -275,77 +280,81 @@ private:
// Must be accessed with mMonitor held.
RefPtr<HangMonitoredProcess> mProcess;
bool mShutdownDone;
// Map from plugin ID to crash dump ID. Protected by mBrowserCrashDumpHashLock.
nsDataHashtable<nsUint32HashKey, nsString> mBrowserCrashDumpIds;
Mutex mBrowserCrashDumpHashLock;
mozilla::ipc::TaskFactory<HangMonitorParent> mMainThreadTaskFactory;
- static bool sShouldForcePaint;
+ static bool sShouldPaintWhileInterruptingJS;
};
-bool HangMonitorParent::sShouldForcePaint = true;
+bool HangMonitorParent::sShouldPaintWhileInterruptingJS = true;
} // namespace
/* HangMonitorChild implementation */
HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
: mHangMonitor(aMonitor),
mMonitor("HangMonitorChild lock"),
mSentReport(false),
mTerminateScript(false),
mTerminateGlobal(false),
mStartDebugger(false),
mFinishedStartingDebugger(false),
- mForcePaint(false),
+ mPaintWhileInterruptingJS(false),
+ mPaintWhileInterruptingJSForce(false),
mShutdownDone(false),
mIPCOpen(true)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
mContext = danger::GetJSContext();
- mForcePaintMonitor =
+ mPaintWhileInterruptingJSMonitor =
MakeUnique<mozilla::BackgroundHangMonitor>("Gecko_Child_ForcePaint",
128, /* ms timeout for microhangs */
1024, /* ms timeout for permahangs */
BackgroundHangMonitor::THREAD_PRIVATE);
}
HangMonitorChild::~HangMonitorChild()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sInstance == this);
- mForcePaintMonitor = nullptr;
+ mPaintWhileInterruptingJSMonitor = nullptr;
sInstance = nullptr;
}
void
HangMonitorChild::InterruptCallback()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
- bool forcePaint;
- TabId forcePaintTab;
- uint64_t forcePaintEpoch;
+ bool paintWhileInterruptingJS;
+ bool paintWhileInterruptingJSForce;
+ TabId paintWhileInterruptingJSTab;
+ uint64_t paintWhileInterruptingJSEpoch;
{
MonitorAutoLock lock(mMonitor);
- forcePaint = mForcePaint;
- forcePaintTab = mForcePaintTab;
- forcePaintEpoch = mForcePaintEpoch;
+ paintWhileInterruptingJS = mPaintWhileInterruptingJS;
+ paintWhileInterruptingJSForce = mPaintWhileInterruptingJSForce;
+ paintWhileInterruptingJSTab = mPaintWhileInterruptingJSTab;
+ paintWhileInterruptingJSEpoch = mPaintWhileInterruptingJSEpoch;
- mForcePaint = false;
+ mPaintWhileInterruptingJS = false;
}
- if (forcePaint) {
- RefPtr<TabChild> tabChild = TabChild::FindTabChild(forcePaintTab);
+ if (paintWhileInterruptingJS) {
+ RefPtr<TabChild> tabChild = TabChild::FindTabChild(paintWhileInterruptingJSTab);
if (tabChild) {
js::AutoAssertNoContentJS nojs(mContext);
- tabChild->ForcePaint(forcePaintEpoch);
+ tabChild->PaintWhileInterruptingJS(paintWhileInterruptingJSEpoch,
+ paintWhileInterruptingJSForce);
}
}
}
void
HangMonitorChild::Shutdown()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
@@ -410,46 +419,49 @@ HangMonitorChild::RecvEndStartingDebugge
MOZ_RELEASE_ASSERT(IsOnThread());
MonitorAutoLock lock(mMonitor);
mFinishedStartingDebugger = true;
return IPC_OK();
}
mozilla::ipc::IPCResult
-HangMonitorChild::RecvForcePaint(const TabId& aTabId, const uint64_t& aLayerObserverEpoch)
+HangMonitorChild::RecvPaintWhileInterruptingJS(const TabId& aTabId,
+ const bool& aForceRepaint,
+ const uint64_t& aLayerObserverEpoch)
{
MOZ_RELEASE_ASSERT(IsOnThread());
{
MonitorAutoLock lock(mMonitor);
- MaybeStartForcePaint();
- mForcePaint = true;
- mForcePaintTab = aTabId;
- mForcePaintEpoch = aLayerObserverEpoch;
+ MaybeStartPaintWhileInterruptingJS();
+ mPaintWhileInterruptingJS = true;
+ mPaintWhileInterruptingJSForce = aForceRepaint;
+ mPaintWhileInterruptingJSTab = aTabId;
+ mPaintWhileInterruptingJSEpoch = aLayerObserverEpoch;
}
JS_RequestInterruptCallback(mContext);
return IPC_OK();
}
void
-HangMonitorChild::MaybeStartForcePaint()
+HangMonitorChild::MaybeStartPaintWhileInterruptingJS()
{
// See Bug 1449662. The body of this function other than assertions
// has been temporarily removed to diagnose a tab switch spinner
// problem.
if (!NS_IsMainThread()) {
mMonitor.AssertCurrentThreadOwns();
}
}
void
-HangMonitorChild::ClearForcePaint(uint64_t aLayerObserverEpoch)
+HangMonitorChild::ClearPaintWhileInterruptingJS(uint64_t aLayerObserverEpoch)
{
// See Bug 1449662. The body of this function other than assertions
// has been temporarily removed to diagnose a tab switch spinner
// problem.
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(XRE_IsContentProcess());
}
@@ -604,17 +616,17 @@ HangMonitorParent::HangMonitorParent(Pro
mMainThreadTaskFactory(this)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
mReportHangs = mozilla::Preferences::GetBool("dom.ipc.reportProcessHangs", false);
static bool sInited = false;
if (!sInited) {
sInited = true;
- Preferences::AddBoolVarCache(&sShouldForcePaint,
+ Preferences::AddBoolVarCache(&sShouldPaintWhileInterruptingJS,
"browser.tabs.remote.force-paint", true);
}
}
HangMonitorParent::~HangMonitorParent()
{
MutexAutoLock lock(mBrowserCrashDumpHashLock);
@@ -660,37 +672,43 @@ HangMonitorParent::ShutdownOnThread()
}
MonitorAutoLock lock(mMonitor);
mShutdownDone = true;
mMonitor.Notify();
}
void
-HangMonitorParent::ForcePaint(dom::TabParent* aTab, uint64_t aLayerObserverEpoch)
+HangMonitorParent::PaintWhileInterruptingJS(dom::TabParent* aTab,
+ bool aForceRepaint,
+ uint64_t aLayerObserverEpoch)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
- if (sShouldForcePaint) {
+ if (sShouldPaintWhileInterruptingJS) {
TabId id = aTab->GetTabId();
- Dispatch(NewNonOwningRunnableMethod<TabId, uint64_t>(
- "HangMonitorParent::ForcePaintOnThread",
+ Dispatch(NewNonOwningRunnableMethod<TabId, bool, uint64_t>(
+ "HangMonitorParent::PaintWhileInterruptingJSOnThread",
this,
- &HangMonitorParent::ForcePaintOnThread,
+ &HangMonitorParent::PaintWhileInterruptingJSOnThread,
id,
+ aForceRepaint,
aLayerObserverEpoch));
}
}
void
-HangMonitorParent::ForcePaintOnThread(TabId aTabId, uint64_t aLayerObserverEpoch)
+HangMonitorParent::PaintWhileInterruptingJSOnThread(TabId aTabId,
+ bool aForceRepaint,
+ uint64_t aLayerObserverEpoch)
{
MOZ_RELEASE_ASSERT(IsOnThread());
if (mIPCOpen) {
- Unused << SendForcePaint(aTabId, aLayerObserverEpoch);
+ Unused << SendPaintWhileInterruptingJS(aTabId, aForceRepaint,
+ aLayerObserverEpoch);
}
}
void
HangMonitorParent::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_RELEASE_ASSERT(IsOnThread());
mIPCOpen = false;
@@ -1352,38 +1370,39 @@ ProcessHangMonitor::ClearHang()
{
MOZ_ASSERT(NS_IsMainThread());
if (HangMonitorChild* child = HangMonitorChild::Get()) {
child->ClearHang();
}
}
/* static */ void
-ProcessHangMonitor::ForcePaint(PProcessHangMonitorParent* aParent,
- dom::TabParent* aTabParent,
- uint64_t aLayerObserverEpoch)
+ProcessHangMonitor::PaintWhileInterruptingJS(PProcessHangMonitorParent* aParent,
+ dom::TabParent* aTabParent,
+ bool aForceRepaint,
+ uint64_t aLayerObserverEpoch)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
auto parent = static_cast<HangMonitorParent*>(aParent);
- parent->ForcePaint(aTabParent, aLayerObserverEpoch);
+ parent->PaintWhileInterruptingJS(aTabParent, aForceRepaint, aLayerObserverEpoch);
}
/* static */ void
-ProcessHangMonitor::ClearForcePaint(uint64_t aLayerObserverEpoch)
+ProcessHangMonitor::ClearPaintWhileInterruptingJS(uint64_t aLayerObserverEpoch)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(XRE_IsContentProcess());
if (HangMonitorChild* child = HangMonitorChild::Get()) {
- child->ClearForcePaint(aLayerObserverEpoch);
+ child->ClearPaintWhileInterruptingJS(aLayerObserverEpoch);
}
}
/* static */ void
-ProcessHangMonitor::MaybeStartForcePaint()
+ProcessHangMonitor::MaybeStartPaintWhileInterruptingJS()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(XRE_IsContentProcess());
if (HangMonitorChild* child = HangMonitorChild::Get()) {
- child->MaybeStartForcePaint();
+ child->MaybeStartPaintWhileInterruptingJS();
}
}
--- a/dom/ipc/ProcessHangMonitor.h
+++ b/dom/ipc/ProcessHangMonitor.h
@@ -40,21 +40,22 @@ class ProcessHangMonitor final
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static PProcessHangMonitorParent* AddProcess(dom::ContentParent* aContentParent);
static void RemoveProcess(PProcessHangMonitorParent* aParent);
static void ClearHang();
- static void ForcePaint(PProcessHangMonitorParent* aParent,
- dom::TabParent* aTab,
- uint64_t aLayerObserverEpoch);
- static void ClearForcePaint(uint64_t aLayerObserverEpoch);
- static void MaybeStartForcePaint();
+ static void PaintWhileInterruptingJS(PProcessHangMonitorParent* aParent,
+ dom::TabParent* aTab,
+ bool aForceRepaint,
+ uint64_t aLayerObserverEpoch);
+ static void ClearPaintWhileInterruptingJS(uint64_t aLayerObserverEpoch);
+ static void MaybeStartPaintWhileInterruptingJS();
enum SlowScriptAction {
Continue,
Terminate,
StartDebugger,
TerminateGlobal,
};
SlowScriptAction NotifySlowScript(nsITabChild* aTabChild,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2531,17 +2531,19 @@ TabChild::RemovePendingDocShellBlocker()
{
mPendingDocShellBlockers--;
if (!mPendingDocShellBlockers && mPendingDocShellReceivedMessage) {
mPendingDocShellReceivedMessage = false;
InternalSetDocShellIsActive(mPendingDocShellIsActive);
}
if (!mPendingDocShellBlockers && mPendingRenderLayersReceivedMessage) {
mPendingRenderLayersReceivedMessage = false;
- RecvRenderLayers(mPendingRenderLayers, mPendingLayerObserverEpoch);
+ RecvRenderLayers(mPendingRenderLayers,
+ false /* aForceRepaint */,
+ mPendingLayerObserverEpoch);
}
}
void
TabChild::InternalSetDocShellIsActive(bool aIsActive)
{
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
@@ -2562,17 +2564,17 @@ TabChild::RecvSetDocShellIsActive(const
return IPC_OK();
}
InternalSetDocShellIsActive(aIsActive);
return IPC_OK();
}
mozilla::ipc::IPCResult
-TabChild::RecvRenderLayers(const bool& aEnabled, const uint64_t& aLayerObserverEpoch)
+TabChild::RecvRenderLayers(const bool& aEnabled, const bool& aForceRepaint, const uint64_t& aLayerObserverEpoch)
{
if (mPendingDocShellBlockers > 0) {
mPendingRenderLayersReceivedMessage = true;
mPendingRenderLayers = aEnabled;
mPendingLayerObserverEpoch = aLayerObserverEpoch;
return IPC_OK();
}
@@ -2580,49 +2582,49 @@ TabChild::RecvRenderLayers(const bool& a
// monitor channel and the PContent channel, we have an ordering problem. This
// code ensures that we respect the order in which the requests were made and
// ignore stale requests.
if (mLayerObserverEpoch >= aLayerObserverEpoch) {
return IPC_OK();
}
mLayerObserverEpoch = aLayerObserverEpoch;
- auto clearForcePaint = MakeScopeExit([&] {
+ auto clearPaintWhileInterruptingJS = MakeScopeExit([&] {
// We might force a paint, or we might already have painted and this is a
// no-op. In either case, once we exit this scope, we need to alert the
// ProcessHangMonitor that we've finished responding to what might have
// been a request to force paint. This is so that the BackgroundHangMonitor
// for force painting can be made to wait again.
if (aEnabled) {
- ProcessHangMonitor::ClearForcePaint(mLayerObserverEpoch);
+ ProcessHangMonitor::ClearPaintWhileInterruptingJS(mLayerObserverEpoch);
}
});
if (aEnabled) {
- ProcessHangMonitor::MaybeStartForcePaint();
+ ProcessHangMonitor::MaybeStartPaintWhileInterruptingJS();
}
if (mCompositorOptions) {
MOZ_ASSERT(mPuppetWidget);
RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
MOZ_ASSERT(lm);
// We send the current layer observer epoch to the compositor so that
// TabParent knows whether a layer update notification corresponds to the
// latest RecvRenderLayers request that was made.
lm->SetLayerObserverEpoch(mLayerObserverEpoch);
}
if (aEnabled) {
- if (IsVisible()) {
+ if (!aForceRepaint && IsVisible()) {
// This request is a no-op. In this case, we still want a MozLayerTreeReady
// notification to fire in the parent (so that it knows that the child has
- // updated its epoch). ForcePaintNoOp does that.
+ // updated its epoch). PaintWhileInterruptingJSNoOp does that.
if (IPCOpen()) {
- Unused << SendForcePaintNoOp(mLayerObserverEpoch);
+ Unused << SendPaintWhileInterruptingJSNoOp(mLayerObserverEpoch);
return IPC_OK();
}
}
if (!sVisibleTabs) {
sVisibleTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
}
sVisibleTabs->PutEntry(this);
@@ -3441,26 +3443,27 @@ ScreenIntRect
TabChild::GetOuterRect()
{
LayoutDeviceIntRect outerRect =
RoundedToInt(mUnscaledOuterRect * mPuppetWidget->GetDefaultScale());
return ViewAs<ScreenPixel>(outerRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
}
void
-TabChild::ForcePaint(uint64_t aLayerObserverEpoch)
+TabChild::PaintWhileInterruptingJS(uint64_t aLayerObserverEpoch,
+ bool aForceRepaint)
{
if (!IPCOpen() || !mPuppetWidget || !mPuppetWidget->HasLayerManager()) {
// Don't bother doing anything now. Better to wait until we receive the
// message on the PContent channel.
return;
}
nsAutoScriptBlocker scriptBlocker;
- RecvRenderLayers(true, aLayerObserverEpoch);
+ RecvRenderLayers(true /* aEnabled */, aForceRepaint, aLayerObserverEpoch);
}
void
TabChild::BeforeUnloadAdded()
{
// Don't bother notifying the parent if we don't have an IPC link open.
if (mBeforeUnloadListeners == 0 && IPCOpen()) {
SendSetHasBeforeUnload(true);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -650,17 +650,18 @@ public:
const int& aArg);
void StartScrollbarDrag(const layers::AsyncDragMetrics& aDragMetrics);
void ZoomToRect(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const CSSRect& aRect,
const uint32_t& aFlags);
// Request that the docshell be marked as active.
- void ForcePaint(uint64_t aLayerObserverEpoch);
+ void PaintWhileInterruptingJS(uint64_t aLayerObserverEpoch,
+ bool aForceRepaint);
#if defined(XP_WIN) && defined(ACCESSIBILITY)
uintptr_t GetNativeWindowHandle() const { return mNativeWindowHandle; }
#endif
// These methods return `true` if this TabChild is currently awaiting a
// Large-Allocation header.
bool StopAwaitingLargeAlloc();
@@ -723,17 +724,17 @@ protected:
virtual PRenderFrameChild* AllocPRenderFrameChild() override;
virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
virtual mozilla::ipc::IPCResult RecvDestroy() override;
virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(const bool& aIsActive) override;
- virtual mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled, const uint64_t& aLayerObserverEpoch) override;
+ virtual mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled, const bool& aForce, const uint64_t& aLayerObserverEpoch) override;
virtual mozilla::ipc::IPCResult RecvNavigateByKey(const bool& aForward,
const bool& aForDocumentNavigation) override;
virtual mozilla::ipc::IPCResult RecvRequestNotifyAfterRemotePaint() override;
virtual mozilla::ipc::IPCResult RecvSuppressDisplayport(const bool& aEnabled) override;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2926,29 +2926,17 @@ TabParent::SetRenderLayers(bool aEnabled
// Preserve layers means that attempts to stop rendering layers
// will be ignored.
if (!aEnabled && mPreserveLayers) {
return NS_OK;
}
mRenderLayers = aEnabled;
- // Increment the epoch so that layer tree updates from previous
- // RenderLayers requests are ignored.
- mLayerTreeEpoch++;
-
- Unused << SendRenderLayers(aEnabled, mLayerTreeEpoch);
-
- // Ask the child to repaint using the PHangMonitor channel/thread (which may
- // be less congested).
- if (aEnabled) {
- ContentParent* cp = Manager()->AsContentParent();
- cp->ForceTabPaint(this, mLayerTreeEpoch);
- }
-
+ SetRenderLayersInternal(aEnabled, false /* aForceRepaint */);
return NS_OK;
}
NS_IMETHODIMP
TabParent::GetRenderLayers(bool* aResult)
{
*aResult = mRenderLayers;
return NS_OK;
@@ -2957,16 +2945,41 @@ TabParent::GetRenderLayers(bool* aResult
NS_IMETHODIMP
TabParent::GetHasLayers(bool* aResult)
{
*aResult = mHasLayers;
return NS_OK;
}
NS_IMETHODIMP
+TabParent::ForceRepaint()
+{
+ SetRenderLayersInternal(true /* aEnabled */,
+ true /* aForceRepaint */);
+ return NS_OK;
+}
+
+void
+TabParent::SetRenderLayersInternal(bool aEnabled, bool aForceRepaint)
+{
+ // Increment the epoch so that layer tree updates from previous
+ // RenderLayers requests are ignored.
+ mLayerTreeEpoch++;
+
+ Unused << SendRenderLayers(aEnabled, aForceRepaint, mLayerTreeEpoch);
+
+ // Ask the child to repaint using the PHangMonitor channel/thread (which may
+ // be less congested).
+ if (aEnabled) {
+ ContentParent* cp = Manager()->AsContentParent();
+ cp->PaintTabWhileInterruptingJS(this, aForceRepaint, mLayerTreeEpoch);
+ }
+}
+
+NS_IMETHODIMP
TabParent::PreserveLayers(bool aPreserveLayers)
{
mPreserveLayers = aPreserveLayers;
return NS_OK;
}
NS_IMETHODIMP
TabParent::SuppressDisplayport(bool aEnabled)
@@ -3074,19 +3087,19 @@ TabParent::LayerTreeUpdate(uint64_t aEpo
event->InitEvent(NS_LITERAL_STRING("MozLayerTreeCleared"), true, false);
}
event->SetTrusted(true);
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
mFrameElement->DispatchEvent(*event);
}
mozilla::ipc::IPCResult
-TabParent::RecvForcePaintNoOp(const uint64_t& aLayerObserverEpoch)
+TabParent::RecvPaintWhileInterruptingJSNoOp(const uint64_t& aLayerObserverEpoch)
{
- // We sent a ForcePaint message when layers were already visible. In this
+ // We sent a PaintWhileInterruptingJS message when layers were already visible. In this
// case, we should act as if an update occurred even though we already have
// the layers.
LayerTreeUpdate(aLayerObserverEpoch, true);
return IPC_OK();
}
mozilla::ipc::IPCResult
TabParent::RecvRemotePaintIsReady()
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -620,17 +620,17 @@ protected:
virtual PRenderFrameParent* AllocPRenderFrameParent() override;
virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) override;
virtual mozilla::ipc::IPCResult RecvRemotePaintIsReady() override;
virtual mozilla::ipc::IPCResult RecvRemoteIsReadyToHandleInputEvents() override;
- virtual mozilla::ipc::IPCResult RecvForcePaintNoOp(const uint64_t& aLayerObserverEpoch) override;
+ virtual mozilla::ipc::IPCResult RecvPaintWhileInterruptingJSNoOp(const uint64_t& aLayerObserverEpoch) override;
virtual mozilla::ipc::IPCResult RecvSetDimensions(const uint32_t& aFlags,
const int32_t& aX, const int32_t& aY,
const int32_t& aCx, const int32_t& aCy) override;
virtual mozilla::ipc::IPCResult RecvGetTabCount(uint32_t* aValue) override;
virtual mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(const nsCString& aFirstPartyURI) override;
@@ -646,16 +646,18 @@ protected:
bool mUpdatedDimensions;
nsSizeMode mSizeMode;
LayoutDeviceIntPoint mClientOffset;
LayoutDeviceIntPoint mChromeOffset;
private:
void DestroyInternal();
+ void SetRenderLayersInternal(bool aEnabled, bool aForceRepaint);
+
already_AddRefed<nsFrameLoader>
GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy = false) const;
RefPtr<nsIContentParent> mManager;
void TryCacheDPIAndScale();
bool AsyncPanZoomEnabled() const;
--- a/toolkit/content/widgets/remote-browser.xml
+++ b/toolkit/content/widgets/remote-browser.xml
@@ -261,16 +261,27 @@
if (frameLoader && frameLoader.tabParent) {
return frameLoader.tabParent.renderLayers = val;
}
return false;
]]>
</setter>
</property>
+ <method name="forceRepaint">
+ <body>
+ <![CDATA[
+ let {frameLoader} = this;
+ if (frameLoader && frameLoader.tabParent) {
+ frameLoader.tabParent.forceRepaint();
+ }
+ ]]>
+ </body>
+ </method>
+
<property name="hasLayers" readonly="true">
<getter><![CDATA[
let {frameLoader} = this;
if (frameLoader.tabParent) {
return frameLoader.tabParent.hasLayers;
}
return false;
]]></getter>