diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index cb70187ade6..46aece26a63 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1190,6 +1190,7 @@ public: NS_DISPLAY_DECL_NAME("Clip") nsRect GetClipRect() { return mClip; } + void SetClipRect(const nsRect& aRect) { mClip = aRect; } virtual nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index c91e51fe2ed..f253a06471e 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -824,6 +824,101 @@ void nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder, aCtx->FillRect(aDirtyRect); } +/** + * Remove all leaf display items that are not for descendants of + * aBuilder->GetReferenceFrame() from aList, and move all nsDisplayClip + * wrappers to their correct locations. + * @param aExtraPage the page we constructed aList for + * @param aY the Y-coordinate where aPage would be positioned relative + * to the main page (aBuilder->GetReferenceFrame()), considering only + * the content and ignoring page margins and dead space + * @param aList the list that is modified in-place + */ +static void +PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, + nsIFrame* aExtraPage, nscoord aY, nsDisplayList* aList) +{ + nsDisplayList newList; + // The page which we're really constructing a display list for + nsIFrame* mainPage = aBuilder->ReferenceFrame(); + + while (PR_TRUE) { + nsDisplayItem* i = aList->RemoveBottom(); + if (!i) + break; + nsDisplayList* subList = i->GetList(); + if (subList) { + PruneDisplayListForExtraPage(aBuilder, aExtraPage, aY, subList); + if (i->GetType() == nsDisplayItem::TYPE_CLIP) { + // This might clip an element which should appear on the first + // page, and that element might be visible if this uses a 'clip' + // property with a negative top. + // The clip area needs to be moved because the frame geometry doesn't + // put page content frames for adjacent pages vertically adjacent, + // there are page margins and dead space between them in print + // preview, and in printing all pages are at (0,0)... + // XXX we have no way to test this right now that I know of; + // the 'clip' property requires an abs-pos element and we never + // paint abs-pos elements that start after the main page + // (bug 426909). + nsDisplayClip* clip = static_cast(i); + clip->SetClipRect(clip->GetClipRect() + nsPoint(0, aY) - + aExtraPage->GetOffsetTo(mainPage)); + } + newList.AppendToTop(i); + } else { + nsIFrame* f = i->GetUnderlyingFrame(); + if (f && nsLayoutUtils::IsProperAncestorFrameCrossDoc(mainPage, f)) { + // This one is in the page we care about, keep it + newList.AppendToTop(i); + } else { + // We're throwing this away so call its destructor now. The memory + // is owned by aBuilder which destroys all items at once. + i->nsDisplayItem::~nsDisplayItem(); + } + } + } + aList->AppendToTop(&newList); +} + +static nsresult +BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, + nsIFrame* aPage, nscoord aY, nsDisplayList* aList) +{ + nsDisplayList list; + // Pass an empty dirty rect since we're only interested in finding + // placeholders whose out-of-flows are in the page + // aBuilder->GetReferenceFrame(), and the paths to those placeholders + // have already been marked as NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO. + // Note that we should still do a prune step since we don't want to + // rely on dirty-rect checking for correctness. + nsresult rv = aPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list); + if (NS_FAILED(rv)) + return rv; + PruneDisplayListForExtraPage(aBuilder, aPage, aY, &list); + aList->AppendToTop(&list); + return NS_OK; +} + +static nsIFrame* +GetNextPage(nsIFrame* aPageContentFrame) +{ + // XXX ugh + nsIFrame* pageFrame = aPageContentFrame->GetParent(); + NS_ASSERTION(pageFrame->GetType() == nsGkAtoms::pageFrame, + "pageContentFrame has unexpected parent"); + nsIFrame* nextPageFrame = pageFrame->GetNextSibling(); + if (!nextPageFrame) + return nsnull; + NS_ASSERTION(nextPageFrame->GetType() == nsGkAtoms::pageFrame, + "pageFrame's sibling is not a page frame..."); + nsIFrame* f = nextPageFrame->GetFirstChild(nsnull); + NS_ASSERTION(f, "pageFrame has no page content frame!"); + NS_ASSERTION(f->GetType() == nsGkAtoms::pageContentFrame, + "pageFrame's child is not page content!"); + return f; +} + nsresult nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame, const nsRegion& aDirtyRegion, nscolor aBackground) @@ -839,6 +934,24 @@ nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFra nsAutoDisableGetUsedXAssertions disableAssert; rv = aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list); + + if (NS_SUCCEEDED(rv) && aFrame->GetType() == nsGkAtoms::pageContentFrame) { + // We may need to paint out-of-flow frames whose placeholders are + // on other pages. Add those pages to our display list. Note that + // out-of-flow frames can't be placed after their placeholders so + // we don't have to process earlier pages. The display lists for + // these extra pages are pruned so that only display items for the + // page we currently care about (which we would have reached by + // following placeholders to their out-of-flows) end up on the list. + nsIFrame* page = aFrame; + nscoord y = aFrame->GetSize().height; + while ((page = GetNextPage(page)) != nsnull) { + rv = BuildDisplayListForExtraPage(&builder, page, y, &list); + if (NS_FAILED(rv)) + break; + y += page->GetSize().height; + } + } } builder.LeavePresShell(aFrame, dirtyRect); diff --git a/layout/generic/nsPageContentFrame.cpp b/layout/generic/nsPageContentFrame.cpp index 657ad4c60f3..ee0ef24576b 100644 --- a/layout/generic/nsPageContentFrame.cpp +++ b/layout/generic/nsPageContentFrame.cpp @@ -252,18 +252,3 @@ nsPageContentFrame::IsContainingBlock() const { return PR_TRUE; } - - -//------------------------------------------------------------------------------ -NS_IMETHODIMP -nsPageContentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists) -{ - nsDisplayListCollection set; - nsresult rv = ViewportFrame::BuildDisplayList(aBuilder, aDirtyRect, set); - NS_ENSURE_SUCCESS(rv, rv); - - return Clip(aBuilder, set, aLists, - nsRect(aBuilder->ToReferenceFrame(this), GetSize())); -} diff --git a/layout/generic/nsPageContentFrame.h b/layout/generic/nsPageContentFrame.h index 994c32d5949..d1856b8f15c 100644 --- a/layout/generic/nsPageContentFrame.h +++ b/layout/generic/nsPageContentFrame.h @@ -54,10 +54,6 @@ public: const nsHTMLReflowState& aMaxSize, nsReflowStatus& aStatus); - NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, - const nsRect& aDirtyRect, - const nsDisplayListSet& aLists); - virtual PRBool IsContainingBlock() const; virtual void SetSharedPageData(nsSharedPageData* aPD) { mPD = aPD; } @@ -74,7 +70,7 @@ public: /** * Get the "type" of the frame * - * @see nsGkAtoms::pageFrame + * @see nsGkAtoms::pageContentFrame */ virtual nsIAtom* GetType() const; diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp index 7f4b003fce1..7963a735d22 100644 --- a/layout/generic/nsPageFrame.cpp +++ b/layout/generic/nsPageFrame.cpp @@ -537,18 +537,17 @@ nsPageFrame::PaintPageContent(nsIRenderingContext& aRenderingContext, nsRect rect = aDirtyRect; float scale = PresContext()->GetPageScale(); aRenderingContext.PushState(); - // Make sure we don't draw where we aren't supposed to draw, especially - // when printing selection - nsRect clipRect(nsPoint(0, 0), GetSize()); - clipRect.Deflate(mPD->mReflowMargin); - aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); - // aPt translates to coords relative to this, then margins translate to - // pageContentFrame's coords nsPoint framePos = aPt + pageContentFrame->GetOffsetTo(this); aRenderingContext.Translate(framePos.x, framePos.y); + // aPt translates to coords relative to this, then margins translate to + // pageContentFrame's coords rect -= framePos; aRenderingContext.Scale(scale, scale); rect.ScaleRoundOut(1.0f / scale); + // Make sure we don't draw where we aren't supposed to draw, especially + // when printing selection + nsRect clipRect(nsPoint(0, 0), pageContentFrame->GetSize()); + aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect); const nsStyleBorder* border = GetStyleBorder(); const nsStylePadding* padding = GetStylePadding(); diff --git a/layout/reftests/bugs/411585-1-ref.html b/layout/reftests/bugs/411585-1-ref.html new file mode 100644 index 00000000000..e68337c066f --- /dev/null +++ b/layout/reftests/bugs/411585-1-ref.html @@ -0,0 +1,7 @@ + + + +
This text should be visible in print preview
+
+ + diff --git a/layout/reftests/bugs/411585-1.html b/layout/reftests/bugs/411585-1.html new file mode 100644 index 00000000000..bcedc8d37b1 --- /dev/null +++ b/layout/reftests/bugs/411585-1.html @@ -0,0 +1,7 @@ + + + +
+
This text should be visible in print preview
+ + diff --git a/layout/reftests/bugs/411585-2-ref.html b/layout/reftests/bugs/411585-2-ref.html new file mode 100644 index 00000000000..a2e815e0624 --- /dev/null +++ b/layout/reftests/bugs/411585-2-ref.html @@ -0,0 +1,7 @@ + + + +
Hi
+
+ + diff --git a/layout/reftests/bugs/411585-2.html b/layout/reftests/bugs/411585-2.html new file mode 100644 index 00000000000..c192401b7f1 --- /dev/null +++ b/layout/reftests/bugs/411585-2.html @@ -0,0 +1,9 @@ + + + +
+
+
Hi
+
+ + diff --git a/layout/reftests/bugs/411585-3-ref.html b/layout/reftests/bugs/411585-3-ref.html new file mode 100644 index 00000000000..c0d7cae0d4b --- /dev/null +++ b/layout/reftests/bugs/411585-3-ref.html @@ -0,0 +1,7 @@ + + + +
Hi
+
+ + diff --git a/layout/reftests/bugs/411585-3.html b/layout/reftests/bugs/411585-3.html new file mode 100644 index 00000000000..ebf64d0bfa9 --- /dev/null +++ b/layout/reftests/bugs/411585-3.html @@ -0,0 +1,9 @@ + + + +
+
+
Hi
+
+ + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index c22ac8d1944..84f04142d67 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -727,6 +727,9 @@ random == 403134-1.html 403134-1-ref.html # bug 405377 != 409659-1c.html 409659-1-ref.html == 409659-1d.html 409659-1-ref.html == 411334-1.xml 411334-1-ref.xml +== 411585-1.html 411585-1-ref.html +== 411585-2.html 411585-2-ref.html +fails == 411585-3.html 411585-3-ref.html # bug 426909 == 411792-1.html 411792-1-ref.html == 412093-1.html 412093-1-ref.html == 412607-1a.html 412607-1-ref.html