Bug 539356 - Add to pref to disable painting from the refresh driver. r=roc

This commit is contained in:
Matt Woodrow 2012-08-13 22:11:33 +12:00
parent 247c27d47f
commit 470534c6d3
2 changed files with 119 additions and 40 deletions

View File

@ -1218,8 +1218,9 @@ public:
virtual void SynthesizeMouseMove(bool aFromScroll) = 0; virtual void SynthesizeMouseMove(bool aFromScroll) = 0;
enum PaintType { enum PaintType {
PaintType_Composite, PaintType_Composite, /* Just composite the layers, don't do ThebesLayer painting. */
PaintType_NoComposite PaintType_NoComposite, /* Only paint ThebesLayers, don't composite. */
PaintType_Full /* Do a full transaction. */
}; };
virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion, virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
PaintType aType, bool aWillSendDidPaint) = 0; PaintType aType, bool aWillSendDidPaint) = 0;

View File

@ -24,6 +24,7 @@
#include "mozilla/StartupTimeline.h" #include "mozilla/StartupTimeline.h"
#include "sampler.h" #include "sampler.h"
#include "nsRefreshDriver.h" #include "nsRefreshDriver.h"
#include "mozilla/Preferences.h"
/** /**
XXX TODO XXX XXX TODO XXX
@ -45,6 +46,22 @@
#undef DEBUG_MOUSE_LOCATION #undef DEBUG_MOUSE_LOCATION
static bool
IsRefreshDriverPaintingEnabled()
{
static bool sRefreshDriverPaintingEnabled;
static bool sRefreshDriverPaintingPrefCached = false;
if (!sRefreshDriverPaintingPrefCached) {
sRefreshDriverPaintingPrefCached = true;
mozilla::Preferences::AddBoolVarCache(&sRefreshDriverPaintingEnabled,
"viewmanager.refresh-driver-painting.enabled",
true);
}
return sRefreshDriverPaintingEnabled;
}
PRInt32 nsViewManager::mVMCount = 0; PRInt32 nsViewManager::mVMCount = 0;
// Weakly held references to all of the view managers // Weakly held references to all of the view managers
@ -337,8 +354,13 @@ void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion,
#ifdef DEBUG_INVALIDATIONS #ifdef DEBUG_INVALIDATIONS
printf("--COMPOSITE-- %p\n", mPresShell); printf("--COMPOSITE-- %p\n", mPresShell);
#endif #endif
mPresShell->Paint(aView, damageRegion, nsIPresShell::PaintType_Composite, if (IsRefreshDriverPaintingEnabled()) {
false); mPresShell->Paint(aView, damageRegion, nsIPresShell::PaintType_Composite,
false);
} else {
mPresShell->Paint(aView, damageRegion, nsIPresShell::PaintType_Full,
aWillSendDidPaint);
}
#ifdef DEBUG_INVALIDATIONS #ifdef DEBUG_INVALIDATIONS
printf("--ENDCOMPOSITE--\n"); printf("--ENDCOMPOSITE--\n");
#endif #endif
@ -377,36 +399,40 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
// Push out updates after we've processed the children; ensures that // Push out updates after we've processed the children; ensures that
// damage is applied based on the final widget geometry // damage is applied based on the final widget geometry
if (aFlushDirtyRegion) { if (aFlushDirtyRegion) {
nsIWidget *widget = aView->GetWidget(); if (IsRefreshDriverPaintingEnabled()) {
if (widget && widget->NeedsPaint() && aView->HasNonEmptyDirtyRegion()) { nsIWidget *widget = aView->GetWidget();
FlushDirtyRegionToWidget(aView); if (widget && widget->NeedsPaint() && aView->HasNonEmptyDirtyRegion()) {
// If an ancestor widget was hidden and then shown, we could FlushDirtyRegionToWidget(aView);
// have a delayed resize to handle. // If an ancestor widget was hidden and then shown, we could
for (nsViewManager *vm = this; vm; // have a delayed resize to handle.
vm = vm->mRootView->GetParent() for (nsViewManager *vm = this; vm;
? vm->mRootView->GetParent()->GetViewManager() vm = vm->mRootView->GetParent()
: nullptr) { ? vm->mRootView->GetParent()->GetViewManager()
if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) && : nullptr) {
vm->mRootView->IsEffectivelyVisible() && if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
mPresShell && mPresShell->IsVisible()) { vm->mRootView->IsEffectivelyVisible() &&
vm->FlushDelayedResize(true); mPresShell && mPresShell->IsVisible()) {
vm->InvalidateView(vm->mRootView); vm->FlushDelayedResize(true);
vm->InvalidateView(vm->mRootView);
}
} }
NS_ASSERTION(aView->HasWidget(), "Must have a widget!");
SetPainting(true);
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
#endif
nsAutoScriptBlocker scriptBlocker;
NS_ASSERTION(aView->HasWidget(), "Must have a widget!");
mPresShell->Paint(aView, nsRegion(), nsIPresShell::PaintType_NoComposite, true);
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT END ----\n");
#endif
SetPainting(false);
} }
} else {
NS_ASSERTION(aView->HasWidget(), "Must have a widget!"); FlushDirtyRegionToWidget(aView);
SetPainting(true);
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
#endif
nsAutoScriptBlocker scriptBlocker;
NS_ASSERTION(aView->HasWidget(), "Must have a widget!");
mPresShell->Paint(aView, nsRegion(), nsIPresShell::PaintType_NoComposite, true);
#ifdef DEBUG_INVALIDATIONS
printf("---- PAINT END ----\n");
#endif
SetPainting(false);
} }
} }
} }
@ -734,6 +760,38 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
break; break;
*aStatus = nsEventStatus_eConsumeNoDefault; *aStatus = nsEventStatus_eConsumeNoDefault;
if (!IsRefreshDriverPaintingEnabled()) {
nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
NS_ASSERTION(static_cast<nsView*>(aView) ==
nsView::GetViewFor(event->widget),
"view/widget mismatch");
// If an ancestor widget was hidden and then shown, we could
// have a delayed resize to handle.
for (nsViewManager *vm = this; vm;
vm = vm->mRootView->GetParent()
? vm->mRootView->GetParent()->GetViewManager()
: nullptr) {
if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
vm->mRootView->IsEffectivelyVisible() &&
mPresShell && mPresShell->IsVisible()) {
vm->FlushDelayedResize(true);
vm->InvalidateView(vm->mRootView);
}
}
// Flush things like reflows and plugin widget geometry updates by
// calling WillPaint on observer presShells.
nsRefPtr<nsViewManager> rootVM = RootViewManager();
if (mPresShell) {
rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
}
// Flush view widget geometry updates and invalidations.
rootVM->ProcessPendingUpdates();
}
} }
break; break;
@ -751,6 +809,17 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
"shouldn't be receiving paint events while painting is " "shouldn't be receiving paint events while painting is "
"disallowed!"); "disallowed!");
if (!event->didSendWillPaint && !IsRefreshDriverPaintingEnabled()) {
// Send NS_WILL_PAINT event ourselves.
nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget);
willPaintEvent.willSendDidPaint = event->willSendDidPaint;
DispatchEvent(&willPaintEvent, view, aStatus);
// Get the view pointer again since NS_WILL_PAINT might have
// destroyed it during CallWillPaintOnObservers (bug 378273).
view = nsView::GetViewFor(event->widget);
}
if (!view || event->region.IsEmpty()) if (!view || event->region.IsEmpty())
break; break;
@ -761,6 +830,10 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
} }
case NS_DID_PAINT: { case NS_DID_PAINT: {
if (!IsRefreshDriverPaintingEnabled()) {
nsRefPtr<nsViewManager> rootVM = RootViewManager();
rootVM->CallDidPaintOnObserver();
}
break; break;
} }
@ -1285,17 +1358,22 @@ nsViewManager::ProcessPendingUpdates()
return; return;
} }
mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush(); if (IsRefreshDriverPaintingEnabled()) {
if (mHasPendingUpdates) { mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
mHasPendingUpdates = false; if (mHasPendingUpdates) {
mHasPendingUpdates = false;
// Flush things like reflows and plugin widget geometry updates by // Flush things like reflows and plugin widget geometry updates by
// calling WillPaint on observer presShells. // calling WillPaint on observer presShells.
if (mPresShell) { if (mPresShell) {
CallWillPaintOnObservers(true); CallWillPaintOnObservers(true);
}
ProcessPendingUpdatesForView(mRootView, true);
CallDidPaintOnObserver();
} }
} else if (mHasPendingUpdates) {
ProcessPendingUpdatesForView(mRootView, true); ProcessPendingUpdatesForView(mRootView, true);
CallDidPaintOnObserver(); mHasPendingUpdates = false;
} }
} }