Bug 1397426 - Add IPC interface to tell TabChild's to render and clear layers, distinct from setting the active state on the DocShell. r=billm

Originally, setting the active state on the DocShell for remote browsers also did the
work of making the TabChild render its layers and upload them to the compositor.

This patch adds a new renderLayers method to nsITabParent which allows more fine-grained
control - we can now, for example, cause layers to be rendered and uploaded without
activating the DocShell.

Note that if one activates or deactivates the DocShell, we'll still do the work of
attempting to render / clear the layers if it hasn't already been done.

MozReview-Commit-ID: KkLaMDTzfHi

--HG--
extra : rebase_source : 6c53729ae4b07c67d9e3de99c12e1165a85ffaac
extra : source : 261be8ec05542a9e50c0ca03a59a8a44997269b7
This commit is contained in:
Mike Conley 2017-11-03 10:27:05 -04:00
Родитель a5bf8f2796
Коммит 592c9fede9
6 изменённых файлов: 125 добавлений и 69 удалений

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

@ -17,10 +17,21 @@ interface nsITabParent : nsISupports
readonly attribute boolean useAsyncPanZoom;
/**
* Manages the docshell active state of the remote browser.
* Manages the docshell active state of the remote browser. Setting the
* docShell to be active will also cause it to render layers and upload
* them to the compositor. Setting the docShell as not active will clear
* those layers.
*/
attribute boolean docShellIsActive;
/**
* When aEnabled is set to true, this tells the child to paint and
* upload layers to the compositor. When aEnabled is set to false,
* previous layers are cleared from the compositor, but only if
* preserveLayers is also set to false.
*/
void renderLayers(in bool aEnabled);
/**
* Whether this tabParent is in prerender mode.
*/

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

@ -791,11 +791,22 @@ child:
* Whether to activate or deactivate the docshell.
* @param aPreserveLayers
* Whether layer trees should be preserved for inactive docshells.
*/
async SetDocShellIsActive(bool aIsActive);
/**
* 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 aLayerObserverEpoch
* The layer observer epoch for this activation. This message should be
* ignored if this epoch has already been observed (via ForcePaint).
*/
async SetDocShellIsActive(bool aIsActive, bool aPreserveLayers, uint64_t aLayerObserverEpoch);
async RenderLayers(bool aEnabled, uint64_t aLayerObserverEpoch);
/**
* Notify the child that it shouldn't paint the offscreen displayport.

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

@ -436,7 +436,6 @@ TabChild::TabChild(nsIContentChild* aManager,
, mTopLevelDocAccessibleChild(nullptr)
#endif
, mPendingDocShellIsActive(false)
, mPendingDocShellPreserveLayers(false)
, mPendingDocShellReceivedMessage(false)
, mPendingDocShellBlockers(0)
, mWidgetNativeData(0)
@ -2662,8 +2661,7 @@ TabChild::RemovePendingDocShellBlocker()
mPendingDocShellBlockers--;
if (!mPendingDocShellBlockers && mPendingDocShellReceivedMessage) {
mPendingDocShellReceivedMessage = false;
InternalSetDocShellIsActive(mPendingDocShellIsActive,
mPendingDocShellPreserveLayers);
InternalSetDocShellIsActive(mPendingDocShellIsActive);
}
}
@ -2685,15 +2683,52 @@ TabChild::OnDocShellActivated(bool aIsActive)
}
void
TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
TabChild::InternalSetDocShellIsActive(bool aIsActive)
{
// docshell is consider prerendered only if not active yet
mIsPrerendered &= !aIsActive;
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
if (docShell) {
docShell->SetIsActive(aIsActive);
}
}
mozilla::ipc::IPCResult
TabChild::RecvSetDocShellIsActive(const bool& aIsActive)
{
// If we're currently waiting for window opening to complete, we need to hold
// off on setting the docshell active. We queue up the values we're receiving
// in the mWindowOpenDocShellActiveStatus.
if (mPendingDocShellBlockers > 0) {
mPendingDocShellReceivedMessage = true;
mPendingDocShellIsActive = aIsActive;
return IPC_OK();
}
InternalSetDocShellIsActive(aIsActive);
return IPC_OK();
}
mozilla::ipc::IPCResult
TabChild::RecvRenderLayers(const bool& aEnabled, const uint64_t& aLayerObserverEpoch)
{
// Since requests to change the rendering state come in from both the hang
// 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([&] {
// 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 (aIsActive) {
if (aEnabled) {
ProcessHangMonitor::ClearForcePaint();
}
});
@ -2705,34 +2740,26 @@ TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
// We send the current layer observer epoch to the compositor so that
// TabParent knows whether a layer update notification corresponds to the
// latest SetDocShellIsActive request that was made.
// latest RecvRenderLayers request that was made.
lm->SetLayerObserverEpoch(mLayerObserverEpoch);
}
// docshell is consider prerendered only if not active yet
mIsPrerendered &= !aIsActive;
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
if (docShell) {
bool wasActive;
docShell->GetIsActive(&wasActive);
if (aIsActive && wasActive) {
if (aEnabled) {
if (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.
if (IPCOpen()) {
Unused << SendForcePaintNoOp(mLayerObserverEpoch);
return;
return IPC_OK();
}
}
docShell->SetIsActive(aIsActive);
}
if (aIsActive) {
MakeVisible();
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
if (!docShell) {
return;
return IPC_OK();
}
// We don't use TabChildBase::GetPresShell() here because that would create
@ -2740,6 +2767,8 @@ TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
// cause JS to run, which we want to avoid. nsIDocShell::GetPresShell
// returns null if no content viewer exists yet.
if (nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell()) {
presShell->SetIsActive(true);
if (nsIFrame* root = presShell->FrameConstructor()->GetRootFrame()) {
FrameLayerBuilder::InvalidateAllLayersForFrame(
nsLayoutUtils::GetDisplayRootFrame(root));
@ -2763,36 +2792,10 @@ TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
}
APZCCallbackHelper::SuppressDisplayport(false, presShell);
}
} else if (!aPreserveLayers) {
} else {
MakeHidden();
}
}
mozilla::ipc::IPCResult
TabChild::RecvSetDocShellIsActive(const bool& aIsActive,
const bool& aPreserveLayers,
const uint64_t& aLayerObserverEpoch)
{
// Since requests to change the active docshell come in from both the hang
// 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;
// If we're currently waiting for window opening to complete, we need to hold
// off on setting the docshell active. We queue up the values we're receiving
// in the mWindowOpenDocShellActiveStatus.
if (mPendingDocShellBlockers > 0) {
mPendingDocShellReceivedMessage = true;
mPendingDocShellIsActive = aIsActive;
mPendingDocShellPreserveLayers = aPreserveLayers;
return IPC_OK();
}
InternalSetDocShellIsActive(aIsActive, aPreserveLayers);
return IPC_OK();
}
@ -3037,7 +3040,7 @@ TabChild::NotifyPainted()
void
TabChild::MakeVisible()
{
if (mPuppetWidget && mPuppetWidget->IsVisible()) {
if (IsVisible()) {
return;
}
@ -3049,7 +3052,7 @@ TabChild::MakeVisible()
void
TabChild::MakeHidden()
{
if (mPuppetWidget && !mPuppetWidget->IsVisible()) {
if (!IsVisible()) {
return;
}
@ -3063,6 +3066,7 @@ TabChild::MakeHidden()
rootPresContext->ComputePluginGeometryUpdates(rootFrame, nullptr, nullptr);
rootPresContext->ApplyPluginGeometryUpdates();
}
shell->SetIsActive(false);
}
if (mPuppetWidget) {
@ -3070,6 +3074,12 @@ TabChild::MakeHidden()
}
}
bool
TabChild::IsVisible()
{
return mPuppetWidget && mPuppetWidget->IsVisible();
}
NS_IMETHODIMP
TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
{
@ -3558,7 +3568,7 @@ TabChild::ForcePaint(uint64_t aLayerObserverEpoch)
}
nsAutoScriptBlocker scriptBlocker;
RecvSetDocShellIsActive(true, false, aLayerObserverEpoch);
RecvRenderLayers(true, aLayerObserverEpoch);
}
void

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

@ -579,6 +579,7 @@ public:
*/
void MakeVisible();
void MakeHidden();
bool IsVisible();
void OnDocShellActivated(bool aIsActive);
@ -802,9 +803,9 @@ protected:
virtual mozilla::ipc::IPCResult RecvDestroy() override;
virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(const bool& aIsActive,
const bool& aIsHidden,
const uint64_t& aLayerObserverEpoch) 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 RecvNavigateByKey(const bool& aForward,
const bool& aForDocumentNavigation) override;
@ -895,8 +896,7 @@ private:
const ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId);
void InternalSetDocShellIsActive(bool aIsActive,
bool aPreserveLayers);
void InternalSetDocShellIsActive(bool aIsActive);
bool CreateRemoteLayerManager(mozilla::layers::PCompositorBridgeChild* aCompositorChild);
@ -986,7 +986,6 @@ private:
bool mCoalesceMouseMoveEvents;
bool mPendingDocShellIsActive;
bool mPendingDocShellPreserveLayers;
bool mPendingDocShellReceivedMessage;
uint32_t mPendingDocShellBlockers;

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

@ -173,6 +173,7 @@ TabParent::TabParent(nsIContentParent* aManager,
#endif
, mLayerTreeEpoch(0)
, mPreserveLayers(false)
, mRenderingLayers(false)
, mHasPresented(false)
, mHasBeforeUnload(false)
, mIsMouseEnterIntoWidgetEventSuppressed(false)
@ -2902,14 +2903,11 @@ TabParent::GetUseAsyncPanZoom(bool* useAsyncPanZoom)
NS_IMETHODIMP
TabParent::SetDocShellIsActive(bool isActive)
{
// Increment the epoch so that layer tree updates from previous
// SetDocShellIsActive requests are ignored.
mLayerTreeEpoch++;
// docshell is consider prerendered only if not active yet
mIsPrerendered &= !isActive;
mDocShellIsActive = isActive;
Unused << SendSetDocShellIsActive(isActive, mPreserveLayers, mLayerTreeEpoch);
RenderLayers(isActive);
Unused << SendSetDocShellIsActive(isActive);
// update active accessible documents on windows
#if defined(XP_WIN) && defined(ACCESSIBILITY)
@ -2932,13 +2930,6 @@ TabParent::SetDocShellIsActive(bool isActive)
// changing of the process priority.
ProcessPriorityManager::TabActivityChanged(this, isActive);
// Ask the child to repaint using the PHangMonitor channel/thread (which may
// be less congested).
if (isActive) {
ContentParent* cp = Manager()->AsContentParent();
cp->ForceTabPaint(this, mLayerTreeEpoch);
}
return NS_OK;
}
@ -2956,6 +2947,37 @@ TabParent::GetIsPrerendered(bool* aIsPrerendered)
return NS_OK;
}
NS_IMETHODIMP
TabParent::RenderLayers(bool aEnabled)
{
if (aEnabled == mRenderingLayers) {
return NS_OK;
}
// Preserve layers means that attempts to stop rendering layers
// will be ignored.
if (!aEnabled && mPreserveLayers) {
return NS_OK;
}
mRenderingLayers = 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);
}
return NS_OK;
}
NS_IMETHODIMP
TabParent::PreserveLayers(bool aPreserveLayers)
{

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

@ -782,6 +782,9 @@ private:
// the tab's docshell is inactive.
bool mPreserveLayers;
// Holds the most recent value passed to the RenderLayers function.
bool mRenderingLayers;
// True if this TabParent has had its layer tree sent to the compositor
// at least once.
bool mHasPresented;