mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Add assertions to verify no-reentry invariants in layout. b=310985 r+sr=bzbarsky
This commit is contained in:
parent
755d917156
commit
637a3c6242
@ -4693,6 +4693,7 @@ nsresult
|
||||
nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
nsIFrame** aNewFrame)
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
NS_PRECONDITION(aNewFrame, "null out param");
|
||||
|
||||
// how the root frame hierarchy should look
|
||||
@ -8196,6 +8197,13 @@ IsRootBoxFrame(nsIFrame *aFrame)
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ReconstructDocElementHierarchy()
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
return ReconstructDocElementHierarchyInternal();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ReconstructDocElementHierarchyInternal()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
@ -8802,6 +8810,7 @@ nsresult
|
||||
nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
||||
PRInt32 aNewIndexInContainer)
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::ContentAppended container=%p index=%d\n",
|
||||
@ -8891,11 +8900,13 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
||||
for (ChildIterator::Init(insertionContent, &iter, &last);
|
||||
iter != last;
|
||||
++iter) {
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
nsIContent* item = nsCOMPtr<nsIContent>(*iter);
|
||||
if (item == child)
|
||||
// Call ContentInserted with this index.
|
||||
ContentInserted(aContainer, child,
|
||||
iter.index(), mTempFrameTreeState, PR_FALSE);
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
}
|
||||
}
|
||||
|
||||
@ -9061,7 +9072,9 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
||||
}
|
||||
|
||||
// We built some new frames. Initialize any newly-constructed bindings.
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
mDocument->BindingManager()->ProcessAttachedQueue();
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
|
||||
// process the current pseudo frame state
|
||||
if (!state.mPseudoFrames.IsEmpty()) {
|
||||
@ -9312,6 +9325,7 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
|
||||
nsILayoutHistoryState* aFrameState,
|
||||
PRBool aInReinsertContent)
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
// XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
|
||||
// the :empty pseudo-class?
|
||||
#ifdef DEBUG
|
||||
@ -9388,7 +9402,9 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
|
||||
#endif
|
||||
}
|
||||
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
mDocument->BindingManager()->ProcessAttachedQueue();
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
|
||||
// otherwise this is not a child of the root element, and we
|
||||
// won't let it have a frame.
|
||||
@ -9607,7 +9623,9 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
|
||||
|
||||
// Now that we've created frames, run the attach queue.
|
||||
//XXXwaterson should we do this after we've processed pseudos, too?
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
mDocument->BindingManager()->ProcessAttachedQueue();
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
|
||||
// process the current pseudo frame state
|
||||
if (!state.mPseudoFrames.IsEmpty())
|
||||
@ -9897,6 +9915,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
||||
PRInt32 aIndexInContainer,
|
||||
PRBool aInReinsertContent)
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
// XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
|
||||
// the :empty pseudo-class?
|
||||
|
||||
@ -10362,6 +10381,7 @@ nsresult
|
||||
nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
|
||||
PRBool aAppend)
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Find the child frame
|
||||
@ -13243,7 +13263,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
|
||||
ReinsertContent(parentContainer, blockContent);
|
||||
}
|
||||
else if (blockContent->GetCurrentDoc() == mDocument) {
|
||||
ReconstructDocElementHierarchy();
|
||||
ReconstructDocElementHierarchyInternal();
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -13303,7 +13323,7 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
|
||||
}
|
||||
|
||||
// If we get here, we're screwed!
|
||||
return ReconstructDocElementHierarchy();
|
||||
return ReconstructDocElementHierarchyInternal();
|
||||
}
|
||||
|
||||
nsresult nsCSSFrameConstructor::RemoveFixedItems(const nsFrameConstructorState& aState)
|
||||
|
@ -193,6 +193,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
nsresult ReconstructDocElementHierarchyInternal();
|
||||
|
||||
nsresult ReinsertContent(nsIContent* aContainer,
|
||||
nsIContent* aChild);
|
||||
|
||||
@ -206,7 +208,6 @@ private:
|
||||
void DoContentStateChanged(nsIContent* aContent,
|
||||
PRInt32 aStateMask);
|
||||
|
||||
private:
|
||||
/* aMinHint is the minimal change that should be made to the element */
|
||||
void RestyleElement(nsIContent* aContent,
|
||||
nsIFrame* aPrimaryFrame,
|
||||
|
@ -121,6 +121,17 @@ enum nsPresContext_CachedIntPrefType {
|
||||
const PRUint8 kPresContext_DefaultVariableFont_ID = 0x00; // kGenericFont_moz_variable
|
||||
const PRUint8 kPresContext_DefaultFixedFont_ID = 0x01; // kGenericFont_moz_fixed
|
||||
|
||||
#ifdef DEBUG
|
||||
struct nsAutoLayoutPhase;
|
||||
|
||||
enum nsLayoutPhase {
|
||||
eLayoutPhase_Paint,
|
||||
eLayoutPhase_Reflow,
|
||||
eLayoutPhase_FrameC,
|
||||
eLayoutPhase_COUNT
|
||||
};
|
||||
#endif
|
||||
|
||||
// An interface for presentation contexts. Presentation contexts are
|
||||
// objects that provide an outer context for a presentation shell.
|
||||
|
||||
@ -762,6 +773,16 @@ protected:
|
||||
eDefaultFont_COUNT
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
private:
|
||||
friend struct nsAutoLayoutPhase;
|
||||
PRUint32 mLayoutPhaseCount[eLayoutPhase_COUNT];
|
||||
public:
|
||||
PRUint32 LayoutPhaseCount(nsLayoutPhase aPhase) {
|
||||
return mLayoutPhaseCount[aPhase];
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
// Bit values for StartLoadImage's aImageStatus
|
||||
@ -769,6 +790,94 @@ protected:
|
||||
#define NS_LOAD_IMAGE_STATUS_SIZE 0x2
|
||||
#define NS_LOAD_IMAGE_STATUS_BITS 0x4
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
struct nsAutoLayoutPhase {
|
||||
nsAutoLayoutPhase(nsPresContext* aPresContext, nsLayoutPhase aPhase)
|
||||
: mPresContext(aPresContext), mPhase(aPhase), mCount(0)
|
||||
{
|
||||
Enter();
|
||||
}
|
||||
|
||||
~nsAutoLayoutPhase()
|
||||
{
|
||||
Exit();
|
||||
NS_ASSERTION(mCount == 0, "imbalanced");
|
||||
}
|
||||
|
||||
void Enter()
|
||||
{
|
||||
switch (mPhase) {
|
||||
case eLayoutPhase_Paint:
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
||||
"recurring into paint");
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
||||
"painting in the middle of reflow");
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
||||
"painting in the middle of frame construction");
|
||||
break;
|
||||
case eLayoutPhase_Reflow:
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
||||
"reflowing in the middle of a paint");
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
||||
"recurring into reflow");
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
||||
"reflowing in the middle of frame construction");
|
||||
break;
|
||||
case eLayoutPhase_FrameC:
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_Paint] == 0,
|
||||
"constructing frames in the middle of a paint");
|
||||
NS_ASSERTION(mPresContext->mLayoutPhaseCount[eLayoutPhase_Reflow] == 0,
|
||||
"constructing frames in the middle of reflow");
|
||||
// The nsXBLService::LoadBindings call in ConstructFrameInternal
|
||||
// makes us hit this one too often to be an NS_ASSERTION,
|
||||
// despite how scary it is.
|
||||
NS_WARN_IF_FALSE(mPresContext->mLayoutPhaseCount[eLayoutPhase_FrameC] == 0,
|
||||
"recurring into frame construction");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
++(mPresContext->mLayoutPhaseCount[mPhase]);
|
||||
++mCount;
|
||||
}
|
||||
|
||||
void Exit()
|
||||
{
|
||||
NS_ASSERTION(mCount > 0 && mPresContext->mLayoutPhaseCount[mPhase] > 0,
|
||||
"imbalanced");
|
||||
--(mPresContext->mLayoutPhaseCount[mPhase]);
|
||||
--mCount;
|
||||
}
|
||||
|
||||
private:
|
||||
nsPresContext *mPresContext;
|
||||
nsLayoutPhase mPhase;
|
||||
PRUint32 mCount;
|
||||
};
|
||||
|
||||
#define AUTO_LAYOUT_PHASE_ENTRY_POINT(pc_, phase_) \
|
||||
nsAutoLayoutPhase autoLayoutPhase((pc_), (eLayoutPhase_##phase_))
|
||||
#define LAYOUT_PHASE_TEMP_EXIT() \
|
||||
PR_BEGIN_MACRO \
|
||||
autoLayoutPhase.Exit(); \
|
||||
PR_END_MACRO
|
||||
#define LAYOUT_PHASE_TEMP_REENTER() \
|
||||
PR_BEGIN_MACRO \
|
||||
autoLayoutPhase.Enter(); \
|
||||
PR_END_MACRO
|
||||
|
||||
#else
|
||||
|
||||
#define AUTO_LAYOUT_PHASE_ENTRY_POINT(pc_, phase_) \
|
||||
PR_BEGIN_MACRO PR_END_MACRO
|
||||
#define LAYOUT_PHASE_TEMP_EXIT() \
|
||||
PR_BEGIN_MACRO PR_END_MACRO
|
||||
#define LAYOUT_PHASE_TEMP_REENTER() \
|
||||
PR_BEGIN_MACRO PR_END_MACRO
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_REFLOW_PERF
|
||||
|
||||
#define DO_GLOBAL_REFLOW_COUNT(_name, _type) \
|
||||
|
@ -2805,6 +2805,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
nsresult rv=CreateRenderingContext(rootFrame, &rcx);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
mIsReflowing = PR_TRUE;
|
||||
|
||||
nsHTMLReflowState reflowState(mPresContext, rootFrame,
|
||||
@ -2952,6 +2953,9 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
|
||||
nsresult rv=CreateRenderingContext(rootFrame, &rcx);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
// XXXldb Set mIsReflowing (and unset it later)?
|
||||
|
||||
nsHTMLReflowState reflowState(mPresContext, rootFrame,
|
||||
eReflowReason_Resize, rcx, maxSize);
|
||||
|
||||
@ -3402,6 +3406,9 @@ PresShell::StyleChangeReflow()
|
||||
nsresult rv=CreateRenderingContext(rootFrame, &rcx);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
// XXXldb Set mIsReflowing (and unset it later)?
|
||||
|
||||
nsHTMLReflowState reflowState(mPresContext, rootFrame,
|
||||
eReflowReason_StyleChange, rcx, maxSize);
|
||||
|
||||
@ -5555,6 +5562,7 @@ PresShell::Paint(nsIView* aView,
|
||||
nsIRenderingContext* aRenderingContext,
|
||||
const nsRegion& aDirtyRegion)
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);
|
||||
nsIFrame* frame;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
@ -6515,6 +6523,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible)
|
||||
mDocument->BeginUpdate(UPDATE_ALL);
|
||||
mDocument->EndUpdate(UPDATE_ALL);
|
||||
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
mIsReflowing = PR_TRUE;
|
||||
|
||||
do {
|
||||
|
Loading…
Reference in New Issue
Block a user