mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 577607 part 2. Teach the refresh driver to flush restyles and reflow on more than one presshell. r=roc
This commit is contained in:
parent
d9188b16ef
commit
657e764de8
@ -171,6 +171,8 @@ RestyleTracker::ProcessRestyles()
|
||||
// processing restyles
|
||||
mFrameConstructor->BeginUpdate();
|
||||
|
||||
mFrameConstructor->mInStyleRefresh = PR_TRUE;
|
||||
|
||||
// loop so that we process any restyle events generated by processing
|
||||
while (mPendingRestyles.Count()) {
|
||||
if (mHaveLaterSiblingRestyles) {
|
||||
|
@ -1374,9 +1374,6 @@ MoveChildrenTo(nsPresContext* aPresContext,
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ADDREF(nsCSSFrameConstructor)
|
||||
NS_IMPL_RELEASE(nsCSSFrameConstructor)
|
||||
|
||||
nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
|
||||
nsIPresShell *aPresShell)
|
||||
: mDocument(aDocument)
|
||||
@ -1395,7 +1392,6 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
|
||||
, mHasRootAbsPosContainingBlock(PR_FALSE)
|
||||
, mObservingRefreshDriver(PR_FALSE)
|
||||
, mInStyleRefresh(PR_FALSE)
|
||||
, mInLazyFCRefresh(PR_FALSE)
|
||||
, mHoverGeneration(0)
|
||||
, mRebuildAllExtraHint(nsChangeHint(0))
|
||||
, mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
|
||||
@ -6360,8 +6356,6 @@ void nsCSSFrameConstructor::CreateNeededFrames()
|
||||
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
||||
"Someone forgot a script blocker");
|
||||
|
||||
mInLazyFCRefresh = PR_FALSE;
|
||||
|
||||
Element* rootElement = mDocument->GetRootElement();
|
||||
NS_ASSERTION(!rootElement || !rootElement->HasFlag(NODE_NEEDS_FRAME),
|
||||
"root element should not have frame created lazily");
|
||||
@ -8284,12 +8278,11 @@ nsCSSFrameConstructor::WillDestroyFrameTree()
|
||||
mQuoteList.Clear();
|
||||
mCounterManager.Clear();
|
||||
|
||||
// Remove ourselves as a refresh observer, so the refresh driver
|
||||
// won't assert about us. But leave mObservingRefreshDriver true so
|
||||
// we don't readd to it even if someone tries to post restyle events
|
||||
// on us from this point on for some reason.
|
||||
// Remove our presshell as a style flush observer. But leave
|
||||
// mObservingRefreshDriver true so we don't readd to it even if someone tries
|
||||
// to post restyle events on us from this point on for some reason.
|
||||
mPresShell->GetPresContext()->RefreshDriver()->
|
||||
RemoveRefreshObserver(this, Flush_Style);
|
||||
RemoveStyleFlushObserver(mPresShell);
|
||||
}
|
||||
|
||||
//STATIC
|
||||
@ -11673,26 +11666,13 @@ nsCSSFrameConstructor::PostRestyleEventInternal(PRBool aForLazyConstruction)
|
||||
// Make sure we're not in a style refresh; if we are, we still have
|
||||
// a call to ProcessPendingRestyles coming and there's no need to
|
||||
// add ourselves as a refresh observer until then.
|
||||
PRBool inRefresh = aForLazyConstruction ? mInLazyFCRefresh : mInStyleRefresh;
|
||||
PRBool inRefresh = !aForLazyConstruction && mInStyleRefresh;
|
||||
if (!mObservingRefreshDriver && !inRefresh) {
|
||||
mObservingRefreshDriver = mPresShell->AddRefreshObserver(this, Flush_Style);
|
||||
mObservingRefreshDriver = mPresShell->GetPresContext()->RefreshDriver()->
|
||||
AddStyleFlushObserver(mPresShell);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
NS_ASSERTION(mObservingRefreshDriver, "How did we get here?");
|
||||
// Stop observing the refresh driver and flag ourselves as being in
|
||||
// a refresh so we don't restart due to animation-triggered
|
||||
// restyles. The actual work of processing our restyles will get
|
||||
// done when the refresh driver flushes styles.
|
||||
mPresShell->RemoveRefreshObserver(this, Flush_Style);
|
||||
mObservingRefreshDriver = PR_FALSE;
|
||||
mInLazyFCRefresh = PR_TRUE;
|
||||
mInStyleRefresh = PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
|
||||
{
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsPageContentFrame.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "RestyleTracker.h"
|
||||
|
||||
class nsIDocument;
|
||||
@ -72,6 +71,7 @@ class ChildIterator;
|
||||
class nsICSSAnonBoxPseudo;
|
||||
class nsPageContentFrame;
|
||||
struct PendingBinding;
|
||||
class nsRefreshDriver;
|
||||
|
||||
typedef void (nsLazyFrameConstructionCallback)
|
||||
(nsIContent* aContent, nsIFrame* aFrame, void* aArg);
|
||||
@ -79,8 +79,10 @@ typedef void (nsLazyFrameConstructionCallback)
|
||||
class nsFrameConstructorState;
|
||||
class nsFrameConstructorSaveState;
|
||||
|
||||
class nsCSSFrameConstructor : public nsARefreshObserver
|
||||
class nsCSSFrameConstructor
|
||||
{
|
||||
friend class nsRefreshDriver;
|
||||
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
typedef mozilla::css::RestyleTracker RestyleTracker;
|
||||
@ -90,15 +92,6 @@ public:
|
||||
NS_ASSERTION(mUpdateCount == 0, "Dying in the middle of our own update?");
|
||||
}
|
||||
|
||||
// Matches signature on nsARefreshObserver. Just like
|
||||
// NS_DECL_ISUPPORTS, but without the QI part.
|
||||
NS_IMETHOD_(nsrefcnt) AddRef(void);
|
||||
NS_IMETHOD_(nsrefcnt) Release(void);
|
||||
protected:
|
||||
nsAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
public:
|
||||
|
||||
struct RestyleData;
|
||||
friend struct RestyleData;
|
||||
|
||||
@ -351,9 +344,6 @@ public:
|
||||
{
|
||||
PostRestyleEventCommon(aElement, aRestyleHint, aMinChangeHint, PR_TRUE);
|
||||
}
|
||||
|
||||
// nsARefreshObserver
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime);
|
||||
private:
|
||||
/**
|
||||
* Notify the frame constructor that an element needs to have its
|
||||
@ -1871,9 +1861,6 @@ private:
|
||||
PRPackedBool mObservingRefreshDriver : 1;
|
||||
// True if we're in the middle of a nsRefreshDriver refresh
|
||||
PRPackedBool mInStyleRefresh : 1;
|
||||
// True if we're in the middle of a nsRefreshDriver refresh and haven't yet
|
||||
// called CreateNeededFrames
|
||||
PRPackedBool mInLazyFCRefresh : 1;
|
||||
PRUint32 mHoverGeneration;
|
||||
nsChangeHint mRebuildAllExtraHint;
|
||||
|
||||
|
@ -1093,6 +1093,8 @@ public:
|
||||
static void ReleaseStatics();
|
||||
|
||||
protected:
|
||||
friend class nsRefreshDriver;
|
||||
|
||||
// IMPORTANT: The ownership implicit in the following member variables
|
||||
// has been explicitly checked. If you add any members to this class,
|
||||
// please make the ownership explicit (pinkerton, scc).
|
||||
@ -1102,7 +1104,7 @@ protected:
|
||||
nsIDocument* mDocument; // [STRONG]
|
||||
nsPresContext* mPresContext; // [STRONG]
|
||||
nsStyleSet* mStyleSet; // [OWNS]
|
||||
nsCSSFrameConstructor* mFrameConstructor; // [STRONG]
|
||||
nsCSSFrameConstructor* mFrameConstructor; // [OWNS]
|
||||
nsIViewManager* mViewManager; // [WEAK] docViewer owns it so I don't have to
|
||||
nsFrameSelection* mSelection;
|
||||
nsFrameManagerBase mFrameManager; // [OWNS]
|
||||
@ -1140,6 +1142,13 @@ protected:
|
||||
|
||||
PRPackedBool mObservesMutationsForPrint;
|
||||
|
||||
PRPackedBool mReflowScheduled; // If true, we have a reflow
|
||||
// scheduled. Guaranteed to be
|
||||
// false if mReflowContinueTimer
|
||||
// is non-null.
|
||||
|
||||
PRPackedBool mSuppressInterruptibleReflows;
|
||||
|
||||
// A list of weak frames. This is a pointer to the last item in the list.
|
||||
nsWeakFrame* mWeakFrames;
|
||||
|
||||
|
@ -673,7 +673,7 @@ struct nsCallbackEventRequest
|
||||
#define ASSERT_REFLOW_SCHEDULED_STATE() \
|
||||
NS_ASSERTION(mReflowScheduled == \
|
||||
GetPresContext()->RefreshDriver()-> \
|
||||
IsRefreshObserver(this, Flush_Layout), "Unexpected state")
|
||||
IsLayoutFlushObserver(this), "Unexpected state")
|
||||
|
||||
class nsPresShellEventCB;
|
||||
class nsAutoCauseReflowNotifier;
|
||||
@ -681,8 +681,7 @@ class nsAutoCauseReflowNotifier;
|
||||
class PresShell : public nsIPresShell, public nsIViewObserver,
|
||||
public nsStubDocumentObserver,
|
||||
public nsISelectionController, public nsIObserver,
|
||||
public nsSupportsWeakReference,
|
||||
public nsARefreshObserver
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
PresShell();
|
||||
@ -913,9 +912,6 @@ public:
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
// nsARefreshObserver
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime);
|
||||
|
||||
#ifdef MOZ_REFLOW_PERF
|
||||
virtual NS_HIDDEN_(void) DumpReflows();
|
||||
virtual NS_HIDDEN_(void) CountReflows(const char * aName, nsIFrame * aFrame);
|
||||
@ -1217,16 +1213,11 @@ protected:
|
||||
nsCallbackEventRequest* mFirstCallbackEventRequest;
|
||||
nsCallbackEventRequest* mLastCallbackEventRequest;
|
||||
|
||||
PRPackedBool mSuppressInterruptibleReflows;
|
||||
|
||||
PRPackedBool mIsDocumentGone; // We've been disconnected from the document.
|
||||
// We will refuse to paint the document until either
|
||||
// (a) our timer fires or (b) all frames are constructed.
|
||||
PRPackedBool mShouldUnsuppressPainting; // Indicates that it is safe to unlock painting once all pending
|
||||
// reflows have been processed.
|
||||
PRPackedBool mReflowScheduled; // If true, we have a reflow scheduled.
|
||||
// Guaranteed to be false if
|
||||
// mReflowContinueTimer is non-null.
|
||||
nsCOMPtr<nsITimer> mPaintSuppressionTimer; // This timer controls painting suppression. Until it fires
|
||||
// or all frames are constructed, we won't paint anything but
|
||||
// our <body> background and scrollbars.
|
||||
@ -1645,7 +1636,7 @@ PresShell::~PresShell()
|
||||
#endif
|
||||
|
||||
delete mStyleSet;
|
||||
NS_IF_RELEASE(mFrameConstructor);
|
||||
delete mFrameConstructor;
|
||||
|
||||
mCurrentEventContent = nsnull;
|
||||
|
||||
@ -1694,7 +1685,6 @@ PresShell::Init(nsIDocument* aDocument,
|
||||
// Create our frame constructor.
|
||||
mFrameConstructor = new nsCSSFrameConstructor(mDocument, this);
|
||||
NS_ENSURE_TRUE(mFrameConstructor, NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(mFrameConstructor);
|
||||
|
||||
// The document viewer owns both view manager and pres shell.
|
||||
mViewManager->SetViewObserver(this);
|
||||
@ -1942,7 +1932,7 @@ PresShell::Destroy()
|
||||
// Revoke any pending events. We need to do this and cancel pending reflows
|
||||
// before we destroy the frame manager, since apparently frame destruction
|
||||
// sometimes spins the event queue when plug-ins are involved(!).
|
||||
rd->RemoveRefreshObserver(this, Flush_Layout);
|
||||
rd->RemoveLayoutFlushObserver(this);
|
||||
mResizeEvent.Revoke();
|
||||
if (mAsyncResizeTimerIsActive) {
|
||||
mAsyncResizeEventTimer->Cancel();
|
||||
@ -3583,7 +3573,7 @@ PresShell::CancelAllPendingReflows()
|
||||
mDirtyRoots.Clear();
|
||||
|
||||
if (mReflowScheduled) {
|
||||
GetPresContext()->RefreshDriver()->RemoveRefreshObserver(this, Flush_Layout);
|
||||
GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
|
||||
mReflowScheduled = PR_FALSE;
|
||||
}
|
||||
|
||||
@ -7346,20 +7336,6 @@ PresShell::Thaw()
|
||||
QueryIsActive();
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
// Remove ourselves as a refresh observer; we'll readd during the
|
||||
// flush if needed.
|
||||
GetPresContext()->RefreshDriver()->RemoveRefreshObserver(this, Flush_Layout);
|
||||
mReflowScheduled = PR_FALSE;
|
||||
// Allow interruptible reflows now, since that's what the refresh
|
||||
// driver will issue.
|
||||
mSuppressInterruptibleReflows = PR_FALSE;
|
||||
|
||||
ASSERT_REFLOW_SCHEDULED_STATE();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Start of protected and private methods on the PresShell
|
||||
//--------------------------------------------------------
|
||||
@ -7385,7 +7361,7 @@ PresShell::ScheduleReflow()
|
||||
NS_PRECONDITION(!mReflowScheduled, "Why are we trying to schedule a reflow?");
|
||||
ASSERT_REFLOW_SCHEDULED_STATE();
|
||||
|
||||
if (GetPresContext()->RefreshDriver()->AddRefreshObserver(this, Flush_Layout)) {
|
||||
if (GetPresContext()->RefreshDriver()->AddLayoutFlushObserver(this)) {
|
||||
mReflowScheduled = PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "prlog.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
@ -140,6 +141,8 @@ nsRefreshDriver::ObserverCount() const
|
||||
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mObservers); ++i) {
|
||||
sum += mObservers[i].Length();
|
||||
}
|
||||
sum += mStyleFlushObservers.Length();
|
||||
sum += mLayoutFlushObservers.Length();
|
||||
return sum;
|
||||
}
|
||||
|
||||
@ -215,13 +218,25 @@ nsRefreshDriver::Notify(nsITimer * /* unused */)
|
||||
}
|
||||
if (i == 0) {
|
||||
// This is the Flush_Style case.
|
||||
// FIXME: Maybe we should only flush if the WillRefresh calls did
|
||||
// something? It's probably ok as-is, though, especially as we
|
||||
// hook up more things here (or to the replacement of this class).
|
||||
presShell->FlushPendingNotifications(Flush_Style);
|
||||
while (!mStyleFlushObservers.IsEmpty() &&
|
||||
mPresContext && mPresContext->GetPresShell()) {
|
||||
PRUint32 idx = mStyleFlushObservers.Length() - 1;
|
||||
nsCOMPtr<nsIPresShell> shell = mStyleFlushObservers[idx];
|
||||
mStyleFlushObservers.RemoveElementAt(idx);
|
||||
shell->FrameConstructor()->mObservingRefreshDriver = PR_FALSE;
|
||||
shell->FlushPendingNotifications(Flush_Style);
|
||||
}
|
||||
} else if (i == 1) {
|
||||
// This is the Flush_Layout case.
|
||||
presShell->FlushPendingNotifications(Flush_InterruptibleLayout);
|
||||
while (!mLayoutFlushObservers.IsEmpty() &&
|
||||
mPresContext && mPresContext->GetPresShell()) {
|
||||
PRUint32 idx = mLayoutFlushObservers.Length() - 1;
|
||||
nsCOMPtr<nsIPresShell> shell = mLayoutFlushObservers[idx];
|
||||
mLayoutFlushObservers.RemoveElementAt(idx);
|
||||
shell->mReflowScheduled = PR_FALSE;
|
||||
shell->mSuppressInterruptibleReflows = PR_FALSE;
|
||||
shell->FlushPendingNotifications(Flush_InterruptibleLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,10 @@
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
|
||||
/**
|
||||
* An abstract base class to be implemented by callers wanting to be
|
||||
@ -111,6 +113,33 @@ public:
|
||||
PRBool RemoveRefreshObserver(nsARefreshObserver *aObserver,
|
||||
mozFlushType aFlushType);
|
||||
|
||||
/**
|
||||
* Add / remove presshells that we should flush style and layout on
|
||||
*/
|
||||
PRBool AddStyleFlushObserver(nsIPresShell* aShell) {
|
||||
NS_ASSERTION(!mStyleFlushObservers.Contains(aShell),
|
||||
"Double-adding style flush observer");
|
||||
PRBool appended = mStyleFlushObservers.AppendElement(aShell) != nsnull;
|
||||
EnsureTimerStarted();
|
||||
return appended;
|
||||
}
|
||||
void RemoveStyleFlushObserver(nsIPresShell* aShell) {
|
||||
mStyleFlushObservers.RemoveElement(aShell);
|
||||
}
|
||||
PRBool AddLayoutFlushObserver(nsIPresShell* aShell) {
|
||||
NS_ASSERTION(!IsLayoutFlushObserver(aShell),
|
||||
"Double-adding layout flush observer");
|
||||
PRBool appended = mLayoutFlushObservers.AppendElement(aShell) != nsnull;
|
||||
EnsureTimerStarted();
|
||||
return appended;
|
||||
}
|
||||
void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
|
||||
mLayoutFlushObservers.RemoveElement(aShell);
|
||||
}
|
||||
PRBool IsLayoutFlushObserver(nsIPresShell* aShell) {
|
||||
return mLayoutFlushObservers.Contains(aShell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the refresh driver that it is done driving refreshes and
|
||||
* should stop its timer and forget about its pres context. This may
|
||||
@ -162,6 +191,8 @@ private:
|
||||
|
||||
// separate arrays for each flush type we support
|
||||
ObserverArray mObservers[3];
|
||||
nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
|
||||
nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
|
||||
};
|
||||
|
||||
#endif /* !defined(nsRefreshDriver_h_) */
|
||||
|
Loading…
Reference in New Issue
Block a user