handle dynamic insertion with overflow containers properly, b=403369 r=bzbarsky sr=roc

This commit is contained in:
fantasai.cvs@inkedblade.net 2008-01-27 00:13:19 -08:00
parent 6b498ff79d
commit b81577fea9
19 changed files with 579 additions and 14 deletions

View File

@ -8011,7 +8011,9 @@ nsCSSFrameConstructor::AppendFrames(nsFrameConstructorState& aState,
if (IsFrameSpecial(aParentFrame) &&
!IsInlineFrame(aParentFrame) &&
IsInlineOutside(aFrameList.lastChild)) {
NS_ASSERTION(!aParentFrame->GetNextContinuation(), "Shouldn't happen");
NS_ASSERTION(!aParentFrame->GetNextContinuation() ||
!aParentFrame->GetNextContinuation()->GetFirstChild(nsnull),
"Shouldn't happen");
// We want to put some of the frames into the following inline frame.
nsIFrame* lastBlock = FindLastBlock(aFrameList.childList);
@ -8355,11 +8357,7 @@ nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
// The frame may have a continuation. If so, we want the last
// non-overflow-container continuation as our previous sibling.
sibling = sibling->GetLastContinuation();
while (sibling->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
sibling = sibling->GetPrevInFlow();
NS_ASSERTION(sibling, "first-in-flow can't be overflow container");
}
sibling = sibling->GetTailContinuation();
}
if (aTargetContent &&
@ -8673,8 +8671,8 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
parentFrame = GetLastSpecialSibling(parentFrame);
}
// Get the parent frame's last continuation
parentFrame = parentFrame->GetLastContinuation();
// Get continuation that parents the last child
parentFrame = nsLayoutUtils::GetLastContinuationWithChild(parentFrame);
nsIAtom* frameType = parentFrame->GetType();
// Deal with fieldsets
@ -9121,7 +9119,7 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
nsLayoutUtils::IsGeneratedContentFor(aContainer, firstChild,
nsCSSPseudoElements::before)) {
// Insert the new frames after the last continuation of the :before
prevSibling = firstChild->GetLastContinuation();
prevSibling = firstChild->GetTailContinuation();
parentFrame = prevSibling->GetParent();
// We perhaps could leave this true and take the AppendFrames path
// below, but we'd have to update appendAfterFrame and it seems safer
@ -11174,7 +11172,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForIBSplitterFrame(nsIFrame* aFrame
// Not a kid of the third part of the IB split
GetSpecialSibling(parent) || !IsInlineOutside(parent) ||
// Or not the only child
aFrame->GetLastContinuation()->GetNextSibling() ||
aFrame->GetTailContinuation()->GetNextSibling() ||
aFrame != parent->GetFirstContinuation()->GetFirstChild(nsnull)
)) {
return PR_FALSE;

View File

@ -80,6 +80,19 @@
* A namespace class for static layout utilities.
*/
nsIFrame*
nsLayoutUtils::GetLastContinuationWithChild(nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame, "NULL frame pointer");
aFrame = aFrame->GetLastContinuation();
while (!aFrame->GetFirstChild(nsnull) &&
aFrame->GetPrevContinuation()) {
aFrame = aFrame->GetPrevContinuation();
}
return aFrame;
}
/**
* GetFirstChildFrame returns the first "real" child frame of a
* given frame. It will descend down into pseudo-frames (unless the
@ -121,11 +134,11 @@ GetLastChildFrame(nsIFrame* aFrame,
{
NS_PRECONDITION(aFrame, "NULL frame pointer");
// Get the last continuation frame
nsIFrame* lastContinuation = aFrame->GetLastContinuation();
// Get the last continuation frame that's a parent
nsIFrame* lastParentContinuation = nsLayoutUtils::GetLastContinuationWithChild(aFrame);
// Get the last child frame
nsIFrame* firstChildFrame = lastContinuation->GetFirstChild(nsnull);
nsIFrame* firstChildFrame = lastParentContinuation->GetFirstChild(nsnull);
if (firstChildFrame) {
nsFrameList frameList(firstChildFrame);
nsIFrame* lastChildFrame = frameList.LastChild();

View File

@ -200,6 +200,12 @@ public:
PRInt32 aIf2Ancestor,
nsIFrame* aCommonAncestor = nsnull);
/**
* GetLastContinuationWithChild gets the last continuation in aFrame's chain
* that has a child, or the first continuation if the frame has no children.
*/
static nsIFrame* GetLastContinuationWithChild(nsIFrame* aFrame);
/**
* GetLastSibling simply finds the last sibling of aFrame, or returns nsnull if
* aFrame is null.

View File

@ -3291,6 +3291,22 @@ NS_IMETHODIMP nsFrame::SetNextInFlow(nsIFrame*)
return NS_ERROR_NOT_IMPLEMENTED;
}
nsIFrame* nsIFrame::GetTailContinuation()
{
nsIFrame* frame = this;
while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
frame = frame->GetPrevContinuation();
NS_ASSERTION(frame, "first continuation can't be overflow container");
}
for (nsIFrame* next = frame->GetNextContinuation();
next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
next = frame->GetNextContinuation()) {
frame = next;
}
NS_POSTCONDITION(frame, "illegal state in continuation chain.");
return frame;
}
nsIView*
nsIFrame::GetParentViewForChildFrame(nsIFrame* aFrame) const
{

View File

@ -1058,7 +1058,14 @@ public:
virtual nsIFrame* GetLastContinuation() const {
return const_cast<nsIFrame*>(this);
}
/**
* GetTailContinuation gets the last non-overflow-container continuation
* in the continuation chain, i.e. where the next sibling element
* should attach).
*/
nsIFrame* GetTailContinuation();
/**
* Flow member functions
*/

View File

@ -0,0 +1,40 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in {ib} Pagination with Overflow Containers</title>
<style type="text/css">
#colset {
height: 400px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 200px;
border-bottom: 3px solid blue;
}
#overflow {
height: 1000px;
border-bottom: 3px solid orange;
}
</style>
</head>
<body>
<div id="colset"
><span id="span"
><div id="x"
><div id="overflow"></div
>This must be in the last column, below the orange line.
</div
>This must be in the first column, below the blue line.</span
></div>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in {ib} Pagination with Overflow Containers</title>
<style type="text/css">
#colset {
height: 400px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 200px;
border-bottom: 3px solid blue;
}
#overflow {
height: 1000px;
border-bottom: 3px solid orange;
}
</style>
</head>
<body onload="document.getElementById('span').appendChild(document.createTextNode('This must be in the first column, below the blue line.'))">
<div id="colset"
><span id="span"
><div id="x"
><div id="overflow"></div
>This must be in the last column, below the orange line.
</div
></span
></div>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Paginated Element</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 500px;
}
</style>
</head>
<body>
<div id="colset">
<div id="x">This must be in the first column.</div>
</div>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Paginated Element</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 500px;
}
</style>
</head>
<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the first column.'))">
<div id="colset">
<div id="x"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Pagination</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#mark {
border-bottom: 4px solid blue;
}
#shift {
height: 201px;
border-bottom: 4px solid blue;
}
</style>
</head>
<body>
<div id="colset">
<div id="x">
<div id="shift"></div>
<div id="mark">This must be in the second column between two 4px blue lines.</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Pagination before ::after</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 500px;
}
#x:after {
display: block;
content: "";
border-top: 4px solid blue;
}
#shift {
height: 201px;
border-bottom: 4px solid blue;
}
</style>
</head>
<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the second column between two 4px blue lines.'))">
<div id="colset">
<div id="x">
<div id="shift"></div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,43 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Pagination before ::after (alternate)</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 500px;
}
#x:after {
display: block;
height: 220px;
content: "";
border-top: 4px solid blue;
}
#shift {
height: 201px;
border-bottom: 4px solid blue;
}
</style>
</head>
<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the second column between two 4px blue lines.'))">
<div id="colset">
<div id="x">
<div id="shift"></div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,41 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Inserted in Pagination after ::before</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 500px;
}
#x:before {
display: block;
height: 201px;
content: "";
border-bottom: 4px solid blue;
}
#shift {
height: 220px;
border-top: 4px solid blue;
}
</style>
</head>
<body onload="document.getElementById('x').insertBefore(document.createTextNode('This must be in the second column between two 4px blue lines.'), document.getElementById('shift'))">
<div id="colset">
<div id="x"><div id="shift"></div></div>
</div>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Pagination after ::before</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
border-bottom: 4px solid blue;
}
#x:before {
display: block;
height: 201px;
content: "";
border-bottom: 4px solid blue;
}
</style>
</head>
<body onload="document.getElementById('x').insertBefore(document.createTextNode('This must be in the second column between two 4px blue lines.'), null)">
<div id="colset">
<div id="x">
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,49 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Pagination before ::after (alternate)</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 500px;
}
#x:after {
display: block;
height: 220px;
content: "";
border-top: 4px solid blue;
}
#shift {
height: 201px;
border-bottom: 4px solid blue;
}
#overflow {
height: 700px;
}
</style>
</head>
<body onload="document.getElementById('x').appendChild(document.createTextNode('This must be in the second column between two 4px blue lines.'))">
<div id="colset">
<div id="x">
<div id="shift">
<div id="overflow"></div>
</div
></div>
</div>
</body>
</html>

View File

@ -0,0 +1,48 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Inserted in Pagination after ::before</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#x {
height: 500px;
}
#x:before {
display: block;
height: 201px;
padding: 0 10px;
white-space: pre;
font-size: 100px;
line-height: 1.9em;
color: white;
content: "a\a b\a c\a d\a";
border-bottom: 4px solid blue;
}
#shift {
height: 220px;
border-top: 4px solid blue;
position: relative;
z-index: 1;
}
</style>
</head>
<body onload="document.getElementById('x').insertBefore(document.createTextNode('This must be in the second column between two 4px blue lines.'), document.getElementById('shift'))">
<div id="colset">
<div id="x"><div id="shift"></div></div>
</div>
</body>
</html>

View File

@ -0,0 +1,36 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Pagination before ::after</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#shift {
height: 0;
}
#overflow {
height: 500px;
}
</style>
</head>
<body onload="document.getElementById('colset').insertBefore(document.createTextNode('This must be in the first column.'), document.getElementById('x'))">
<div id="colset">
<div id="shift">
<div id="overflow"></div>
</div
><div id="x">
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Content Appended in Pagination before ::after</title>
<style type="text/css">
#colset {
height: 200px;
width: 450px;
-moz-column-width: 150px;
-moz-column-gap: 0;
border: 3px solid silver;
}
#shift {
height: 201px;
border-bottom: 2px solid blue;
}
#overflow {
height: 500px;
}
div:not([id]) {
border-top: 2px solid blue;
}
#x {
border-bottom: 4px solid blue;
}
</style>
</head>
<body onload="document.getElementById('span').insertBefore(document.createElement('div'), document.getElementById('x'))">
<div id="colset">
<span id="span">
<div id="shift">
<div id="overflow"></div>
</div
><div id="x">This must be in the second column between two 4px blue lines.</div
></span
></div>
</body>
</html>

View File

@ -10,3 +10,13 @@
== border-breaking-002-cols.xhtml border-breaking-002-cols.ref.xhtml
== border-breaking-003-cols.xhtml border-breaking-003-cols.ref.xhtml
== border-breaking-004-cols.xhtml border-breaking-002-cols.ref.xhtml
== content-inserted-000.xhtml content-inserted-000.ref.xhtml
== content-inserted-001.xhtml content-inserted-001.ref.xhtml
== content-inserted-002.xhtml content-inserted-002.ref.xhtml
== content-inserted-003.xhtml content-inserted-002.ref.xhtml
== content-inserted-004.xhtml content-inserted-002.ref.xhtml
== content-inserted-005.xhtml content-inserted-002.ref.xhtml
== content-inserted-006.xhtml content-inserted-002.ref.xhtml
== content-inserted-007.xhtml content-inserted-002.ref.xhtml
== content-inserted-008.xhtml content-inserted-001.ref.xhtml
== content-inserted-009.xhtml content-inserted-002.ref.xhtml