Correctly handle a style change reflow on a subtree that has placeholders with out of flows outside that subtree. (Bug 363247) r+sr=bzbarsky a1.9.0.14=ss

git-svn-id: svn://10.0.0.236/trunk@258035 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
dbaron%dbaron.org
2009-08-10 17:30:01 +00:00
parent 5cbf1a7f64
commit 5a130abdc8
4 changed files with 120 additions and 66 deletions

View File

@@ -3237,88 +3237,106 @@ PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
}
#endif
// Grab |wasDirty| now so we can go ahead and update the bits on aFrame.
PRBool wasDirty = NS_SUBTREE_DIRTY(aFrame);
aFrame->AddStateBits(aBitToAdd);
nsAutoTArray<nsIFrame*, 4> subtrees;
subtrees.AppendElement(aFrame);
// Now if aFrame is a reflow root we can cut off this reflow at it if the bit
// being added is NS_FRAME_HAS_DIRTY_CHILDREN.
PRBool targetFrameDirty = (aBitToAdd == NS_FRAME_IS_DIRTY);
do {
nsIFrame *subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1);
subtrees.RemoveElementAt(subtrees.Length() - 1);
// Grab |wasDirty| now so we can go ahead and update the bits on
// subtreeRoot.
PRBool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot);
subtreeRoot->AddStateBits(aBitToAdd);
// Now if subtreeRoot is a reflow root we can cut off this reflow at it if
// the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN.
PRBool targetFrameDirty = (aBitToAdd == NS_FRAME_IS_DIRTY);
#define FRAME_IS_REFLOW_ROOT(_f) \
((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
(_f != aFrame || !targetFrameDirty))
(_f != subtreeRoot || !targetFrameDirty))
// Mark the intrinsic widths as dirty on the frame, all of its ancestors,
// and all of its descendants, if needed:
// Mark the intrinsic widths as dirty on the frame, all of its ancestors,
// and all of its descendants, if needed:
if (aIntrinsicDirty != eResize) {
// Mark argument and all ancestors dirty. (Unless we hit a reflow root that
// should contain the reflow. That root could be aFrame itself if it's not
// dirty, or it could be some ancestor of aFrame.)
for (nsIFrame *a = aFrame;
a && !FRAME_IS_REFLOW_ROOT(a);
a = a->GetParent())
a->MarkIntrinsicWidthsDirty();
}
if (aIntrinsicDirty != eResize) {
// Mark argument and all ancestors dirty. (Unless we hit a reflow
// root that should contain the reflow. That root could be
// subtreeRoot itself if it's not dirty, or it could be some
// ancestor of subtreeRoot.)
for (nsIFrame *a = subtreeRoot;
a && !FRAME_IS_REFLOW_ROOT(a);
a = a->GetParent())
a->MarkIntrinsicWidthsDirty();
}
if (aIntrinsicDirty == eStyleChange) {
// Mark all descendants dirty (using an nsVoidArray stack rather than
// recursion).
nsVoidArray stack;
stack.AppendElement(aFrame);
if (aIntrinsicDirty == eStyleChange) {
// Mark all descendants dirty (using an nsTArray stack rather than
// recursion).
nsAutoTArray<nsIFrame*, 32> stack;
stack.AppendElement(subtreeRoot);
while (stack.Count() != 0) {
nsIFrame *f =
static_cast<nsIFrame*>(stack.FastElementAt(stack.Count() - 1));
stack.RemoveElementAt(stack.Count() - 1);
PRInt32 childListIndex = 0;
nsIAtom *childListName;
do {
childListName = f->GetAdditionalChildListName(childListIndex++);
for (nsIFrame *kid = f->GetFirstChild(childListName); kid;
kid = kid->GetNextSibling()) {
kid->MarkIntrinsicWidthsDirty();
stack.AppendElement(kid);
nsIFrame *f = stack.ElementAt(stack.Length() - 1);
stack.RemoveElementAt(stack.Length() - 1);
if (f->GetType() == nsGkAtoms::placeholderFrame) {
nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f);
if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) {
// We have another distinct subtree we need to mark.
subtrees.AppendElement(oof);
}
}
} while (childListName);
}
}
// Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty) up the
// tree until we reach either a frame that's already dirty or a reflow root.
nsIFrame *f = aFrame;
for (;;) {
if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
// we've hit a reflow root or the root frame
if (!wasDirty) {
mDirtyRoots.AppendElement(f);
}
PRInt32 childListIndex = 0;
nsIAtom *childListName;
do {
childListName = f->GetAdditionalChildListName(childListIndex++);
for (nsIFrame *kid = f->GetFirstChild(childListName); kid;
kid = kid->GetNextSibling()) {
kid->MarkIntrinsicWidthsDirty();
stack.AppendElement(kid);
}
} while (childListName);
} while (stack.Length() != 0);
}
// Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty)
// up the tree until we reach either a frame that's already dirty or
// a reflow root.
nsIFrame *f = subtreeRoot;
for (;;) {
if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
// we've hit a reflow root or the root frame
if (!wasDirty) {
mDirtyRoots.AppendElement(f);
}
#ifdef DEBUG
else {
VerifyHasDirtyRootAncestor(f);
}
#endif
break;
}
nsIFrame *child = f;
f = f->GetParent();
wasDirty = NS_SUBTREE_DIRTY(f);
f->ChildIsDirty(child);
NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
"ChildIsDirty didn't do its job");
if (wasDirty) {
// This frame was already marked dirty.
#ifdef DEBUG
else {
VerifyHasDirtyRootAncestor(f);
#endif
break;
}
#endif
break;
}
nsIFrame *child = f;
f = f->GetParent();
wasDirty = NS_SUBTREE_DIRTY(f);
f->ChildIsDirty(child);
NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN,
"ChildIsDirty didn't do its job");
if (wasDirty) {
// This frame was already marked dirty.
#ifdef DEBUG
VerifyHasDirtyRootAncestor(f);
#endif
break;
}
}
} while (subtrees.Length() != 0);
PostReflowEvent();

View File

@@ -0,0 +1,15 @@
<html>
<head>
<title>bug 363247</title>
<link rel="stylesheet" href="data:text/css,body {font-size: 20pt}" id="main-css">
</head>
<body>
<table id="table" style="position: absolute; font-size: inherit;">
<tbody>
<tr>
<td>foo</td><td>bar</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<html>
<head>
<title>bug 363247</title>
<link rel="stylesheet" href="data:text/css,body {font-size: 10pt}" id="main-css">
</head>
<body>
<table id="table" style="position: absolute; font-size: inherit;">
<tbody>
<tr>
<td>foo</td><td>bar</td>
</tr>
</tbody>
</table>
<script>
document.body.offsetHeight;
var node = document.getElementById("main-css");
node.setAttribute("href", 'data:text/css,body {font-size: 20pt}');
</script>
</body>
</html>

View File

@@ -381,6 +381,7 @@ skip-if(MOZ_WIDGET_TOOLKIT=="windows") == 347496-1.xhtml 347496-1-ref.xhtml # Bu
== 362594-2b.html 362594-2-standards-ref.html
== 362594-2c.html 362594-2-standards-ref.html
== 362901-1.html 362901-1-ref.html
== 363247-1.html 363247-1-ref.html
== 363329-1.html 363329-1-ref.html
== 363329-2.html 363329-2-ref.html
== 363370-1.html 363370-1-ref.html