Bug 411585. Traverse all pages after the current page when painting a page, to locate placeholders that we need to traverse in order to paint out-of-flows on the current page. r+sr=dbaron

This commit is contained in:
roc+@cs.cmu.edu 2008-04-08 06:06:12 -07:00
parent 01b9637f7c
commit 2e1111534b
12 changed files with 170 additions and 27 deletions

View File

@ -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);

View File

@ -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<nsDisplayClip*>(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);

View File

@ -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()));
}

View File

@ -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;

View File

@ -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();

View File

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html class="reftest-print">
<body>
<div style="position:absolute; top:0; left:0;">This text should be visible in print preview</div>
<div style="height:800px;"></div>
</body>
</html>

View File

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html class="reftest-print">
<body>
<div style="height:800px;"></div>
<div style="position:absolute; top:0; left:0;">This text should be visible in print preview</div>
</body>
</html>

View File

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html class="reftest-print">
<body>
<div style="position:absolute; top:0; left:0; width:100px; height:100px; background:black; opacity:0.5;">Hi</div>
<div style="height:800px;"></div>
</body>
</html>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html class="reftest-print">
<body>
<div style="height:800px;"></div>
<div style="opacity:0.5;">
<div style="position:absolute; top:0; left:0; width:100px; height:100px; background:black;">Hi</div>
</div>
</body>
</html>

View File

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html class="reftest-print">
<body style="margin:0">
<div style="position:absolute; top:0; left:0; width:100px; height:100px; background:black;">Hi</div>
<div style="height:800px;"></div>
</body>
</html>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html class="reftest-print">
<body style="margin:0">
<div style="height:800px;"></div>
<div style="position:absolute; clip:rect(-800px 200px 100px 0px);">
<div style="position:absolute; top:-800px; left:0; width:100px; height:100px; background:black;">Hi</div>
</div>
</body>
</html>

View File

@ -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