Bug 90205. Rather than recreating the {ib} frames for a style-change reflow, retarget the reflow at the {ib}'s containing block. Clean up logic in ReframeContainingBlock(). r=karnaze, sr=attinasi

This commit is contained in:
waterson%netscape.com 2001-07-24 20:24:15 +00:00
Родитель 4381fc9986
Коммит 9bc9aa7389
2 изменённых файлов: 134 добавлений и 126 удалений

Просмотреть файл

@ -372,6 +372,24 @@ SetFrameIsSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame, nsIFrame* aS
} }
} }
static nsIFrame*
GetIBContainingBlockFor(nsIFrame* aFrame)
{
// Get the first "normal" ancestor of the target frame.
NS_PRECONDITION(IsFrameSpecial(aFrame),
"GetIBContainingBlockFor() should only be called on known IB frames");
nsIFrame* parentFrame;
do {
aFrame->GetParent(&parentFrame);
if (!parentFrame || !IsFrameSpecial(parentFrame))
break;
aFrame = parentFrame;
} while (1);
return aFrame;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -9591,30 +9609,26 @@ nsCSSFrameConstructor::StyleChangeReflow(nsIPresContext* aPresContext,
nsBoxLayoutState state(aPresContext); nsBoxLayoutState state(aPresContext);
box->MarkStyleChange(state); box->MarkStyleChange(state);
} }
else if (IsFrameSpecial(aFrame)) {
// We are pretty harsh here (and definitely not optimal) -- we
// wipe out the entire containing block and recreate it from
// scratch. The reason is that because we know that a special
// inline frame has propogated some of its children upward to be
// children of the block and that those frames may need to move
// around. This logic guarantees a correct answer.
ReframeContainingBlock(aPresContext, aFrame);
}
else { else {
// If the frame is part of a split block-in-inline hierarchy, then
// target the style-change reflow at the first ``normal'' ancestor
// so we're sure that the style change will propagate to any
// anonymously created siblings.
if (IsFrameSpecial(aFrame))
aFrame = GetIBContainingBlockFor(aFrame);
// Target a style-change reflow at the frame.
nsCOMPtr<nsIPresShell> shell; nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell)); aPresContext->GetShell(getter_AddRefs(shell));
nsCOMPtr<nsIReflowCommand> reflowCmd;
nsIReflowCommand* reflowCmd; rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), aFrame,
rv = NS_NewHTMLReflowCommand(&reflowCmd, aFrame,
nsIReflowCommand::StyleChanged, nsIReflowCommand::StyleChanged,
nsnull, nsnull,
aAttribute); aAttribute);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv))
shell->AppendReflowCommand(reflowCmd); shell->AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
} }
return NS_OK; return NS_OK;
@ -9998,13 +10012,13 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext,
// apply changes // apply changes
if (primaryFrame && aHint == NS_STYLE_HINT_ATTRCHANGE) if (primaryFrame && aHint == NS_STYLE_HINT_ATTRCHANGE)
result = primaryFrame->AttributeChanged(aPresContext, aContent, aNameSpaceID, aAttribute, aHint); result = primaryFrame->AttributeChanged(aPresContext, aContent, aNameSpaceID, aAttribute, aHint);
else if (PR_TRUE == reconstruct) { else if (reconstruct) {
result = ReconstructDocElementHierarchy(aPresContext); result = ReconstructDocElementHierarchy(aPresContext);
} }
else if (PR_TRUE == reframe) { else if (reframe) {
result = RecreateFramesForContent(aPresContext, aContent, inlineStyle, rule, styleContext); result = RecreateFramesForContent(aPresContext, aContent, inlineStyle, rule, styleContext);
} }
else if (PR_TRUE == restyle) { else if (restyle) {
if (inlineStyle) { if (inlineStyle) {
if (styleContext) { if (styleContext) {
nsCOMPtr<nsIRuleNode> ruleNode; nsCOMPtr<nsIRuleNode> ruleNode;
@ -13379,55 +13393,45 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIPresContext* aPresContext, nsIF
} }
#endif #endif
// Get the first "normal" parent of the target frame. From there we // Get the first "normal" ancestor of the target frame.
// look for the containing block in case the target frame is already nsIFrame* parentFrame = GetIBContainingBlockFor(aFrame);
// a block (which can happen when an inline frame wraps some of its if (parentFrame) {
// content in an anonymous block; see ConstructInline) // From here we look for the containing block in case the target
nsIFrame* parentFrame; // frame is already a block (which can happen when an inline frame
do { // wraps some of its content in an anonymous block; see
aFrame->GetParent(&parentFrame); // ConstructInline)
if (!parentFrame || !IsFrameSpecial(parentFrame)) //
break; // XXXwaterson I don't think this extra step is necessary: we
// should just be able to recreate the frames starting from the IB
aFrame = parentFrame; // containing block.
} while (1); nsIFrame* containingBlock = GetFloaterContainingBlock(aPresContext, aFrame);
if (containingBlock) {
// And get the containingBlock's content
if (!parentFrame) { nsCOMPtr<nsIContent> blockContent;
return RecreateEntireFrameTree(aPresContext); containingBlock->GetContent(getter_AddRefs(blockContent));
} if (blockContent) {
// Now find the containingBlock's content's parent
// Now find the containing block nsCOMPtr<nsIContent> parentContainer;
nsIFrame* containingBlock = GetFloaterContainingBlock(aPresContext, parentFrame); blockContent->GetParent(*getter_AddRefs(parentContainer));
if (!containingBlock) { if (parentContainer) {
return RecreateEntireFrameTree(aPresContext);
}
// And get the containingBlock's content
nsCOMPtr<nsIContent> blockContent;
containingBlock->GetContent(getter_AddRefs(blockContent));
if (!blockContent) {
return RecreateEntireFrameTree(aPresContext);
}
// Now find the containingBlock's content's parent
nsCOMPtr<nsIContent> parentContainer;
blockContent->GetParent(*getter_AddRefs(parentContainer));
if (!parentContainer) {
return RecreateEntireFrameTree(aPresContext);
}
#ifdef DEBUG #ifdef DEBUG
if (gNoisyContentUpdates) { if (gNoisyContentUpdates) {
printf(" ==> blockContent=%p, parentContainer=%p\n", printf(" ==> blockContent=%p, parentContainer=%p\n",
blockContent.get(), parentContainer.get()); blockContent.get(), parentContainer.get());
} }
#endif #endif
PRInt32 ix; PRInt32 ix;
parentContainer->IndexOf(blockContent, ix); parentContainer->IndexOf(blockContent, ix);
nsresult rv = ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix); return ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix);
return rv; }
}
}
}
// If we get here, we're screwed!
return RecreateEntireFrameTree(aPresContext);
} }
nsresult nsresult

Просмотреть файл

@ -372,6 +372,24 @@ SetFrameIsSpecial(nsIFrameManager* aFrameManager, nsIFrame* aFrame, nsIFrame* aS
} }
} }
static nsIFrame*
GetIBContainingBlockFor(nsIFrame* aFrame)
{
// Get the first "normal" ancestor of the target frame.
NS_PRECONDITION(IsFrameSpecial(aFrame),
"GetIBContainingBlockFor() should only be called on known IB frames");
nsIFrame* parentFrame;
do {
aFrame->GetParent(&parentFrame);
if (!parentFrame || !IsFrameSpecial(parentFrame))
break;
aFrame = parentFrame;
} while (1);
return aFrame;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -9591,30 +9609,26 @@ nsCSSFrameConstructor::StyleChangeReflow(nsIPresContext* aPresContext,
nsBoxLayoutState state(aPresContext); nsBoxLayoutState state(aPresContext);
box->MarkStyleChange(state); box->MarkStyleChange(state);
} }
else if (IsFrameSpecial(aFrame)) {
// We are pretty harsh here (and definitely not optimal) -- we
// wipe out the entire containing block and recreate it from
// scratch. The reason is that because we know that a special
// inline frame has propogated some of its children upward to be
// children of the block and that those frames may need to move
// around. This logic guarantees a correct answer.
ReframeContainingBlock(aPresContext, aFrame);
}
else { else {
// If the frame is part of a split block-in-inline hierarchy, then
// target the style-change reflow at the first ``normal'' ancestor
// so we're sure that the style change will propagate to any
// anonymously created siblings.
if (IsFrameSpecial(aFrame))
aFrame = GetIBContainingBlockFor(aFrame);
// Target a style-change reflow at the frame.
nsCOMPtr<nsIPresShell> shell; nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell)); aPresContext->GetShell(getter_AddRefs(shell));
nsCOMPtr<nsIReflowCommand> reflowCmd;
nsIReflowCommand* reflowCmd; rv = NS_NewHTMLReflowCommand(getter_AddRefs(reflowCmd), aFrame,
rv = NS_NewHTMLReflowCommand(&reflowCmd, aFrame,
nsIReflowCommand::StyleChanged, nsIReflowCommand::StyleChanged,
nsnull, nsnull,
aAttribute); aAttribute);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv))
shell->AppendReflowCommand(reflowCmd); shell->AppendReflowCommand(reflowCmd);
NS_RELEASE(reflowCmd);
}
} }
return NS_OK; return NS_OK;
@ -9998,13 +10012,13 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext,
// apply changes // apply changes
if (primaryFrame && aHint == NS_STYLE_HINT_ATTRCHANGE) if (primaryFrame && aHint == NS_STYLE_HINT_ATTRCHANGE)
result = primaryFrame->AttributeChanged(aPresContext, aContent, aNameSpaceID, aAttribute, aHint); result = primaryFrame->AttributeChanged(aPresContext, aContent, aNameSpaceID, aAttribute, aHint);
else if (PR_TRUE == reconstruct) { else if (reconstruct) {
result = ReconstructDocElementHierarchy(aPresContext); result = ReconstructDocElementHierarchy(aPresContext);
} }
else if (PR_TRUE == reframe) { else if (reframe) {
result = RecreateFramesForContent(aPresContext, aContent, inlineStyle, rule, styleContext); result = RecreateFramesForContent(aPresContext, aContent, inlineStyle, rule, styleContext);
} }
else if (PR_TRUE == restyle) { else if (restyle) {
if (inlineStyle) { if (inlineStyle) {
if (styleContext) { if (styleContext) {
nsCOMPtr<nsIRuleNode> ruleNode; nsCOMPtr<nsIRuleNode> ruleNode;
@ -13379,55 +13393,45 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIPresContext* aPresContext, nsIF
} }
#endif #endif
// Get the first "normal" parent of the target frame. From there we // Get the first "normal" ancestor of the target frame.
// look for the containing block in case the target frame is already nsIFrame* parentFrame = GetIBContainingBlockFor(aFrame);
// a block (which can happen when an inline frame wraps some of its if (parentFrame) {
// content in an anonymous block; see ConstructInline) // From here we look for the containing block in case the target
nsIFrame* parentFrame; // frame is already a block (which can happen when an inline frame
do { // wraps some of its content in an anonymous block; see
aFrame->GetParent(&parentFrame); // ConstructInline)
if (!parentFrame || !IsFrameSpecial(parentFrame)) //
break; // XXXwaterson I don't think this extra step is necessary: we
// should just be able to recreate the frames starting from the IB
aFrame = parentFrame; // containing block.
} while (1); nsIFrame* containingBlock = GetFloaterContainingBlock(aPresContext, aFrame);
if (containingBlock) {
// And get the containingBlock's content
if (!parentFrame) { nsCOMPtr<nsIContent> blockContent;
return RecreateEntireFrameTree(aPresContext); containingBlock->GetContent(getter_AddRefs(blockContent));
} if (blockContent) {
// Now find the containingBlock's content's parent
// Now find the containing block nsCOMPtr<nsIContent> parentContainer;
nsIFrame* containingBlock = GetFloaterContainingBlock(aPresContext, parentFrame); blockContent->GetParent(*getter_AddRefs(parentContainer));
if (!containingBlock) { if (parentContainer) {
return RecreateEntireFrameTree(aPresContext);
}
// And get the containingBlock's content
nsCOMPtr<nsIContent> blockContent;
containingBlock->GetContent(getter_AddRefs(blockContent));
if (!blockContent) {
return RecreateEntireFrameTree(aPresContext);
}
// Now find the containingBlock's content's parent
nsCOMPtr<nsIContent> parentContainer;
blockContent->GetParent(*getter_AddRefs(parentContainer));
if (!parentContainer) {
return RecreateEntireFrameTree(aPresContext);
}
#ifdef DEBUG #ifdef DEBUG
if (gNoisyContentUpdates) { if (gNoisyContentUpdates) {
printf(" ==> blockContent=%p, parentContainer=%p\n", printf(" ==> blockContent=%p, parentContainer=%p\n",
blockContent.get(), parentContainer.get()); blockContent.get(), parentContainer.get());
} }
#endif #endif
PRInt32 ix; PRInt32 ix;
parentContainer->IndexOf(blockContent, ix); parentContainer->IndexOf(blockContent, ix);
nsresult rv = ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix); return ContentReplaced(aPresContext, parentContainer, blockContent, blockContent, ix);
return rv; }
}
}
}
// If we get here, we're screwed!
return RecreateEntireFrameTree(aPresContext);
} }
nsresult nsresult