Bug 598482 part 16. When flushing layout, also flush out widget geometry changes. r=roc

This commit is contained in:
Boris Zbarsky 2011-12-23 22:52:23 -05:00
parent 81d739b868
commit 5bdbbbc47c
6 changed files with 54 additions and 19 deletions

View File

@ -3616,6 +3616,9 @@ PresShell::ScheduleViewManagerFlush()
if (presContext) {
presContext->RefreshDriver()->ScheduleViewManagerFlush();
}
if (mDocument) {
mDocument->SetNeedLayoutFlush();
}
}
void
@ -4094,6 +4097,10 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
if (rootPresContext) {
rootPresContext->UpdatePluginGeometry();
}
if (!mIsDestroying) {
mViewManager->UpdateWidgetGeometry();
}
}
}
}

View File

@ -331,6 +331,11 @@ public:
* geometry.
*/
virtual void ProcessPendingUpdates()=0;
/**
* Just update widget geometry without flushing the dirty region
*/
virtual void UpdateWidgetGeometry() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewManager, NS_IVIEWMANAGER_IID)

View File

@ -351,7 +351,7 @@ void nsView::SetPosition(nscoord aX, nscoord aY)
NS_ASSERTION(GetParent() || (aX == 0 && aY == 0),
"Don't try to move the root widget to something non-zero");
ResetWidgetBounds(true, true, false);
ResetWidgetBounds(true, false);
}
void nsIView::SetInvalidationDimensions(const nsRect* aRect)
@ -359,22 +359,23 @@ void nsIView::SetInvalidationDimensions(const nsRect* aRect)
return Impl()->SetInvalidationDimensions(aRect);
}
void nsView::ResetWidgetBounds(bool aRecurse, bool aMoveOnly,
bool aInvalidateChangedSize) {
void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync)
{
if (mWindow) {
// Don't change widget geometry while refresh is disabled, for example
// during reflow. Changing widget sizes can cause synchronous painting
// which is forbidden during reflow.
if (!mViewManager->IsPaintingAllowed()) {
if (!aForceSync) {
// Don't change widget geometry synchronously, since that can
// cause synchronous painting.
mViewManager->PostPendingUpdate();
return;
} else {
DoResetWidgetBounds(false, true);
}
return;
}
DoResetWidgetBounds(aMoveOnly, aInvalidateChangedSize);
} else if (aRecurse) {
if (aRecurse) {
// reposition any widgets under this view
for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
v->ResetWidgetBounds(true, aMoveOnly, aInvalidateChangedSize);
v->ResetWidgetBounds(true, aForceSync);
}
}
}
@ -492,7 +493,7 @@ void nsView::SetDimensions(const nsRect& aRect, bool aPaint, bool aResizeWidget)
mDimBounds = dims;
if (aResizeWidget) {
ResetWidgetBounds(false, false, aPaint);
ResetWidgetBounds(false, false);
}
}

View File

@ -181,7 +181,7 @@ public:
void SetTopMost(bool aTopMost) { aTopMost ? mVFlags |= NS_VIEW_FLAG_TOPMOST : mVFlags &= ~NS_VIEW_FLAG_TOPMOST; }
bool IsTopMost() { return((mVFlags & NS_VIEW_FLAG_TOPMOST) != 0); }
void ResetWidgetBounds(bool aRecurse, bool aMoveOnly, bool aInvalidateChangedSize);
void ResetWidgetBounds(bool aRecurse, bool aForceSync);
void AssertNoWindow();
void NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible);

View File

@ -105,6 +105,7 @@ nsViewManager::nsViewManager()
// NOTE: we use a zeroing operator new, so all data members are
// assumed to be cleared here.
mHasPendingUpdates = false;
mHasPendingWidgetGeometryChanges = false;
mRecursiveRefreshPending = false;
}
@ -395,7 +396,8 @@ void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
}
}
void nsViewManager::ProcessPendingUpdatesForView(nsView* aView)
void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
bool aFlushDirtyRegion)
{
NS_ASSERTION(IsRootVM(), "Updates will be missed");
@ -405,18 +407,20 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView)
}
if (aView->HasWidget()) {
aView->ResetWidgetBounds(false, false, true);
aView->ResetWidgetBounds(false, true);
}
// process pending updates in child view.
for (nsView* childView = aView->GetFirstChild(); childView;
childView = childView->GetNextSibling()) {
ProcessPendingUpdatesForView(childView);
ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
}
// Push out updates after we've processed the children; ensures that
// damage is applied based on the final widget geometry
FlushDirtyRegionToWidget(aView);
if (aFlushDirtyRegion) {
FlushDirtyRegionToWidget(aView);
}
}
void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
@ -459,6 +463,7 @@ nsViewManager::PostPendingUpdate()
{
nsViewManager* rootVM = RootViewManager();
rootVM->mHasPendingUpdates = true;
rootVM->mHasPendingWidgetGeometryChanges = true;
if (rootVM->mPresShell) {
rootVM->mPresShell->ScheduleViewManagerFlush();
}
@ -1362,11 +1367,25 @@ nsViewManager::ProcessPendingUpdates()
}
if (mHasPendingUpdates) {
ProcessPendingUpdatesForView(mRootView);
ProcessPendingUpdatesForView(mRootView, true);
mHasPendingUpdates = false;
}
}
void
nsViewManager::UpdateWidgetGeometry()
{
if (!IsRootVM()) {
RootViewManager()->UpdateWidgetGeometry();
return;
}
if (mHasPendingWidgetGeometryChanges) {
ProcessPendingUpdatesForView(mRootView, false);
mHasPendingWidgetGeometryChanges = false;
}
}
void
nsViewManager::CallWillPaintOnObservers(bool aWillSendDidPaint)
{

View File

@ -145,6 +145,7 @@ public:
void InvalidateHierarchy();
virtual void ProcessPendingUpdates();
virtual void UpdateWidgetGeometry();
protected:
virtual ~nsViewManager();
@ -152,7 +153,8 @@ protected:
private:
void FlushPendingInvalidates();
void ProcessPendingUpdatesForView(nsView *aView);
void ProcessPendingUpdatesForView(nsView *aView,
bool aFlushDirtyRegion = true);
void FlushDirtyRegionToWidget(nsView* aView);
/**
* Call WillPaint() on all view observers under this vm root.
@ -241,6 +243,7 @@ private:
bool mPainting;
bool mRecursiveRefreshPending;
bool mHasPendingUpdates;
bool mHasPendingWidgetGeometryChanges;
bool mInScroll;
//from here to public should be static and locked... MMP