Bug 897105 - Part 4: Build display items and layers for sticky positioned elements. r=roc

This commit is contained in:
Corey Ford 2013-09-12 18:56:57 -07:00
Родитель 5eef149568
Коммит d5b2deaa8e
4 изменённых файлов: 157 добавлений и 45 удалений

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

@ -44,6 +44,7 @@
#include "ImageLayers.h"
#include "ImageContainer.h"
#include "nsCanvasFrame.h"
#include "StickyScrollContainer.h"
#include "mozilla/LookAndFeel.h"
#include <stdint.h>
@ -3133,42 +3134,29 @@ nsDisplayFixedPosition::~nsDisplayFixedPosition() {
}
#endif
already_AddRefed<Layer>
nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<Layer> layer =
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
void nsDisplayFixedPosition::SetFixedPositionLayerData(Layer* const aLayer,
nsIFrame* aViewportFrame,
nsSize aViewportSize,
nsPresContext* aPresContext,
const ContainerParameters& aContainerParameters) {
// Find out the rect of the viewport frame relative to the reference frame.
// This, in conjunction with the container scale, will correspond to the
// coordinate-space of the built layer.
float factor = aPresContext->AppUnitsPerDevPixel();
nsPoint origin = aViewportFrame->GetOffsetToCrossDoc(ReferenceFrame());
LayerRect anchorRect(NSAppUnitsToFloatPixels(origin.x, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(origin.y, factor) *
aContainerParameters.mYScale,
NSAppUnitsToFloatPixels(aViewportSize.width, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(aViewportSize.height, factor) *
aContainerParameters.mYScale);
// Work out the anchor point for this fixed position layer. We assume that
// any positioning set (left/top/right/bottom) indicates that the
// corresponding side of its container should be the anchor point,
// defaulting to top-left.
nsIFrame* viewportFrame = mFixedPosFrame->GetParent();
nsPresContext *presContext = viewportFrame->PresContext();
// Fixed position frames are reflowed into the scroll-port size if one has
// been set.
nsSize containingBlockSize = viewportFrame->GetSize();
if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
containingBlockSize = presContext->PresShell()->
GetScrollPositionClampingScrollPortSize();
}
// Find out the rect of the viewport frame relative to the reference frame.
// This, in conjunction with the container scale, will correspond to the
// coordinate-space of the built layer.
float factor = presContext->AppUnitsPerDevPixel();
nsPoint origin = viewportFrame->GetOffsetToCrossDoc(ReferenceFrame());
LayerRect anchorRect(NSAppUnitsToFloatPixels(origin.x, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(origin.y, factor) *
aContainerParameters.mYScale,
NSAppUnitsToFloatPixels(containingBlockSize.width, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(containingBlockSize.height, factor) *
aContainerParameters.mYScale);
LayerPoint anchor = anchorRect.TopLeft();
const nsStylePosition* position = mFixedPosFrame->StylePosition();
@ -3177,11 +3165,11 @@ nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
if (position->mOffset.GetBottomUnit() != eStyleUnit_Auto)
anchor.y = anchorRect.YMost();
layer->SetFixedPositionAnchor(anchor);
aLayer->SetFixedPositionAnchor(anchor);
// Also make sure the layer is aware of any fixed position margins that have
// been set.
nsMargin fixedMargins = presContext->PresShell()->GetContentDocumentFixedPositionMargins();
nsMargin fixedMargins = aPresContext->PresShell()->GetContentDocumentFixedPositionMargins();
LayerMargin fixedLayerMargins(NSAppUnitsToFloatPixels(fixedMargins.top, factor) *
aContainerParameters.mYScale,
NSAppUnitsToFloatPixels(fixedMargins.right, factor) *
@ -3203,7 +3191,29 @@ nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
fixedLayerMargins.top = -1;
}
layer->SetFixedPositionMargins(fixedLayerMargins);
aLayer->SetFixedPositionMargins(fixedLayerMargins);
}
already_AddRefed<Layer>
nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<Layer> layer =
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
nsIFrame* viewportFrame = mFixedPosFrame->GetParent();
nsPresContext *presContext = viewportFrame->PresContext();
// Fixed position frames are reflowed into the scroll-port size if one has
// been set.
nsSize viewportSize = viewportFrame->GetSize();
if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
viewportSize = presContext->PresShell()->
GetScrollPositionClampingScrollPortSize();
}
SetFixedPositionLayerData(layer, viewportFrame, viewportSize, presContext,
aContainerParameters);
return layer.forget();
}
@ -3221,6 +3231,76 @@ bool nsDisplayFixedPosition::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayI
return true;
}
nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsIFrame* aStickyPosFrame,
nsDisplayList* aList)
: nsDisplayFixedPosition(aBuilder, aFrame, aStickyPosFrame, aList) {
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsDisplayStickyPosition::~nsDisplayStickyPosition() {
MOZ_COUNT_DTOR(nsDisplayStickyPosition);
}
#endif
already_AddRefed<Layer>
nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<Layer> layer =
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
StickyScrollContainer* stickyScrollContainer = StickyScrollContainer::
GetStickyScrollContainerForFrame(mFrame);
if (!stickyScrollContainer) {
return layer.forget();
}
nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame());
nsPresContext* presContext = scrollFrame->PresContext();
// Sticky position frames whose scroll frame is the root scroll frame are
// reflowed into the scroll-port size if one has been set.
nsSize scrollFrameSize = scrollFrame->GetSize();
if (scrollFrame == presContext->PresShell()->GetRootScrollFrame() &&
presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
scrollFrameSize = presContext->PresShell()->
GetScrollPositionClampingScrollPortSize();
}
SetFixedPositionLayerData(layer, scrollFrame, scrollFrameSize, presContext,
aContainerParameters);
ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(
stickyScrollContainer->ScrollFrame()->GetScrolledFrame()->GetContent());
float factor = presContext->AppUnitsPerDevPixel();
nsRect outer;
nsRect inner;
stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
LayerRect stickyOuter(NSAppUnitsToFloatPixels(outer.x, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(outer.y, factor) *
aContainerParameters.mYScale,
NSAppUnitsToFloatPixels(outer.width, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(outer.height, factor) *
aContainerParameters.mYScale);
LayerRect stickyInner(NSAppUnitsToFloatPixels(inner.x, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(inner.y, factor) *
aContainerParameters.mYScale,
NSAppUnitsToFloatPixels(inner.width, factor) *
aContainerParameters.mXScale,
NSAppUnitsToFloatPixels(inner.height, factor) *
aContainerParameters.mYScale);
layer->SetStickyPositionData(scrollId, stickyOuter, stickyInner);
return layer.forget();
}
nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList,
nsIFrame* aForFrame,

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

@ -2569,9 +2569,30 @@ public:
NS_DISPLAY_DECL_NAME("FixedPosition", TYPE_FIXED_POSITION)
protected:
void SetFixedPositionLayerData(Layer* const aLayer, nsIFrame* aViewportFrame,
nsSize aViewportSize, nsPresContext* aPresContext,
const ContainerParameters& aContainerParameters);
nsIFrame* mFixedPosFrame;
};
/**
* A display item used to represent sticky position elements. The contents
* gets its own layer and creates a stacking context, and the layer will have
* position-related metadata set on it.
*/
class nsDisplayStickyPosition : public nsDisplayFixedPosition {
public:
nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsIFrame* aStickyPosFrame, nsDisplayList* aList);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayStickyPosition();
#endif
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
};
/**
* This potentially creates a layer for the given list of items, whose
* visibility is determined by the displayport for the given frame instead of

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

@ -1736,6 +1736,12 @@ WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsD
return NS_OK;
}
static bool
IsScrollFrameActive(nsIScrollableFrame* aScrollableFrame)
{
return aScrollableFrame && aScrollableFrame->IsScrollingActive();
}
static nsresult
WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList)
{
@ -1813,10 +1819,14 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
bool useOpacity = HasOpacity() && !nsSVGUtils::CanOptimizeOpacity(this);
bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
IsScrollFrameActive(nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
nsLayoutUtils::SCROLLABLE_SAME_DOC |
nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
if (isTransformed || useOpacity || usingSVGEffects) {
if (isTransformed || useOpacity || usingSVGEffects || useStickyPosition) {
// We don't need to pass ancestor clipping down to our children;
// everything goes inside a display item's child list, and the display
// item itself will be clipped.
@ -1935,6 +1945,13 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
resultList.AppendNewToTop(
new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
}
/* If we have sticky positioning, wrap it in a sticky position item.
*/
if (useStickyPosition) {
resultList.AppendNewToTop(
new (aBuilder) nsDisplayStickyPosition(aBuilder, this, this,
&resultList));
}
/* If we're going to apply a transformation and don't have preserve-3d set, wrap
* everything in an nsDisplayTransform. If there's nothing in the list, don't add
@ -1962,13 +1979,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
aList->AppendToTop(&resultList);
}
static bool
IsRootScrollFrameActive(nsIPresShell* aPresShell)
{
nsIScrollableFrame* sf = aPresShell->GetRootScrollFrameAsScrollable();
return sf && sf->IsScrollingActive();
}
static nsDisplayItem*
WrapInWrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList)
@ -2127,7 +2137,8 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// active, that's pointless and the extra layer(s) created may be wasteful.
bool buildFixedPositionItem = disp->mPosition == NS_STYLE_POSITION_FIXED &&
!child->GetParent()->GetParent() && !aBuilder->IsInFixedPosition() &&
IsRootScrollFrameActive(PresContext()->PresShell()) && !isSVG;
IsScrollFrameActive(PresContext()->PresShell()->GetRootScrollFrameAsScrollable()) &&
!isSVG;
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, child, pseudoStackingContext, buildFixedPositionItem);

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

@ -30,14 +30,14 @@ fuzzy-if(Android,2,4) == right-3.html right-3-ref.html
== scrollframe-reflow-1.html scrollframe-reflow-1-ref.html
== scrollframe-reflow-2.html scrollframe-reflow-2-ref.html
== scrollframe-auto-1.html scrollframe-auto-1-ref.html
== stacking-context-1.html stacking-context-1-ref.html
fuzzy-if(Android,1,3) == stacking-context-1.html stacking-context-1-ref.html
== top-bottom-1.html top-bottom-1-ref.html
== top-bottom-2.html top-bottom-2-ref.html
== top-bottom-3.html top-bottom-3-ref.html
== left-right-1.html left-right-1-ref.html
== left-right-2.html left-right-2-ref.html
== left-right-3.html left-right-3-ref.html
== containing-block-1.html containing-block-1-ref.html
fuzzy-if(Android,4,1) == containing-block-1.html containing-block-1-ref.html
== overconstrained-1.html overconstrained-1-ref.html
== overconstrained-2.html overconstrained-2-ref.html
== overconstrained-3.html overconstrained-3-ref.html