diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 277e7a322d59..a0d5d5542d1d 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -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
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