Backed out 8 changesets (bug 810470) due OSX reftest failures.

This commit is contained in:
Ryan VanderMeulen 2012-11-14 22:14:44 -05:00
parent 4bfd2129d6
commit 98268dbc6a
18 changed files with 568 additions and 363 deletions

View File

@ -2314,6 +2314,33 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
}
}
bool
FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem)
{
if (!aItem->ShouldFixToViewport(aBuilder)) {
return true;
}
nsRefPtr<LayerManager> layerManager;
nsIFrame* referenceFrame = aBuilder->RootReferenceFrame();
NS_ASSERTION(referenceFrame == nsLayoutUtils::GetDisplayRootFrame(referenceFrame),
"Reference frame must be a display root for us to use the layer manager");
nsIWidget* window = referenceFrame->GetNearestWidget();
if (window) {
layerManager = window->GetLayerManager();
}
if (layerManager) {
DisplayItemData* data = GetDisplayItemDataForManager(aItem, layerManager);
if (data) {
return false;
}
}
return true;
}
void
FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
nsDisplayItem* aItem,

View File

@ -321,6 +321,16 @@ public:
LayerManager* GetRetainingLayerManager() { return mRetainingManager; }
/**
* Returns true if the given item (which we assume here is
* background-attachment:fixed) needs to be repainted as we scroll in its
* document.
* Returns false if it doesn't need to be repainted because the layer system
* is ensuring its fixed-ness for us.
*/
static bool NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem);
/**
* Returns true if the given display item was rendered during the previous
* paint. Returns false otherwise.

View File

@ -1810,27 +1810,27 @@ nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
}
const nsStyleBackground *bg = aStyleContext->GetStyleBackground();
nscolor bgColor;
if (aDrawBackgroundColor) {
bgColor =
aStyleContext->GetVisitedDependentColor(eCSSProperty_background_color);
if (NS_GET_A(bgColor) == 0) {
if (NS_GET_A(bgColor) == 0)
aDrawBackgroundColor = false;
}
} else {
// If GetBackgroundColorDraw() is false, we are still expected to
// draw color in the background of any frame that's not completely
// transparent, but we are expected to use white instead of whatever
// color was specified.
bgColor = NS_RGB(255, 255, 255);
if (aDrawBackgroundImage || !bg->IsTransparent()) {
if (aDrawBackgroundImage ||
!aStyleContext->GetStyleBackground()->IsTransparent())
aDrawBackgroundColor = true;
} else {
else
bgColor = NS_RGBA(0,0,0,0);
}
}
const nsStyleBackground *bg = aStyleContext->GetStyleBackground();
// We can skip painting the background color if a background image is opaque.
if (aDrawBackgroundColor &&
bg->BottomLayer().mRepeat.mXRepeat == NS_STYLE_BG_REPEAT_REPEAT &&
@ -2736,103 +2736,6 @@ IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame)
return false;
}
nsRect
nsCSSRendering::ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer,
nsIFrame** aAttachedToFrame)
{
// Compute background origin area relative to aBorderArea now as we may need
// it to compute the effective image size for a CSS gradient.
nsRect bgPositioningArea(0, 0, 0, 0);
nsIAtom* frameType = aForFrame->GetType();
nsIFrame* geometryFrame = aForFrame;
if (frameType == nsGkAtoms::inlineFrame) {
// XXXjwalden Strictly speaking this is not quite faithful to how
// background-break is supposed to interact with background-origin values,
// but it's a non-trivial amount of work to make it fully conformant, and
// until the specification is more finalized (and assuming background-break
// even makes the cut) it doesn't make sense to hammer out exact behavior.
switch (aBackground.mBackgroundInlinePolicy) {
case NS_STYLE_BG_INLINE_POLICY_EACH_BOX:
bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
break;
case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
bgPositioningArea = gInlineBGData->GetBoundingRect(aForFrame);
break;
default:
NS_ERROR("Unknown background-inline-policy value! "
"Please, teach me what to do.");
case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS:
bgPositioningArea = gInlineBGData->GetContinuousRect(aForFrame);
break;
}
} else if (frameType == nsGkAtoms::canvasFrame) {
geometryFrame = aForFrame->GetFirstPrincipalChild();
// geometryFrame might be null if this canvas is a page created
// as an overflow container (e.g. the in-flow content has already
// finished and this page only displays the continuations of
// absolutely positioned content).
if (geometryFrame) {
bgPositioningArea = geometryFrame->GetRect();
}
} else {
bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
}
// Background images are tiled over the 'background-clip' area
// but the origin of the tiling is based on the 'background-origin' area
if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_BORDER && geometryFrame) {
nsMargin border = geometryFrame->GetUsedBorder();
if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_PADDING) {
border += geometryFrame->GetUsedPadding();
NS_ASSERTION(aLayer.mOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
"unknown background-origin value");
}
geometryFrame->ApplySkipSides(border);
bgPositioningArea.Deflate(border);
}
nsIFrame* attachedToFrame = aForFrame;
if (NS_STYLE_BG_ATTACHMENT_FIXED == aLayer.mAttachment) {
// If it's a fixed background attachment, then the image is placed
// relative to the viewport, which is the area of the root frame
// in a screen context or the page content frame in a print context.
attachedToFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame();
NS_ASSERTION(attachedToFrame, "no root frame");
nsIFrame* pageContentFrame = nullptr;
if (aPresContext->IsPaginated()) {
pageContentFrame =
nsLayoutUtils::GetClosestFrameOfType(aForFrame, nsGkAtoms::pageContentFrame);
if (pageContentFrame) {
attachedToFrame = pageContentFrame;
}
// else this is an embedded shell and its root frame is what we want
}
// Set the background positioning area to the viewport's area
// (relative to aForFrame)
bgPositioningArea =
nsRect(-aForFrame->GetOffsetTo(attachedToFrame), attachedToFrame->GetSize());
if (!pageContentFrame) {
// Subtract the size of scrollbars.
nsIScrollableFrame* scrollableFrame =
aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
if (scrollableFrame) {
nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
bgPositioningArea.Deflate(scrollbars);
}
}
}
*aAttachedToFrame = attachedToFrame;
return bgPositioningArea;
}
nsBackgroundLayerState
nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,
@ -2908,13 +2811,57 @@ nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
return state;
}
// The frame to which the background is attached
nsIFrame* attachedToFrame = aForFrame;
// Compute background origin area relative to aBorderArea now as we may need
// it to compute the effective image size for a CSS gradient.
nsRect bgPositioningArea =
ComputeBackgroundPositioningArea(aPresContext, aForFrame, aBorderArea,
aBackground, aLayer, &attachedToFrame);
nsRect bgPositioningArea(0, 0, 0, 0);
nsIAtom* frameType = aForFrame->GetType();
nsIFrame* geometryFrame = aForFrame;
if (frameType == nsGkAtoms::inlineFrame) {
// XXXjwalden Strictly speaking this is not quite faithful to how
// background-break is supposed to interact with background-origin values,
// but it's a non-trivial amount of work to make it fully conformant, and
// until the specification is more finalized (and assuming background-break
// even makes the cut) it doesn't make sense to hammer out exact behavior.
switch (aBackground.mBackgroundInlinePolicy) {
case NS_STYLE_BG_INLINE_POLICY_EACH_BOX:
bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
break;
case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
bgPositioningArea = gInlineBGData->GetBoundingRect(aForFrame);
break;
default:
NS_ERROR("Unknown background-inline-policy value! "
"Please, teach me what to do.");
case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS:
bgPositioningArea = gInlineBGData->GetContinuousRect(aForFrame);
break;
}
} else if (frameType == nsGkAtoms::canvasFrame) {
geometryFrame = aForFrame->GetFirstPrincipalChild();
// geometryFrame might be null if this canvas is a page created
// as an overflow container (e.g. the in-flow content has already
// finished and this page only displays the continuations of
// absolutely positioned content).
if (geometryFrame) {
bgPositioningArea = geometryFrame->GetRect();
}
} else {
bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
}
// Background images are tiled over the 'background-clip' area
// but the origin of the tiling is based on the 'background-origin' area
if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_BORDER && geometryFrame) {
nsMargin border = geometryFrame->GetUsedBorder();
if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_PADDING) {
border += geometryFrame->GetUsedPadding();
NS_ASSERTION(aLayer.mOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
"unknown background-origin value");
}
geometryFrame->ApplySkipSides(border);
bgPositioningArea.Deflate(border);
}
// For background-attachment:fixed backgrounds, we'll limit the area
// where the background can be drawn to the viewport.
@ -2926,8 +2873,40 @@ nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
// of aForFrame's border-box will be rendered)
nsPoint imageTopLeft;
if (NS_STYLE_BG_ATTACHMENT_FIXED == aLayer.mAttachment) {
if ((aFlags & nsCSSRendering::PAINTBG_TO_WINDOW) &&
!IsTransformed(aForFrame, attachedToFrame)) {
aPresContext->SetHasFixedBackgroundFrame();
// If it's a fixed background attachment, then the image is placed
// relative to the viewport, which is the area of the root frame
// in a screen context or the page content frame in a print context.
nsIFrame* topFrame =
aPresContext->PresShell()->FrameManager()->GetRootFrame();
NS_ASSERTION(topFrame, "no root frame");
nsIFrame* pageContentFrame = nullptr;
if (aPresContext->IsPaginated()) {
pageContentFrame =
nsLayoutUtils::GetClosestFrameOfType(aForFrame, nsGkAtoms::pageContentFrame);
if (pageContentFrame) {
topFrame = pageContentFrame;
}
// else this is an embedded shell and its root frame is what we want
}
// Set the background positioning area to the viewport's area
// (relative to aForFrame)
bgPositioningArea = nsRect(-aForFrame->GetOffsetTo(topFrame), topFrame->GetSize());
if (!pageContentFrame) {
// Subtract the size of scrollbars.
nsIScrollableFrame* scrollableFrame =
aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
if (scrollableFrame) {
nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
bgPositioningArea.Deflate(scrollbars);
}
}
if (aFlags & nsCSSRendering::PAINTBG_TO_WINDOW &&
!IsTransformed(aForFrame, topFrame)) {
// Clip background-attachment:fixed backgrounds to the viewport, if we're
// painting to the screen and not transformed. This avoids triggering
// tiling in common cases, without affecting output since drawing is

View File

@ -300,14 +300,6 @@ struct nsCSSRendering {
bool& aDrawBackgroundImage,
bool& aDrawBackgroundColor);
static nsRect
ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleBackground& aBackground,
const nsStyleBackground::Layer& aLayer,
nsIFrame** aAttachedToFrame);
static nsBackgroundLayerState
PrepareBackgroundLayer(nsPresContext* aPresContext,
nsIFrame* aForFrame,

View File

@ -1465,22 +1465,20 @@ RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
borderBox.ToNearestPixels(aFrame->PresContext()->AppUnitsPerDevPixel()));
}
nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
uint32_t aLayer,
bool aIsThemed,
const nsStyleBackground* aBackgroundStyle)
nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
uint32_t aLayer,
bool aSkipFixedItemBoundsCheck)
: nsDisplayItem(aBuilder, aFrame)
, mBackgroundStyle(aBackgroundStyle)
, mLayer(aLayer)
, mIsThemed(aIsThemed)
, mIsFixed(false)
, mIsBottommostLayer(true)
, mLayer(aLayer)
{
MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
MOZ_COUNT_CTOR(nsDisplayBackground);
const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
mIsThemed = mFrame->IsThemed(disp, &mThemeTransparency);
if (mIsThemed) {
const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
mFrame->IsThemed(disp, &mThemeTransparency);
// Perform necessary RegisterThemeGeometry
if (disp->mAppearance == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
disp->mAppearance == NS_THEME_TOOLBAR) {
@ -1489,38 +1487,72 @@ nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilde
disp->mAppearance == NS_THEME_WIN_GLASS) {
aBuilder->SetGlassDisplayItem(this);
}
} else if (mBackgroundStyle) {
} else {
// Set HasFixedItems if we construct a background-attachment:fixed item
if (mLayer != mBackgroundStyle->mImageCount - 1) {
mIsBottommostLayer = false;
}
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext* bgSC;
bool hasBG = nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
if (hasBG) {
const nsStyleBackground* bg = bgSC->GetStyleBackground();
if (mLayer != bg->mImageCount - 1) {
mIsBottommostLayer = false;
}
// Check if this background layer is attachment-fixed
if (!mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty() &&
mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED) {
aBuilder->SetHasFixedItems();
// Check if this background layer is attachment-fixed
if (!bg->mLayers[mLayer].mImage.IsEmpty() &&
bg->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED) {
aBuilder->SetHasFixedItems();
// Check whether we should fix to viewport scrolling
if (bg->mLayers[mLayer].mClip == NS_STYLE_BG_CLIP_BORDER &&
!nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius)) {
if (aSkipFixedItemBoundsCheck) {
mIsFixed = true;
} else {
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
bool snap;
nsRect bounds = GetBounds(aBuilder, &snap);
// This bounds check prevents an item fixing to the viewport unless it
// it encompasses the scroll-port. If a fixed background doesn't
// encompass the scroll-port, it usually means that scrolling will
// expose a new area of the fixed background and cause a lot of
// invalidation. This performs badly, and looks especially bad when
// async scrolling is being used.
// XXX A better check would be to see if the underlying frame is fixed to
// the viewport/is the viewport.
nsIScrollableFrame* scrollable = do_QueryFrame(rootScrollFrame);
nsRect scrollport(scrollable->GetScrollPortRect().TopLeft() +
aBuilder->ToReferenceFrame(rootScrollFrame),
scrollable->GetScrollPositionClampingScrollPortSize());
mIsFixed = bounds.Contains(scrollport);
}
}
}
}
}
}
}
nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
nsDisplayBackground::~nsDisplayBackground()
{
#ifdef NS_BUILD_REFCNT_LOGGING
MOZ_COUNT_DTOR(nsDisplayBackgroundImage);
MOZ_COUNT_DTOR(nsDisplayBackground);
#endif
}
/*static*/ nsresult
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayList* aList,
nsDisplayBackgroundImage** aBackground)
nsDisplayBackground::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayList* aList,
nsDisplayBackground** aBackground)
{
nsStyleContext* bgSC = nullptr;
const nsStyleBackground* bg = nullptr;
nsPresContext* presContext = aFrame->PresContext();
bool isThemed = aFrame->IsThemed();
if (!isThemed &&
if (!aFrame->IsThemed() &&
nsCSSRendering::FindBackground(presContext, aFrame, &bgSC)) {
bg = bgSC->GetStyleBackground();
}
@ -1537,15 +1569,15 @@ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuil
// Even if we don't actually have a background color to paint, we still need
// to create the item because it's used for hit testing.
aList->AppendNewToTop(
new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame, bg,
new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame,
drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0)));
// Passing bg == nullptr in this macro will result in one iteration with
// i = 0.
bool backgroundSet = !aBackground;
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
nsDisplayBackgroundImage* bgItem =
new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, isThemed, bg);
nsDisplayBackground* bgItem =
new (aBuilder) nsDisplayBackground(aBuilder, aFrame, i);
nsresult rv = aList->AppendNewToTop(bgItem);
if (rv != NS_OK) {
return rv;
@ -1647,24 +1679,47 @@ RoundedBorderIntersectsRect(nsIFrame* aFrame,
//
// See also RoundedRectIntersectsRect.
static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
const nscoord aRadii[8],
const nsRect& aContainedRect) {
const nscoord aRadii[8],
const nsRect& aContainedRect) {
nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect);
return rgn.Contains(aContainedRect);
}
bool
nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder,
const nsRect& aClipRect,
gfxRect* aDestRect)
nsDisplayBackground::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, const nsRect& aClipRect)
{
if (mIsThemed || !mBackgroundStyle)
if (mIsThemed)
return false;
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext* bgSC;
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
return false;
bool drawBackgroundImage;
bool drawBackgroundColor;
nsCSSRendering::DetermineBackgroundColor(presContext,
bgSC,
mFrame,
drawBackgroundImage,
drawBackgroundColor);
// For now we don't know how to draw image layers with a background color.
if (!drawBackgroundImage || drawBackgroundColor)
return false;
const nsStyleBackground *bg = bgSC->GetStyleBackground();
// We could pretty easily support multiple image layers, but for now we
// just punt here.
if (bg->mLayers.Length() != 1)
return false;
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
nsPoint offset = ToReferenceFrame();
nsRect borderArea = nsRect(offset, mFrame->GetSize());
const nsStyleBackground::Layer &layer = bg->mLayers[0];
if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED)
return false;
@ -1675,7 +1730,7 @@ nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuil
flags,
borderArea,
aClipRect,
*mBackgroundStyle,
*bg,
layer);
nsImageRenderer* imageRenderer = &state.mImageRenderer;
@ -1684,21 +1739,41 @@ nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuil
return false;
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
*aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
mDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
return true;
}
bool
nsDisplayBackgroundImage::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
nsDisplayBackground::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
{
if (mIsThemed || !mBackgroundStyle)
if (mIsThemed)
return false;
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext* bgSC;
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
return false;
bool drawBackgroundImage;
bool drawBackgroundColor;
nsCSSRendering::DetermineBackgroundColor(presContext,
bgSC,
mFrame,
drawBackgroundImage,
drawBackgroundColor);
// For now we don't know how to draw image layers with a background color.
if (!drawBackgroundImage || drawBackgroundColor)
return false;
const nsStyleBackground *bg = bgSC->GetStyleBackground();
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
nsPoint offset = ToReferenceFrame();
nsRect borderArea = nsRect(offset, mFrame->GetSize());
const nsStyleBackground::Layer &layer = bg->mLayers[mLayer];
nsBackgroundLayerState state =
nsCSSRendering::PrepareBackgroundLayer(presContext,
@ -1706,7 +1781,7 @@ nsDisplayBackgroundImage::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder
flags,
borderArea,
borderArea,
*mBackgroundStyle,
*bg,
layer);
nsImageRenderer* imageRenderer = &state.mImageRenderer;
@ -1738,9 +1813,9 @@ nsDisplayBackgroundImage::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder
}
LayerState
nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const FrameLayerBuilder::ContainerParameters& aParameters)
nsDisplayBackground::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const FrameLayerBuilder::ContainerParameters& aParameters)
{
if (!aManager->IsCompositingCheap() ||
!nsLayoutUtils::GPUImageScalingEnabled() ||
@ -1773,9 +1848,9 @@ nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
}
already_AddRefed<Layer>
nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters)
nsDisplayBackground::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters)
{
nsRefPtr<ImageLayer> layer = aManager->CreateImageLayer();
layer->SetContainer(mImageContainer);
@ -1784,7 +1859,7 @@ nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder,
}
void
nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer)
nsDisplayBackground::ConfigureLayer(ImageLayer* aLayer)
{
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
@ -1800,10 +1875,10 @@ nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer)
}
void
nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
const nsRect& aRect,
HitTestState* aState,
nsTArray<nsIFrame*> *aOutFrames)
nsDisplayBackground::HitTest(nsDisplayListBuilder* aBuilder,
const nsRect& aRect,
HitTestState* aState,
nsTArray<nsIFrame*> *aOutFrames)
{
if (mIsThemed) {
// For theme backgrounds, assume that any point in our border rect is a hit.
@ -1820,9 +1895,9 @@ nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
}
bool
nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion)
nsDisplayBackground::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion)
{
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
aAllowVisibleRegionExpansion)) {
@ -1832,14 +1907,16 @@ nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
// Return false if the background was propagated away from this
// frame. We don't want this display item to show up and confuse
// anything.
return mIsThemed || mBackgroundStyle;
nsStyleContext* bgSC;
return mIsThemed ||
nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
}
/* static */ nsRegion
nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
nsPresContext* aPresContext,
uint8_t aClip, const nsRect& aRect,
bool* aSnap)
nsDisplayBackground::GetInsideClipRegion(nsDisplayItem* aItem,
nsPresContext* aPresContext,
uint8_t aClip, const nsRect& aRect,
bool* aSnap)
{
nsRegion result;
if (aRect.IsEmpty())
@ -1878,8 +1955,8 @@ nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
}
nsRegion
nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) {
nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
bool* aSnap) {
nsRegion result;
*aSnap = false;
// theme background overrides any other background
@ -1890,9 +1967,11 @@ nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
return result;
}
if (!mBackgroundStyle)
nsStyleContext* bgSC;
nsPresContext* presContext = mFrame->PresContext();
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
return result;
const nsStyleBackground* bg = bgSC->GetStyleBackground();
*aSnap = true;
@ -1901,15 +1980,14 @@ nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
// which expects frames to be sent to it in content order, not reverse
// content order which we'll produce here.
// Of course, if there's only one frame in the flow, it doesn't matter.
if (mBackgroundStyle->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
if (bg->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
(!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
const nsStyleBackground::Layer& layer = bg->mLayers[mLayer];
if (layer.mImage.IsOpaque()) {
nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
nsPresContext* presContext = mFrame->PresContext();
nsRect r = nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
borderBox, *mBackgroundStyle, layer);
result = GetInsideClipRegion(this, presContext, layer.mClip, r, aSnap);
borderBox, *bg, layer);
result.Or(result, GetInsideClipRegion(this, presContext, layer.mClip, r, aSnap));
}
}
@ -1917,7 +1995,7 @@ nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
}
bool
nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
nsDisplayBackground::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
// theme background overrides any other background
if (mIsThemed) {
const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
@ -1929,11 +2007,15 @@ nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aCo
return false;
}
if (!mBackgroundStyle) {
nsStyleContext *bgSC;
bool hasBG =
nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
if (!hasBG) {
*aColor = NS_RGBA(0,0,0,0);
return true;
}
if (mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty()) {
const nsStyleBackground* bg = bgSC->GetStyleBackground();
if (bg->mLayers[mLayer].mImage.IsEmpty()) {
*aColor = NS_RGBA(0,0,0,0);
return true;
}
@ -1941,16 +2023,21 @@ nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aCo
}
bool
nsDisplayBackgroundImage::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame)
nsDisplayBackground::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame)
{
// theme background overrides any other background and is never fixed
if (mIsThemed)
return false;
if (!mBackgroundStyle)
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext *bgSC;
bool hasBG =
nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
if (!hasBG)
return false;
if (!mBackgroundStyle->HasFixedBackground())
const nsStyleBackground* bg = bgSC->GetStyleBackground();
if (!bg->HasFixedBackground())
return false;
// If aFrame is mFrame or an ancestor in this document, and aFrame is
@ -1961,44 +2048,40 @@ nsDisplayBackgroundImage::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* a
nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame));
}
nsRect
nsDisplayBackgroundImage::GetPositioningArea()
{
if (!mBackgroundStyle) {
return nsRect();
}
nsIFrame* attachedToFrame;
return nsCSSRendering::ComputeBackgroundPositioningArea(
mFrame->PresContext(), mFrame,
nsRect(ToReferenceFrame(), mFrame->GetSize()),
*mBackgroundStyle, mBackgroundStyle->mLayers[mLayer],
&attachedToFrame) + ToReferenceFrame();
}
bool
nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
nsDisplayBackground::RenderingMightDependOnFrameSize()
{
// theme background overrides any other background and we don't know what to do here
if (mIsThemed)
return true;
if (!mBackgroundStyle)
return false;
// We could be smarter with rounded corners and only invalidate the new area + the piece that was previously
// clipped out.
nscoord radii[8];
if (mFrame->GetBorderRadii(radii)) {
// A change in the size of the positioning area might change the position
// of the rounded corners.
if (mFrame->GetBorderRadii(radii))
return true;
}
const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
if (layer.RenderingMightDependOnPositioningAreaSizeChange()) {
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext *bgSC;
bool hasBG =
nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
if (!hasBG)
return false;
const nsStyleBackground* bg = bgSC->GetStyleBackground();
const nsStyleBackground::Layer &layer = bg->mLayers[mLayer];
if (layer.RenderingMightDependOnFrameSize()) {
return true;
}
return false;
}
bool
nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
{
return mIsFixed;
}
static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
{
nsDisplayItem* nextItem = aItem->GetAbove();
@ -2013,8 +2096,8 @@ static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
}
void
nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) {
nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) {
nsPoint offset = ToReferenceFrame();
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
@ -2025,36 +2108,30 @@ nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
flags, nullptr, mLayer);
}
void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
void nsDisplayBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
if (!mBackgroundStyle) {
const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
if (ShouldFixToViewport(aBuilder)) {
// This is incorrect, We definitely need to check more things here.
return;
}
const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
bool snap;
nsRect bounds = GetBounds(aBuilder, &snap);
nsRect positioningArea = GetPositioningArea();
if (positioningArea.TopLeft() != geometry->mPositioningArea.TopLeft() ||
(positioningArea.Size() != geometry->mPositioningArea.Size() &&
RenderingMightDependOnPositioningAreaSizeChange())) {
// Positioning area changed in a way that could cause everything to change,
// so invalidate everything (both old and new painting areas).
aInvalidRegion->Or(bounds, geometry->mBounds);
return;
}
if (!bounds.IsEqualInterior(geometry->mBounds)) {
// Positioning area is unchanged, so invalidate just the change in the
// painting area.
aInvalidRegion->Xor(bounds, geometry->mBounds);
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect()) ||
!geometry->mContentRect.IsEqualInterior(GetContentRect())) {
if (!RenderingMightDependOnFrameSize() && geometry->mBounds.TopLeft() == GetBounds(aBuilder, &snap).TopLeft()) {
aInvalidRegion->Xor(GetBounds(aBuilder, &snap), geometry->mBounds);
} else {
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
}
}
}
nsRect
nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
*aSnap = true;
nsPresContext* presContext = mFrame->PresContext();
@ -2071,18 +2148,20 @@ nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
return r + ToReferenceFrame();
}
if (!mBackgroundStyle) {
nsStyleContext* bgSC;
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC)) {
return nsRect();
}
const nsStyleBackground* bg = bgSC->GetStyleBackground();
nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
const nsStyleBackground::Layer& layer = bg->mLayers[mLayer];
return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
borderBox, *mBackgroundStyle, layer);
borderBox, *bg, layer);
}
uint32_t
nsDisplayBackgroundImage::GetPerFrameKey()
nsDisplayBackground::GetPerFrameKey()
{
return (mLayer << nsDisplayItem::TYPE_BITS) |
nsDisplayItem::GetPerFrameKey();
@ -2113,27 +2192,31 @@ nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
return nsRegion();
}
if (!mBackgroundStyle)
nsStyleContext* bgSC;
nsPresContext* presContext = mFrame->PresContext();
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
return nsRegion();
const nsStyleBackground* bg = bgSC->GetStyleBackground();
const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer();
*aSnap = true;
const nsStyleBackground::Layer& bottomLayer = mBackgroundStyle->BottomLayer();
nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
nsPresContext* presContext = mFrame->PresContext();
return nsDisplayBackgroundImage::GetInsideClipRegion(this, presContext, bottomLayer.mClip, borderBox, aSnap);
return nsDisplayBackground::GetInsideClipRegion(this, presContext, bottomLayer.mClip, borderBox, aSnap);
}
bool
nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor)
{
*aColor = mColor;
if (!mBackgroundStyle)
nsStyleContext* bgSC;
nsPresContext* presContext = mFrame->PresContext();
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
return true;
const nsStyleBackground* bg = bgSC->GetStyleBackground();
return (!nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius) &&
mBackgroundStyle->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER);
bg->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER);
}
void

View File

@ -1782,21 +1782,17 @@ private:
};
/**
* A display item to paint one background-image for a frame. Each background
* image layer gets its own nsDisplayBackgroundImage.
* The standard display item to paint the CSS background of a frame.
*/
class nsDisplayBackgroundImage : public nsDisplayItem {
class nsDisplayBackground : public nsDisplayItem {
public:
/**
* aLayer signifies which background layer this item represents.
* aIsThemed should be the value of aFrame->IsThemed.
* aBackgroundStyle should be the result of
* nsCSSRendering::FindBackground, or null if FindBackground returned false.
*/
nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
uint32_t aLayer, bool aIsThemed,
const nsStyleBackground* aBackgroundStyle);
virtual ~nsDisplayBackgroundImage();
// aLayer signifies which background layer this item represents. Normally
// a background layer will only be marked as fixed if it covers the scroll-
// port of the root scroll-frame. This check can be skipped using
// aSkipFixedItemBoundsCheck.
nsDisplayBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
uint32_t aLayer, bool aSkipFixedItemBoundsCheck = false);
virtual ~nsDisplayBackground();
// This will create and append new items for all the layers of the
// background. If given, aBackground will be set with the address of the
@ -1804,7 +1800,7 @@ public:
static nsresult AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayList* aList,
nsDisplayBackgroundImage** aBackground = nullptr);
nsDisplayBackground** aBackground = nullptr);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
@ -1824,9 +1820,7 @@ public:
virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame) MOZ_OVERRIDE;
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE;
/**
* GetBounds() returns the background painting area.
*/
virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE;
@ -1834,22 +1828,13 @@ public:
// Returns the value of GetUnderlyingFrame()->IsThemed(), but cached
bool IsThemed() { return mIsThemed; }
/**
* Return the background positioning area.
* (GetBounds() returns the background painting area.)
* Can be called only when mBackgroundStyle is non-null.
*/
nsRect GetPositioningArea();
/**
* Returns true if existing rendered pixels of this display item may need
* to be redrawn if the positioning area size changes but its position does
* not.
* If false, only the changed painting area needs to be redrawn when the
* positioning area size changes but its position does not.
* to be redrawn if the frame size changes.
* If false, only the changed area needs to be redrawn.
*/
bool RenderingMightDependOnPositioningAreaSizeChange();
bool RenderingMightDependOnFrameSize();
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
{
return new nsDisplayBackgroundGeometry(this, aBuilder);
@ -1865,35 +1850,31 @@ protected:
typedef class mozilla::layers::ImageContainer ImageContainer;
typedef class mozilla::layers::ImageLayer ImageLayer;
bool TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder,
const nsRect& aClipRect,
gfxRect* aDestRect);
bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, const nsRect& aClipRect);
void ConfigureLayer(ImageLayer* aLayer);
// Cache the result of nsCSSRendering::FindBackground. Always null if
// mIsThemed is true or if FindBackground returned false.
const nsStyleBackground* mBackgroundStyle;
/* Used to cache mFrame->IsThemed() since it isn't a cheap call */
bool mIsThemed;
/* true if this item represents a background-attachment:fixed layer and
* should fix to the viewport. */
bool mIsFixed;
/* true if this item represents the bottom-most background layer */
bool mIsBottommostLayer;
nsITheme::Transparency mThemeTransparency;
/* If this background can be a simple image layer, we store the format here. */
nsRefPtr<ImageContainer> mImageContainer;
gfxRect mDestRect;
uint32_t mLayer;
nsITheme::Transparency mThemeTransparency;
/* Used to cache mFrame->IsThemed() since it isn't a cheap call */
bool mIsThemed;
/* true if this item represents the bottom-most background layer */
bool mIsBottommostLayer;
};
class nsDisplayBackgroundColor : public nsDisplayItem
{
public:
nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsStyleBackground* aBackgroundStyle,
nscolor aColor)
nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nscolor aColor)
: nsDisplayItem(aBuilder, aFrame)
, mBackgroundStyle(aBackgroundStyle)
, mColor(aColor)
{ }
@ -1913,8 +1894,6 @@ public:
NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR)
protected:
const nsStyleBackground* mBackgroundStyle;
nscolor mColor;
};

View File

@ -42,17 +42,18 @@ nsDisplayBorderGeometry::MoveBy(const nsPoint& aOffset)
mContentRect.MoveBy(aOffset);
}
nsDisplayBackgroundGeometry::nsDisplayBackgroundGeometry(nsDisplayBackgroundImage* aItem,
nsDisplayListBuilder* aBuilder)
nsDisplayBackgroundGeometry::nsDisplayBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
: nsDisplayItemGeometry(aItem, aBuilder)
, mPositioningArea(aItem->GetPositioningArea())
, mPaddingRect(aItem->GetPaddingRect())
, mContentRect(aItem->GetContentRect())
{}
void
nsDisplayBackgroundGeometry::MoveBy(const nsPoint& aOffset)
{
mBounds.MoveBy(aOffset);
mPositioningArea.MoveBy(aOffset);
mPaddingRect.MoveBy(aOffset);
mContentRect.MoveBy(aOffset);
}
nsDisplayBoxShadowInnerGeometry::nsDisplayBoxShadowInnerGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)

View File

@ -10,7 +10,6 @@
class nsDisplayItem;
class nsDisplayListBuilder;
class nsDisplayBackgroundImage;
/**
* This stores the geometry of an nsDisplayItem, and the area
@ -76,11 +75,12 @@ public:
class nsDisplayBackgroundGeometry : public nsDisplayItemGeometry
{
public:
nsDisplayBackgroundGeometry(nsDisplayBackgroundImage* aItem, nsDisplayListBuilder* aBuilder);
nsDisplayBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder);
virtual void MoveBy(const nsPoint& aOffset);
nsRect mPositioningArea;
nsRect mPaddingRect;
nsRect mContentRect;
};
class nsDisplayBoxShadowInnerGeometry : public nsDisplayItemGeometry

View File

@ -939,6 +939,9 @@ public:
PropertyTable()->DeleteAllFor(aFrame);
}
bool MayHaveFixedBackgroundFrames() { return mMayHaveFixedBackgroundFrames; }
void SetHasFixedBackgroundFrame() { mMayHaveFixedBackgroundFrames = true; }
virtual size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
@ -1218,6 +1221,7 @@ protected:
unsigned mPendingUIResolutionChanged : 1;
unsigned mPendingMediaFeatureValuesChanged : 1;
unsigned mPrefChangePendingNeedsReflow : 1;
unsigned mMayHaveFixedBackgroundFrames : 1;
// True if the requests in mInvalidateRequestsSinceLastPaint cover the
// entire viewport
unsigned mAllInvalidated : 1;

View File

@ -206,25 +206,18 @@ nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
nsRefPtr<gfxContext> dest = aCtx->ThebesContext();
nsRefPtr<gfxASurface> surf;
nsRefPtr<gfxContext> ctx;
gfxRect destRect;
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) &&
aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap() &&
!dest->CurrentMatrix().HasNonIntegerTranslation()) {
// Snap image rectangle to nearest pixel boundaries. This is the right way
// to snap for this context, because we checked HasNonIntegerTranslation above.
destRect.Round();
if (IsSingleFixedPositionImage(aBuilder, bgClipRect) && aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap()) {
surf = static_cast<gfxASurface*>(GetUnderlyingFrame()->Properties().Get(nsIFrame::CachedBackgroundImage()));
nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface();
if (surf && surf->GetType() == destSurf->GetType()) {
BlitSurface(dest, destRect, surf);
BlitSurface(dest, mDestRect, surf);
return;
}
surf = destSurf->CreateSimilarSurface(gfxASurface::CONTENT_COLOR_ALPHA,
gfxIntSize(destRect.width, destRect.height));
surf = destSurf->CreateSimilarSurface(gfxASurface::CONTENT_COLOR_ALPHA, gfxIntSize(ceil(mDestRect.width), ceil(mDestRect.height)));
if (surf) {
ctx = new gfxContext(surf);
ctx->Translate(-gfxPoint(destRect.x, destRect.y));
ctx->Translate(-gfxPoint(mDestRect.x, mDestRect.y));
context.Init(aCtx->DeviceContext(), ctx);
}
}
@ -236,7 +229,7 @@ nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
aBuilder->GetBackgroundPaintFlags(),
&bgClipRect, mLayer);
if (surf) {
BlitSurface(dest, destRect, surf);
BlitSurface(dest, mDestRect, surf);
GetUnderlyingFrame()->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get());
GetUnderlyingFrame()->AddStateBits(NS_FRAME_HAS_CACHED_BACKGROUND);
@ -298,16 +291,14 @@ nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (IsVisibleForPainting(aBuilder)) {
nsStyleContext* bgSC;
const nsStyleBackground* bg = nullptr;
bool isThemed = IsThemed();
if (!isThemed &&
if (!IsThemed() &&
nsCSSRendering::FindBackground(PresContext(), this, &bgSC)) {
bg = bgSC->GetStyleBackground();
}
// Create separate items for each background layer.
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
rv = aLists.BorderBackground()->AppendNewToTop(
new (aBuilder) nsDisplayCanvasBackground(aBuilder, this, i,
isThemed, bg));
new (aBuilder) nsDisplayCanvasBackground(aBuilder, this, i));
NS_ENSURE_SUCCESS(rv, rv);
}
}
@ -525,6 +516,39 @@ nsCanvasFrame::Reflow(nsPresContext* aPresContext,
aDesiredSize.SetOverflowAreasToDesiredBounds();
aDesiredSize.mOverflowAreas.UnionWith(
kidDesiredSize.mOverflowAreas + kidPt);
// Handle invalidating fixed-attachment backgrounds propagated to the
// canvas when the canvas size (and therefore the background positioning
// area's size) changes. Such backgrounds are not invalidated in the
// normal manner because the size of the original frame for that background
// may not have changed.
//
// This isn't the right fix for this issue, taken more generally. In
// particular, this doesn't handle fixed-attachment backgrounds that are *not*
// propagated. If a layer with the characteristics tested for below exists
// in a non-propagated background, we should invalidate the "corresponding"
// frame (which subsumes this special case if defined broadly). For now,
// however, this addresses the most common case. Given that this behavior has
// long been broken (non-zero percent background-size may be a new instance,
// but non-zero percent background-position is longstanding), we defer a
// fully correct fix until later.
if (nsSize(aDesiredSize.width, aDesiredSize.height) != GetSize()) {
nsIFrame* rootElementFrame =
aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
nsStyleContext* bgSC =
nsCSSRendering::FindCanvasBackground(this, rootElementFrame);
const nsStyleBackground* bg = bgSC->GetStyleBackground();
if (!bg->IsTransparent()) {
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
const nsStyleBackground::Layer& layer = bg->mLayers[i];
if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
layer.RenderingMightDependOnFrameSize()) {
InvalidateFrame();
break;
}
}
}
}
}
if (prevCanvasFrame) {

View File

@ -116,20 +116,40 @@ protected:
bool mAddedScrollPositionListener;
};
class nsDisplayCanvasBackgroundGeometry : public nsDisplayItemGeometry
{
public:
nsDisplayCanvasBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder, const nsRect& aChildBorder)
: nsDisplayItemGeometry(aItem, aBuilder)
, mChildBorder(aChildBorder)
, mPaddingRect(aItem->GetPaddingRect())
, mContentRect(aItem->GetContentRect())
{}
virtual void MoveBy(const nsPoint& aOffset)
{
mBounds.MoveBy(aOffset);
mPaddingRect.MoveBy(aOffset);
mContentRect.MoveBy(aOffset);
}
nsRect mChildBorder;
nsRect mPaddingRect;
nsRect mContentRect;
};
/**
* 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 nsDisplayBackgroundImage {
class nsDisplayCanvasBackground : public nsDisplayBackground {
public:
nsDisplayCanvasBackground(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
uint32_t aLayer, bool aIsThemed,
const nsStyleBackground* aBackgroundStyle)
: nsDisplayBackgroundImage(aBuilder, aFrame, aLayer, aIsThemed, aBackgroundStyle),
mExtraBackgroundColor(NS_RGBA(0,0,0,0))
nsDisplayCanvasBackground(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, uint32_t aLayer)
: nsDisplayBackground(aBuilder, aFrame, aLayer, true)
{
mExtraBackgroundColor = NS_RGBA(0,0,0,0);
}
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
@ -137,7 +157,7 @@ public:
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE
{
return NS_GET_A(mExtraBackgroundColor) > 0 ||
nsDisplayBackgroundImage::ComputeVisibility(aBuilder, aVisibleRegion,
nsDisplayBackground::ComputeVisibility(aBuilder, aVisibleRegion,
aAllowVisibleRegionExpansion);
}
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
@ -146,12 +166,12 @@ public:
if (NS_GET_A(mExtraBackgroundColor) == 255) {
return nsRegion(GetBounds(aBuilder, aSnap));
}
return nsDisplayBackgroundImage::GetOpaqueRegion(aBuilder, aSnap);
return nsDisplayBackground::GetOpaqueRegion(aBuilder, aSnap);
}
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE
{
nscolor background;
if (!nsDisplayBackgroundImage::IsUniform(aBuilder, &background))
if (!nsDisplayBackground::IsUniform(aBuilder, &background))
return false;
NS_ASSERTION(background == NS_RGBA(0,0,0,0),
"The nsDisplayBackground for a canvas frame doesn't paint "
@ -171,17 +191,39 @@ public:
// We need to override so we don't consider border-radius.
aOutFrames->AppendElement(mFrame);
}
virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
{
// Put background-attachment:fixed canvas background images in their own
// compositing layer. Since we know their background painting area can't
// change (unless the viewport size itself changes), async scrolling
// will work well.
return mBackgroundStyle &&
mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
!mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
nsIFrame *child = mFrame->GetFirstPrincipalChild();
return new nsDisplayCanvasBackgroundGeometry(this, aBuilder,
child ? child->GetRect() : nsRect());;
}
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
const nsDisplayCanvasBackgroundGeometry* geometry = static_cast<const nsDisplayCanvasBackgroundGeometry*>(aGeometry);
if (ShouldFixToViewport(aBuilder)) {
// This is incorrect, We definitely need to check more things here.
return;
}
nsIFrame *child = mFrame->GetFirstPrincipalChild();
bool snap;
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
(child && !geometry->mChildBorder.IsEqualInterior(child->GetRect())) ||
!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect()) ||
!geometry->mContentRect.IsEqualInterior(GetContentRect())) {
if (!RenderingMightDependOnFrameSize() && geometry->mBounds.TopLeft() == GetBounds(aBuilder, &snap).TopLeft()) {
aInvalidRegion->Xor(GetBounds(aBuilder, &snap), geometry->mBounds);
} else {
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
}
}
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) MOZ_OVERRIDE;
@ -196,4 +238,5 @@ private:
nscolor mExtraBackgroundColor;
};
#endif /* nsCanvasFrame_h___ */

View File

@ -1495,7 +1495,7 @@ nsresult
nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists,
bool aForceBackground,
nsDisplayBackgroundImage** aBackground)
nsDisplayBackground** aBackground)
{
*aBackground = nullptr;
@ -1504,7 +1504,7 @@ nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
// true.
if (aBuilder->IsForEventDelivery() || aForceBackground ||
!GetStyleBackground()->IsTransparent() || GetStyleDisplay()->mAppearance) {
return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, this,
return nsDisplayBackground::AppendBackgroundItemsToTop(aBuilder, this,
aLists.BorderBackground(),
aBackground);
}
@ -1530,7 +1530,7 @@ nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
NS_ENSURE_SUCCESS(rv, rv);
}
nsDisplayBackgroundImage* bg;
nsDisplayBackground* bg;
nsresult rv =
DisplayBackgroundUnconditional(aBuilder, aLists, aForceBackground, &bg);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -99,7 +99,7 @@
//----------------------------------------------------------------------
struct nsBoxLayoutMetrics;
class nsDisplayBackgroundImage;
class nsDisplayBackground;
/**
* Implementation of a simple frame that's not splittable and has no
@ -510,7 +510,7 @@ public:
nsresult DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists,
bool aForceBackground,
nsDisplayBackgroundImage** aBackground);
nsDisplayBackground** aBackground);
/**
* Adds display items for standard CSS borders, background and outline for
* for this frame, as necessary. Checks IsVisibleForPainting and won't

View File

@ -1671,6 +1671,56 @@ CanScrollWithBlitting(nsIFrame* aFrame)
return true;
}
static void
InvalidateFixedBackgroundFramesFromList(nsDisplayListBuilder* aBuilder,
nsIFrame* aMovingFrame,
const nsDisplayList& aList)
{
for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
nsDisplayList* sublist = item->GetSameCoordinateSystemChildren();
if (sublist) {
InvalidateFixedBackgroundFramesFromList(aBuilder, aMovingFrame, *sublist);
continue;
}
nsIFrame* f = item->GetUnderlyingFrame();
if (f &&
item->IsVaryingRelativeToMovingFrame(aBuilder, aMovingFrame)) {
if (FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(aBuilder, item)) {
// FrameLayerBuilder does not take care of scrolling this one
f->InvalidateFrame();
}
}
}
}
static void
InvalidateFixedBackgroundFrames(nsIFrame* aRootFrame,
nsIFrame* aMovingFrame,
const nsRect& aUpdateRect)
{
if (!aMovingFrame->PresContext()->MayHaveFixedBackgroundFrames())
return;
NS_ASSERTION(aRootFrame != aMovingFrame,
"The root frame shouldn't be the one that's moving, that makes no sense");
// Build the 'after' display list over the whole area of interest.
nsDisplayListBuilder builder(aRootFrame, nsDisplayListBuilder::OTHER, true);
builder.EnterPresShell(aRootFrame, aUpdateRect);
nsDisplayList list;
nsresult rv =
aRootFrame->BuildDisplayListForStackingContext(&builder, aUpdateRect, &list);
builder.LeavePresShell(aRootFrame, aUpdateRect);
if (NS_FAILED(rv))
return;
nsRegion visibleRegion(aUpdateRect);
list.ComputeVisibilityForRoot(&builder, &visibleRegion);
InvalidateFixedBackgroundFramesFromList(&builder, aMovingFrame, list);
list.DeleteAll();
}
bool nsGfxScrollFrameInner::IsIgnoringViewportClipping() const
{
if (!mIsRoot)
@ -1746,11 +1796,14 @@ void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
AdjustViews(mScrolledFrame);
// We need to call this after fixing up the view positions
// to be consistent with the frame hierarchy.
bool invalidate = false;
bool canScrollWithBlitting = CanScrollWithBlitting(mOuter);
mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
if (IsScrollingActive()) {
if (!canScrollWithBlitting) {
MarkInactive();
} else {
invalidate = true;
}
}
if (canScrollWithBlitting) {
@ -1758,6 +1811,16 @@ void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
}
mOuter->SchedulePaint();
if (invalidate) {
nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter);
nsRect update =
GetScrollPortRect() + mOuter->GetOffsetToCrossDoc(displayRoot);
nsRect displayRootUpdate = update.ConvertAppUnitsRoundOut(
mOuter->PresContext()->AppUnitsPerDevPixel(),
displayRoot->PresContext()->AppUnitsPerDevPixel());
InvalidateFixedBackgroundFrames(displayRoot, mScrolledFrame, displayRootUpdate);
}
}
/**

View File

@ -2236,6 +2236,7 @@ public:
/**
* Called when a frame is about to be removed and needs to be invalidated.
* Normally does nothing since DLBI handles removed frames.
*
*/
virtual void InvalidateFrameForRemoval() {}

View File

@ -1833,7 +1833,7 @@ nsStyleBackground::Position::SetInitialValues()
}
bool
nsStyleBackground::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImage) const
nsStyleBackground::Size::DependsOnFrameSize(const nsStyleImage& aImage) const
{
NS_ABORT_IF_FALSE(aImage.GetType() != eStyleImageType_Null,
"caller should have handled this");
@ -1963,15 +1963,14 @@ nsStyleBackground::Layer::SetInitialValues()
}
bool
nsStyleBackground::Layer::RenderingMightDependOnPositioningAreaSizeChange() const
nsStyleBackground::Layer::RenderingMightDependOnFrameSize() const
{
// Do we even have an image?
if (mImage.IsEmpty()) {
return false;
}
return mPosition.DependsOnPositioningAreaSize() ||
mSize.DependsOnPositioningAreaSize(mImage);
return mPosition.DependsOnFrameSize() || mSize.DependsOnFrameSize(mImage);
}
bool

View File

@ -330,7 +330,7 @@ struct nsStyleBackground {
// True if the effective background image position described by this depends
// on the size of the corresponding frame.
bool DependsOnPositioningAreaSize() const {
bool DependsOnFrameSize() const {
return mXPosition.mPercent != 0.0f || mYPosition.mPercent != 0.0f;
}
@ -371,7 +371,7 @@ struct nsStyleBackground {
// Except for eLengthPercentage, Dimension types which might change
// how a layer is painted when the corresponding frame's dimensions
// change *must* precede all dimension types which are agnostic to
// frame size; see DependsOnDependsOnPositioningAreaSizeSize.
// frame size; see DependsOnFrameSize.
enum DimensionType {
// If one of mWidth and mHeight is eContain or eCover, then both are.
// Also, these two values must equal the corresponding values in
@ -387,7 +387,7 @@ struct nsStyleBackground {
// True if the effective image size described by this depends on the size of
// the corresponding frame, when aImage (which must not have null type) is
// the background image.
bool DependsOnPositioningAreaSize(const nsStyleImage& aImage) const;
bool DependsOnFrameSize(const nsStyleImage& aImage) const;
// Initialize nothing
Size() {}
@ -450,11 +450,11 @@ struct nsStyleBackground {
void SetInitialValues();
// True if the rendering of this layer might change when the size
// of the background positioning area changes. This is true for any
// of the corresponding frame changes. This is true for any
// non-solid-color background whose position or size depends on
// the size of the positioning area. It's also true for SVG images
// whose root <svg> node has a viewBox.
bool RenderingMightDependOnPositioningAreaSizeChange() const;
// the frame size. It's also true for SVG images whose root <svg>
// node has a viewBox.
bool RenderingMightDependOnFrameSize() const;
// An equality operator that compares the images using URL-equality
// rather than pointer-equality.

View File

@ -1165,7 +1165,7 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
// handling events.
// XXX how to handle collapsed borders?
if (aBuilder->IsForEventDelivery()) {
nsresult rv = nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame,
nsresult rv = nsDisplayBackground::AppendBackgroundItemsToTop(aBuilder, aFrame,
lists->BorderBackground());
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1243,7 +1243,7 @@ nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// in its own display item, so do that to take advantage of
// opacity and visibility optimizations
if (deflate == nsMargin(0, 0, 0, 0)) {
nsDisplayBackgroundImage* bg;
nsDisplayBackground* bg;
nsresult rv = DisplayBackgroundUnconditional(aBuilder, aLists, false, &bg);
NS_ENSURE_SUCCESS(rv, rv);
}