From 88ef24413f90d52fbe496886f11229f3b435e819 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sat, 6 Sep 2008 20:48:09 +1200 Subject: [PATCH] Bug 422283. Make sure that an overflow container's next-in-flows are always also overflow containers. This means that when we convert a normal frame into an overflow container, we need to scan through its next-in-flows and make them overflow containers too. r=fantasai,sr=mats --- layout/generic/crashtests/422283-1.html | 10 ++++ layout/generic/crashtests/422301-1.html | 24 ++++++++++ layout/generic/crashtests/crashtests.list | 2 + layout/generic/nsContainerFrame.cpp | 58 +++++++++++++++-------- 4 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 layout/generic/crashtests/422283-1.html create mode 100644 layout/generic/crashtests/422301-1.html diff --git a/layout/generic/crashtests/422283-1.html b/layout/generic/crashtests/422283-1.html new file mode 100644 index 00000000000..8f1b9f44f74 --- /dev/null +++ b/layout/generic/crashtests/422283-1.html @@ -0,0 +1,10 @@ + + + + +
+x
+a ! b c
+
+ + diff --git a/layout/generic/crashtests/422301-1.html b/layout/generic/crashtests/422301-1.html new file mode 100644 index 00000000000..8c2f2ef3330 --- /dev/null +++ b/layout/generic/crashtests/422301-1.html @@ -0,0 +1,24 @@ + + + + + + + + + +
This is text
This is textThis is text
This is text
+ + diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index e0e757e3d7a..16c3a1b3884 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -137,6 +137,8 @@ load 416264-1.html load 416476-1.html load 418532-1.html load 421404-1.html +load 422283-1.html +load 422301-1.html load 425253-1.html load 430352-1.html load 448903-1.html diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 472f7261cf2..05d79aef1ca 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -1440,9 +1440,10 @@ nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont, NS_PRECONDITION(aOverflowCont->GetPrevInFlow(), "overflow containers must have a prev-in-flow"); nsresult rv = NS_OK; + PRBool convertedToOverflowContainer = PR_FALSE; + nsPresContext* presContext = aOverflowCont->PresContext(); if (!mSentry || aOverflowCont != mSentry->GetNextInFlow()) { // Not in our list, so we need to add it - nsPresContext* presContext = aOverflowCont->PresContext(); if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) { // aOverflowCont is in some other overflow container list, // steal it first @@ -1455,6 +1456,7 @@ nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont, } else { aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER); + convertedToOverflowContainer = PR_TRUE; } if (!mOverflowContList) { mOverflowContList = new nsFrameList(); @@ -1483,6 +1485,20 @@ nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont, (mPrevOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW) != (aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW)), "OverflowContTracker in unexpected state"); + + if (convertedToOverflowContainer) { + // Convert all non-overflow-container continuations of aOverflowCont + // into overflow containers and move them to our overflow + // tracker. This preserves the invariant that the next-continuations + // of an overflow container are also overflow containers. + nsIFrame* f = aOverflowCont->GetNextContinuation(); + if (f && !(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) { + nsContainerFrame* parent = static_cast(f->GetParent()); + rv = parent->StealFrame(presContext, f); + NS_ENSURE_SUCCESS(rv, rv); + Insert(f, aReflowStatus); + } + } return rv; } @@ -1492,24 +1508,28 @@ nsOverflowContinuationTracker::Finish(nsIFrame* aChild) NS_PRECONDITION(aChild, "null ptr"); NS_PRECONDITION(aChild->GetNextInFlow(), "supposed to call Finish *before* deleting next-in-flow!"); - if (aChild == mSentry) { - // Make sure we drop all references if this was the only frame - // in the overflow containers list - if (mOverflowContList->FirstChild() == aChild->GetNextInFlow() - && !aChild->GetNextInFlow()->GetNextSibling()) { - mOverflowContList = nsnull; - mPrevOverflowCont = nsnull; - mSentry = nsnull; - mParent = static_cast(aChild->GetParent()); - } - else { - // Step past aChild - nsIFrame* prevOverflowCont = mPrevOverflowCont; - StepForward(); - if (mPrevOverflowCont == aChild->GetNextInFlow()) { - // Pull mPrevOverflowChild back to aChild's prevSibling: - // aChild will be removed from our list by our caller - mPrevOverflowCont = prevOverflowCont; + + for (nsIFrame* f = aChild; f; f = f->GetNextInFlow()) { + if (f == mSentry) { + // Make sure we drop all references if this was the only frame + // in the overflow containers list + if (mOverflowContList->FirstChild() == f->GetNextInFlow() + && !f->GetNextInFlow()->GetNextSibling()) { + mOverflowContList = nsnull; + mPrevOverflowCont = nsnull; + mSentry = nsnull; + mParent = static_cast(f->GetParent()); + break; + } + else { + // Step past aChild + nsIFrame* prevOverflowCont = mPrevOverflowCont; + StepForward(); + if (mPrevOverflowCont == f->GetNextInFlow()) { + // Pull mPrevOverflowChild back to aChild's prevSibling: + // aChild will be removed from our list by our caller + mPrevOverflowCont = prevOverflowCont; + } } } }