Bug 572613. Avoid creating a SolidColor display item when possible by poking the color into the canvas background display item. r=tnikkel

This commit is contained in:
Robert O'Callahan 2010-07-16 09:07:53 +12:00
Родитель 2e3d02e038
Коммит 2ac3c549db
6 изменённых файлов: 118 добавлений и 38 удалений

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

@ -2160,8 +2160,11 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
// For canvas frames (in the CSS sense) we draw the background color using
// a solid color item that gets added in nsLayoutUtils::PaintFrame,
// PresShell::RenderDocument, or nsSubDocumentFrame::BuildDisplayList
// (bug 488242).
// or nsSubDocumentFrame::BuildDisplayList (bug 488242). (The solid
// color may be moved into nsDisplayCanvasBackground by
// nsPresShell::AddCanvasBackgroundColorItem, and painted by
// nsDisplayCanvasBackground directly.) Either way we don't need to
// paint the background color here.
PRBool isCanvasFrame = IsCanvasFrame(aForFrame);
// Determine whether we are drawing background images and/or

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

@ -1275,7 +1275,9 @@ nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFra
// an nsPageContentFrame. We only want to add the canvas background color
// item once, for the nsPageContentFrame.
// Add the canvas background color.
// Add the canvas background color to the bottom of the list. This
// happens after we've built the list so that AddCanvasBackgroundColorItem
// can monkey with the contents if necessary.
rv = presShell->AddCanvasBackgroundColorItem(
builder, list, aFrame, canvasArea, aBackstop);
}

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

@ -5713,6 +5713,24 @@ PresShell::RenderSelection(nsISelection* aSelection,
aScreenRect);
}
static PRBool
AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame,
nscolor aColor)
{
for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
if (i->GetUnderlyingFrame() == aCanvasFrame &&
i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND) {
nsDisplayCanvasBackground* bg = static_cast<nsDisplayCanvasBackground*>(i);
bg->SetExtraBackgroundColor(aColor);
return PR_TRUE;
}
nsDisplayList* sublist = i->GetList();
if (sublist && AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor))
return PR_TRUE;
}
return PR_FALSE;
}
nsresult PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
nsDisplayList& aList,
nsIFrame* aFrame,
@ -5730,6 +5748,23 @@ nsresult PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
return NS_OK;
nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor);
// To make layers work better, we want to avoid having a big non-scrolled
// color background behind a scrolled transparent background. Instead,
// we'll try to move the color background into the scrolled content
// by making nsDisplayCanvasBackground paint it.
if (!aFrame->GetParent()) {
nsIScrollableFrame* sf =
aFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
if (sf) {
nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) {
if (AddCanvasBackgroundColor(aList, canvasFrame, bgcolor))
return NS_OK;
}
}
}
return aList.AppendNewToBottom(
new (&aBuilder) nsDisplaySolidColor(aFrame, aBounds, bgcolor));
}

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

@ -249,38 +249,25 @@ nsRect nsCanvasFrame::CanvasArea() const
return result;
}
/*
* Override nsDisplayBackground methods so that we pass aBGClipRect to
* PaintBackground, covering the whole overflow area.
*/
class nsDisplayCanvasBackground : public nsDisplayBackground {
public:
nsDisplayCanvasBackground(nsIFrame *aFrame)
: nsDisplayBackground(aFrame)
{
void
nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx)
{
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
nsPoint offset = aBuilder->ToReferenceFrame(mFrame);
nsRect bgClipRect = frame->CanvasArea() + offset;
if (NS_GET_A(mExtraBackgroundColor) > 0) {
aCtx->SetColor(mExtraBackgroundColor);
aCtx->FillRect(bgClipRect);
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
{
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
return frame->CanvasArea() + aBuilder->ToReferenceFrame(mFrame);
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx)
{
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
nsPoint offset = aBuilder->ToReferenceFrame(mFrame);
nsRect bgClipRect = frame->CanvasArea() + offset;
nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
mVisibleRect,
nsRect(offset, mFrame->GetSize()),
aBuilder->GetBackgroundPaintFlags(),
&bgClipRect);
}
NS_DISPLAY_DECL_NAME("CanvasBackground", TYPE_CANVAS_BACKGROUND)
};
nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
mVisibleRect,
nsRect(offset, mFrame->GetSize()),
aBuilder->GetBackgroundPaintFlags(),
&bgClipRect);
}
/**
* A display item to paint the focus ring for the document.

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

@ -157,4 +157,55 @@ protected:
nsAbsoluteContainingBlock mAbsoluteContainer;
};
/**
* Override nsDisplayBackground methods so that we pass aBGClipRect to
* PaintBackground, covering the whole overflow area.
* We can also paint an "extra background color" behind the normal
* background.
*/
class nsDisplayCanvasBackground : public nsDisplayBackground {
public:
nsDisplayCanvasBackground(nsIFrame *aFrame)
: nsDisplayBackground(aFrame)
{
mExtraBackgroundColor = NS_RGBA(0,0,0,0);
}
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder)
{
return NS_GET_A(mExtraBackgroundColor) == 255 ||
nsDisplayBackground::IsOpaque(aBuilder);
}
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor)
{
nscolor background;
if (!nsDisplayBackground::IsUniform(aBuilder, &background))
return PR_FALSE;
NS_ASSERTION(background == NS_RGBA(0,0,0,0),
"The nsDisplayBackground for a canvas frame doesn't paint "
"its background color normally");
*aColor = mExtraBackgroundColor;
return PR_TRUE;
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
{
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
return frame->CanvasArea() + aBuilder->ToReferenceFrame(mFrame);
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx);
void SetExtraBackgroundColor(nscolor aColor)
{
mExtraBackgroundColor = aColor;
}
NS_DISPLAY_DECL_NAME("CanvasBackground", TYPE_CANVAS_BACKGROUND)
private:
nscolor mExtraBackgroundColor;
};
#endif /* nsCanvasFrame_h___ */

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

@ -427,17 +427,19 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mInnerView->GetPosition() +
GetOffsetTo(aBuilder->ReferenceFrame());
if (f && NS_SUCCEEDED(rv)) {
rv = f->BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
}
if (!aBuilder->IsForEventDelivery()) {
// Add the canvas background color.
// Add the canvas background color to the bottom of the list. This
// happens after we've built the list so that AddCanvasBackgroundColorItem
// can monkey with the contents if necessary.
rv = presShell->AddCanvasBackgroundColorItem(
*aBuilder, childItems, f ? f : this, shellBounds, NS_RGBA(0,0,0,0),
PR_TRUE);
}
if (f && NS_SUCCEEDED(rv)) {
rv = f->BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
}
if (NS_SUCCEEDED(rv)) {
// Clip children to the child root frame's rectangle
rv = aLists.Content()->AppendNewToTop(