Bug 786502 - Fix background-attachment:fixed scrolling with page. r=roc

Fix the size check in nsDisplayBackground::ShouldFixToViewport so that async
scrolling of fixed backgrounds works correctly when zoomed in on Firefox
Mobile. Also make IsFixedItem in nsDisplayList public and use it in
FrameLayerBuilder, so that fixed items are determined and treated consistently.
This commit is contained in:
Chris Lord 2012-09-13 11:34:34 +01:00
parent bb16d413e7
commit d52c9aa58b
4 changed files with 88 additions and 60 deletions

View File

@ -1813,21 +1813,19 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
bool isFixed;
bool forceInactive;
nsIFrame* activeScrolledRoot;
bool forceInactive = false;
if (aFlags & NO_COMPONENT_ALPHA) {
activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(mContainerFrame,
mBuilder->ReferenceFrame());
// When NO_COMPONENT_ALPHA is set, items will be flattened onto the
// reference frame. In this case, force the active scrolled root to
// that frame.
forceInactive = true;
} else if (item->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER) {
nsDisplayScrollLayer* scrollLayerItem =
static_cast<nsDisplayScrollLayer*>(item);
activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(scrollLayerItem->GetScrolledFrame(),
mBuilder->ReferenceFrame());
activeScrolledRoot = mBuilder->ReferenceFrame();
isFixed = mBuilder->IsFixedItem(item, nullptr, activeScrolledRoot);
} else {
activeScrolledRoot = nsLayoutUtils::GetActiveScrolledRootFor(item, mBuilder);
forceInactive = false;
isFixed = mBuilder->IsFixedItem(item, &activeScrolledRoot);
}
// Assign the item to a layer
@ -1865,9 +1863,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
mParameters.mYScale);
}
ownLayer->SetIsFixedPosition(
!nsLayoutUtils::IsScrolledByRootContentDocumentDisplayportScrolling(
activeScrolledRoot, mBuilder));
ownLayer->SetIsFixedPosition(isFixed);
// Update that layer's clip and visible rects.
NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
@ -1916,9 +1912,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip,
activeScrolledRoot);
data->mLayer->SetIsFixedPosition(
!nsLayoutUtils::IsScrolledByRootContentDocumentDisplayportScrolling(
activeScrolledRoot, mBuilder));
data->mLayer->SetIsFixedPosition(isFixed);
InvalidateForLayerChange(item, data->mLayer);

View File

@ -485,19 +485,37 @@ static bool IsFixedFrame(nsIFrame* aFrame)
return aFrame && aFrame->GetParent() && !aFrame->GetParent()->GetParent();
}
static bool IsFixedItem(nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder)
bool
nsDisplayListBuilder::IsFixedItem(nsDisplayItem *aItem,
nsIFrame** aActiveScrolledRoot,
nsIFrame* aOverrideActiveScrolledRoot)
{
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(aItem, aBuilder);
nsIFrame* activeScrolledRoot = aOverrideActiveScrolledRoot;
if (!activeScrolledRoot) {
if (aItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER) {
nsDisplayScrollLayer* scrollLayerItem =
static_cast<nsDisplayScrollLayer*>(aItem);
activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(scrollLayerItem->GetScrolledFrame(),
ReferenceFrame());
} else {
activeScrolledRoot = nsLayoutUtils::GetActiveScrolledRootFor(aItem, this);
}
}
if (aActiveScrolledRoot) {
*aActiveScrolledRoot = activeScrolledRoot;
}
return activeScrolledRoot &&
!nsLayoutUtils::IsScrolledByRootContentDocumentDisplayportScrolling(activeScrolledRoot, aBuilder);
!nsLayoutUtils::IsScrolledByRootContentDocumentDisplayportScrolling(activeScrolledRoot, this);
}
static bool ForceVisiblityForFixedItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem)
{
return aBuilder->GetDisplayPort() && aBuilder->GetHasFixedItems() &&
IsFixedItem(aItem, aBuilder);
aBuilder->IsFixedItem(aItem);
}
void nsDisplayListBuilder::SetDisplayPort(const nsRect& aDisplayPort)
@ -1363,8 +1381,10 @@ RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
uint32_t aLayer)
uint32_t aLayer,
bool aSkipFixedItemBoundsCheck)
: nsDisplayItem(aBuilder, aFrame)
, mIsFixed(false)
, mIsBottommostLayer(true)
, mLayer(aLayer)
{
@ -1396,6 +1416,35 @@ nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
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);
}
}
}
}
}
}
@ -1911,40 +1960,7 @@ nsDisplayBackground::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuild
bool
nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
{
if (mIsThemed)
return false;
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext* bgSC;
bool hasBG =
nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
if (!hasBG)
return false;
const nsStyleBackground* bg = bgSC->GetStyleBackground();
if (!bg->HasFixedBackground())
return false;
const nsStyleBackground::Layer& layer = bg->mLayers[mLayer];
if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED &&
!layer.mImage.IsEmpty()) {
return false;
}
if (layer.mClip != NS_STYLE_BG_CLIP_BORDER)
return false;
if (nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius))
return false;
bool snap;
nsRect bounds = GetBounds(aBuilder, &snap);
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
if (!rootScrollFrame)
return false;
nsIScrollableFrame* scrollable = do_QueryFrame(rootScrollFrame);
nsRect scrollport = scrollable->GetScrollPortRect() +
aBuilder->ToReferenceFrame(rootScrollFrame);
return bounds.Contains(scrollport);
return mIsFixed;
}
void

View File

@ -299,6 +299,18 @@ public:
void SetHasFixedItems() { mHasFixedItems = true; }
bool GetHasFixedItems() { return mHasFixedItems; }
/**
* Determines if this item is scrolled by content-document display-port
* scrolling. aActiveScrolledRoot will be set to the active scrolled root
* of the item. This may not necessarily correspond to the active scrolled
* root of the item's underlying frame.
* If specified, aOverrideActiveScrolledRoot will be treated as the active
* scrolled root.
*/
bool IsFixedItem(nsDisplayItem* aItem,
nsIFrame** aActiveScrolledRoot = nullptr,
nsIFrame* aOverrideActiveScrolledRoot = nullptr);
/**
* @return true if images have been set to decode synchronously.
*/
@ -1604,9 +1616,12 @@ private:
*/
class nsDisplayBackground : public nsDisplayItem {
public:
// aLayer signifies which background layer this item represents
// 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);
uint32_t aLayer, bool aSkipFixedItemBoundsCheck = false);
virtual ~nsDisplayBackground();
// This will create and append new items for all the layers of the
@ -1656,6 +1671,9 @@ protected:
/* 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;

View File

@ -124,7 +124,7 @@ protected:
class nsDisplayCanvasBackground : public nsDisplayBackground {
public:
nsDisplayCanvasBackground(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, uint32_t aLayer)
: nsDisplayBackground(aBuilder, aFrame, aLayer)
: nsDisplayBackground(aBuilder, aFrame, aLayer, true)
{
mExtraBackgroundColor = NS_RGBA(0,0,0,0);
}