Invalidate the canvas correctly when <body> and root nodes are added to or

removed from documents.  Bug 321751, r+sr=roc
This commit is contained in:
bzbarsky%mit.edu 2006-01-11 02:41:50 +00:00
Родитель 922ae3e21a
Коммит 71e963c9c7
1 изменённых файлов: 99 добавлений и 43 удалений

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

@ -8657,6 +8657,9 @@ GetAdjustedParentFrame(nsIFrame* aParentFrame,
return (newParent) ? newParent : aParentFrame;
}
static void
InvalidateCanvasIfNeeded(nsIFrame* aFrame);
nsresult
nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
@ -8893,10 +8896,14 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
// if the container is a table and a caption was appended, it needs to be put in
// the outer table frame's additional child list.
nsFrameItems captionItems;
// The last frame that we added to the list.
nsIFrame* oldNewFrame = nsnull;
PRUint32 i;
count = aContainer->GetChildCount();
for (i = aNewIndexInContainer; i < count; i++) {
nsIFrame* newFrame = nsnull;
nsIContent *childContent = aContainer->GetChildAt(i);
// lookup the table child frame type as it is much more difficult to remove a frame
// and all it descendants (abs. pos. for instance) than to prevent the frame creation.
@ -8905,11 +8912,12 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
ConstructFrame(state, childContent, parentFrame, tempItems);
if (tempItems.childList) {
if (nsLayoutAtoms::tableCaptionFrame == tempItems.childList->GetType()) {
captionItems.AddChild(tempItems.childList);
captionItems.AddChild(tempItems.childList);
}
else {
frameItems.AddChild(tempItems.childList);
}
newFrame = tempItems.childList;
}
}
else if (nsLayoutAtoms::tableColGroupFrame == frameType) {
@ -8918,12 +8926,17 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
if (childStyleContext->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)
continue; //don't create anything else than columns below a colgroup
ConstructFrame(state, childContent, parentFrame, frameItems);
newFrame = frameItems.lastChild;
}
// Don't create child frames for iframes/frames, they should not
// display any content that they contain.
else if (nsLayoutAtoms::subDocumentFrame != frameType) {
else {
// Construct a child frame (that does not have a table as parent)
ConstructFrame(state, childContent, parentFrame, frameItems);
newFrame = frameItems.lastChild;
}
if (newFrame && newFrame != oldNewFrame) {
InvalidateCanvasIfNeeded(newFrame);
oldNewFrame = newFrame;
}
}
@ -9242,6 +9255,10 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
mDocElementContainingBlock->AppendFrames(nsnull, docElementFrame);
}
if (docElementFrame) {
InvalidateCanvasIfNeeded(docElementFrame);
}
#ifdef DEBUG
if (gReallyNoisyContentUpdates && docElementFrame) {
nsIFrameDebug* fdbg = nsnull;
@ -9461,6 +9478,8 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
ConstructFrame(state, aChild, parentFrame, tempItems);
if (tempItems.childList) {
InvalidateCanvasIfNeeded(tempItems.childList);
if (nsLayoutAtoms::tableCaptionFrame == tempItems.childList->GetType()) {
captionItems.AddChild(tempItems.childList);
}
@ -9571,6 +9590,9 @@ nsCSSFrameConstructor::ReinsertContent(nsIContent* aContainer,
{
PRInt32 ix = aContainer->IndexOf(aChild);
// XXX For now, do a brute force remove and insert.
// XXXbz this probably doesn't work so well with anonymous content
// XXXbz doesn't this need to do the state-saving stuff that
// RecreateFramesForContent does?
nsresult res = ContentRemoved(aContainer, aChild, ix, PR_TRUE);
if (NS_SUCCEEDED(res)) {
@ -9807,6 +9829,8 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
#endif // MOZ_XUL
if (childFrame) {
InvalidateCanvasIfNeeded(childFrame);
// If the frame we are manipulating is a special frame then do
// something different instead of just inserting newly created
// frames.
@ -9999,8 +10023,7 @@ static PRBool gInApplyRenderingChangeToTree = PR_FALSE;
#endif
static void
DoApplyRenderingChangeToTree(nsPresContext* aPresContext,
nsIFrame* aFrame,
DoApplyRenderingChangeToTree(nsIFrame* aFrame,
nsIViewManager* aViewManager,
nsFrameManager* aFrameManager,
nsChangeHint aChange);
@ -10010,8 +10033,8 @@ DoApplyRenderingChangeToTree(nsPresContext* aPresContext,
* This rect is relative to aFrame's parent
*/
static void
UpdateViewsForTree(nsPresContext* aPresContext, nsIFrame* aFrame,
nsIViewManager* aViewManager, nsFrameManager* aFrameManager,
UpdateViewsForTree(nsIFrame* aFrame, nsIViewManager* aViewManager,
nsFrameManager* aFrameManager,
nsRect& aBoundsRect, nsChangeHint aChange)
{
NS_PRECONDITION(gInApplyRenderingChangeToTree,
@ -10023,7 +10046,8 @@ UpdateViewsForTree(nsPresContext* aPresContext, nsIFrame* aFrame,
aViewManager->UpdateView(view, NS_VMREFRESH_NO_SYNC);
}
if (aChange & nsChangeHint_SyncFrameView) {
nsContainerFrame::SyncFrameViewProperties(aPresContext, aFrame, nsnull, view);
nsContainerFrame::SyncFrameViewProperties(aFrame->GetPresContext(),
aFrame, nsnull, view);
}
}
@ -10044,12 +10068,13 @@ UpdateViewsForTree(nsPresContext* aPresContext, nsIFrame* aFrame,
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
NS_ASSERTION(outOfFlowFrame, "no out-of-flow frame");
DoApplyRenderingChangeToTree(aPresContext, outOfFlowFrame,
aViewManager, aFrameManager, aChange);
DoApplyRenderingChangeToTree(outOfFlowFrame, aViewManager,
aFrameManager, aChange);
}
else { // regular frame
nsRect childBounds;
UpdateViewsForTree(aPresContext, child, aViewManager, aFrameManager, childBounds, aChange);
UpdateViewsForTree(child, aViewManager, aFrameManager, childBounds,
aChange);
bounds.UnionRect(bounds, childBounds);
}
}
@ -10063,8 +10088,7 @@ UpdateViewsForTree(nsPresContext* aPresContext, nsIFrame* aFrame,
}
static void
DoApplyRenderingChangeToTree(nsPresContext* aPresContext,
nsIFrame* aFrame,
DoApplyRenderingChangeToTree(nsIFrame* aFrame,
nsIViewManager* aViewManager,
nsFrameManager* aFrameManager,
nsChangeHint aChange)
@ -10078,8 +10102,8 @@ DoApplyRenderingChangeToTree(nsPresContext* aPresContext,
// (adjusting r's coordinate system to reflect the nesting) and
// update there.
nsRect invalidRect;
UpdateViewsForTree(aPresContext, aFrame, aViewManager, aFrameManager,
invalidRect, aChange);
UpdateViewsForTree(aFrame, aViewManager, aFrameManager, invalidRect,
aChange);
if (!aFrame->HasView()
&& (aChange & nsChangeHint_RepaintFrame)) {
@ -10094,7 +10118,6 @@ DoApplyRenderingChangeToTree(nsPresContext* aPresContext,
static void
ApplyRenderingChangeToTree(nsPresContext* aPresContext,
nsIFrame* aFrame,
nsIViewManager* aViewManager,
nsChangeHint aChange)
{
nsIPresShell *shell = aPresContext->PresShell();
@ -10118,10 +10141,7 @@ ApplyRenderingChangeToTree(nsPresContext* aPresContext,
NS_ASSERTION(aFrame, "root frame must paint");
}
nsIViewManager* viewManager = aViewManager;
if (!viewManager) {
viewManager = aPresContext->GetViewManager();
}
nsIViewManager* viewManager = aPresContext->GetViewManager();
// Trigger rendering updates by damaging this frame and any
// continuations of this frame.
@ -10133,8 +10153,8 @@ ApplyRenderingChangeToTree(nsPresContext* aPresContext,
#ifdef DEBUG
gInApplyRenderingChangeToTree = PR_TRUE;
#endif
DoApplyRenderingChangeToTree(aPresContext, aFrame, viewManager,
shell->FrameManager(), aChange);
DoApplyRenderingChangeToTree(aFrame, viewManager, shell->FrameManager(),
aChange);
#ifdef DEBUG
gInApplyRenderingChangeToTree = PR_FALSE;
#endif
@ -10142,6 +10162,59 @@ ApplyRenderingChangeToTree(nsPresContext* aPresContext,
viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
}
/**
* This method invalidates the canvas when frames are removed or added for a
* node that might have its background propagated to the canvas, i.e., a
* document root node or an HTML BODY which is a child of the root node.
*
* @param aFrame a frame for a content node about to be removed or a frme that
* was just created for a content node that was inserted.
*/
static void
InvalidateCanvasIfNeeded(nsIFrame* aFrame)
{
NS_ASSERTION(aFrame, "Must have frame!");
// Note that for both in ContentRemoved and ContentInserted the content node
// will still have the right parent pointer, so looking at that is ok.
nsIContent* node = aFrame->GetContent();
nsIContent* parent = node->GetParent();
if (parent) {
// Has a parent; might not be what we want
nsIContent* grandParent = parent->GetParent();
if (grandParent) {
// Has a grandparent, so not what we want
return;
}
// Check whether it's an HTML body
if (node->Tag() != nsHTMLAtoms::body ||
!node->IsContentOfType(nsIContent::eHTML)) {
return;
}
}
// At this point the node has no parent or it's an HTML <body> child of the
// root. We might not need to invalidate in this case (eg we might be in
// XHTML or something), but chances are we want to. Play it safe. Find the
// frame to invalidate and do it.
nsIFrame *ancestor = aFrame;
const nsStyleBackground *bg;
PRBool isCanvas;
nsPresContext* presContext = aFrame->GetPresContext();
while (!nsCSSRendering::FindBackground(presContext, ancestor,
&bg, &isCanvas)) {
ancestor = ancestor->GetParent();
NS_ASSERTION(ancestor, "canvas must paint");
}
if (ancestor != aFrame) {
ApplyRenderingChangeToTree(presContext, ancestor,
nsChangeHint_RepaintFrame);
}
}
nsresult
nsCSSFrameConstructor::StyleChangeReflow(nsIFrame* aFrame,
nsIAtom* aAttribute)
@ -10332,8 +10405,7 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
StyleChangeReflow(frame, nsnull);
}
if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView)) {
ApplyRenderingChangeToTree(mPresShell->GetPresContext(), frame, nsnull,
hint);
ApplyRenderingChangeToTree(mPresShell->GetPresContext(), frame, hint);
}
if (hint & nsChangeHint_UpdateCursor) {
nsIViewManager* viewMgr = mPresShell->GetViewManager();
@ -11438,27 +11510,10 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent)
// below!)
nsIFrame* frame = mPresShell->GetPrimaryFrameFor(aContent);
nsPresContext* presContext = mPresShell->GetPresContext();
nsresult rv = NS_OK;
if (frame) {
// If the background of the frame is painted on one of its ancestors,
// the frame reconstruct might not invalidate correctly.
nsIFrame *ancestor = frame;
const nsStyleBackground *bg;
PRBool isCanvas;
while (!nsCSSRendering::FindBackground(presContext, ancestor,
&bg, &isCanvas)) {
ancestor = ancestor->GetParent();
NS_ASSERTION(ancestor, "canvas must paint");
}
// This isn't the most efficient way to do it, but it saves code
// size and doesn't add much cost compared to the frame reconstruct.
if (ancestor != frame)
ApplyRenderingChangeToTree(presContext, ancestor, nsnull,
nsChangeHint_RepaintFrame);
// If the frame is an anonymous frame created as part of inline-in-block
// splitting --- or if its parent is such an anonymous frame (i.e., this
// frame might have been the cause of such splitting), then recreate the
@ -11473,6 +11528,7 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent)
nsCOMPtr<nsIContent> container = aContent->GetParent();
if (container) {
// XXXbz what if this is anonymous content?
PRInt32 indexInContainer = container->IndexOf(aContent);
// Before removing the frames associated with the content object,
// ask them to save their state onto a temporary state object.