mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 758620 - Force fixed-position frames to have their own layers. r=roc
Introduce a new display-list item 'nsDisplayFixedPosition' that represents fixed-position elements. This item cannot be merged, which forces fixed position elements to have their own layer, and has a BuildLayer implementation that sets the necessary metadata on a Layer to be able to maintain its position correctly during composition when asynchronously panning and zooming.
This commit is contained in:
parent
0609d80d0e
commit
737f39fdfa
@ -731,6 +731,15 @@ public:
|
||||
*/
|
||||
void SetIsFixedPosition(bool aFixedPosition) { mIsFixedPosition = aFixedPosition; }
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* If a layer is "fixed position", this determines which point on the layer
|
||||
* is considered the "anchor" point, that is, the point which remains in the
|
||||
* same position when compositing the layer tree with a transformation
|
||||
* (such as when asynchronously scrolling and zooming).
|
||||
*/
|
||||
void SetFixedPositionAnchor(const gfxPoint& aAnchor) { mAnchor = aAnchor; }
|
||||
|
||||
// These getters can be used anytime.
|
||||
float GetOpacity() { return mOpacity; }
|
||||
const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nsnull; }
|
||||
@ -743,6 +752,7 @@ public:
|
||||
virtual Layer* GetLastChild() { return nsnull; }
|
||||
const gfx3DMatrix& GetTransform() { return mTransform; }
|
||||
bool GetIsFixedPosition() { return mIsFixedPosition; }
|
||||
gfxPoint GetFixedPositionAnchor() { return mAnchor; }
|
||||
Layer* GetMaskLayer() { return mMaskLayer; }
|
||||
|
||||
/**
|
||||
@ -992,6 +1002,7 @@ protected:
|
||||
bool mUseClipRect;
|
||||
bool mUseTileSourceRect;
|
||||
bool mIsFixedPosition;
|
||||
gfxPoint mAnchor;
|
||||
DebugOnly<PRUint32> mDebugColorIndex;
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@ include protocol PRenderFrame;
|
||||
include "gfxipc/ShadowLayerUtils.h";
|
||||
|
||||
using gfx3DMatrix;
|
||||
using gfxPoint;
|
||||
using gfxRGBA;
|
||||
using nsIntPoint;
|
||||
using nsIntRect;
|
||||
@ -85,6 +86,7 @@ struct CommonLayerAttributes {
|
||||
bool useClipRect;
|
||||
nsIntRect clipRect;
|
||||
bool isFixedPosition;
|
||||
gfxPoint fixedPositionAnchor;
|
||||
nullable PLayer maskLayer;
|
||||
};
|
||||
|
||||
|
@ -291,6 +291,7 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
|
||||
common.clipRect() = (common.useClipRect() ?
|
||||
*mutant->GetClipRect() : nsIntRect());
|
||||
common.isFixedPosition() = mutant->GetIsFixedPosition();
|
||||
common.fixedPositionAnchor() = mutant->GetFixedPositionAnchor();
|
||||
if (Layer* maskLayer = mutant->GetMaskLayer()) {
|
||||
common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
|
||||
} else {
|
||||
|
@ -207,6 +207,7 @@ ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
||||
static bool fixedPositionLayersEnabled = getenv("MOZ_ENABLE_FIXED_POSITION_LAYERS") != 0;
|
||||
if (fixedPositionLayersEnabled) {
|
||||
layer->SetIsFixedPosition(common.isFixedPosition());
|
||||
layer->SetFixedPositionAnchor(common.fixedPositionAnchor());
|
||||
}
|
||||
if (PLayerParent* maskLayer = common.maskLayerParent()) {
|
||||
layer->SetMaskLayer(cast(maskLayer)->AsLayer());
|
||||
|
@ -427,6 +427,27 @@ struct ParamTraits<gfxMatrix>
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<gfxPoint>
|
||||
{
|
||||
typedef gfxPoint paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.x);
|
||||
WriteParam(aMsg, aParam.y);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
if (ReadParam(aMsg, aIter, &aResult->x) &&
|
||||
ReadParam(aMsg, aIter, &aResult->y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<gfxSize>
|
||||
{
|
||||
|
@ -2002,6 +2002,68 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame,
|
||||
nsDisplayList* aList)
|
||||
: nsDisplayOwnLayer(aBuilder, aFrame, aList) {
|
||||
MOZ_COUNT_CTOR(nsDisplayFixedPosition);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplayFixedPosition::~nsDisplayFixedPosition() {
|
||||
MOZ_COUNT_DTOR(nsDisplayFixedPosition);
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<Layer> layer =
|
||||
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
|
||||
|
||||
// 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 = mFrame->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 = aBuilder->ToReferenceFrame(viewportFrame);
|
||||
gfxRect 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);
|
||||
|
||||
gfxPoint anchor(anchorRect.x, anchorRect.y);
|
||||
|
||||
const nsStylePosition* position = mFrame->GetStylePosition();
|
||||
if (position->mOffset.GetRightUnit() != eStyleUnit_Auto)
|
||||
anchor.x = anchorRect.XMost();
|
||||
if (position->mOffset.GetBottomUnit() != eStyleUnit_Auto)
|
||||
anchor.y = anchorRect.YMost();
|
||||
|
||||
layer->SetFixedPositionAnchor(anchor);
|
||||
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aList,
|
||||
nsIFrame* aForFrame,
|
||||
|
@ -1909,6 +1909,25 @@ public:
|
||||
NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item used to represent fixed position elements. This will ensure
|
||||
* the contents gets its own layer, and that the built layer will have
|
||||
* position-related metadata set on it.
|
||||
*/
|
||||
class nsDisplayFixedPosition : public nsDisplayOwnLayer {
|
||||
public:
|
||||
nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsDisplayList* aList);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayFixedPosition();
|
||||
#endif
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters);
|
||||
NS_DISPLAY_DECL_NAME("FixedPosition", TYPE_OWN_LAYER)
|
||||
};
|
||||
|
||||
/**
|
||||
* This potentially creates a layer for the given list of items, whose
|
||||
* visibility is determined by the displayport for the given frame instead of
|
||||
|
@ -2168,8 +2168,16 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
// Genuine stacking contexts, and positioned pseudo-stacking-contexts,
|
||||
// go in this level.
|
||||
if (!list.IsEmpty()) {
|
||||
rv = aLists.PositionedDescendants()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayWrapList(aBuilder, child, &list));
|
||||
// Make sure the root of a fixed position frame sub-tree gets the
|
||||
// correct displaylist item type.
|
||||
nsDisplayItem* item;
|
||||
if (!child->GetParent()->GetParent() &&
|
||||
disp->mPosition == NS_STYLE_POSITION_FIXED) {
|
||||
item = new (aBuilder) nsDisplayFixedPosition(aBuilder, child, &list);
|
||||
} else {
|
||||
item = new (aBuilder) nsDisplayWrapList(aBuilder, child, &list);
|
||||
}
|
||||
rv = aLists.PositionedDescendants()->AppendNewToTop(item);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} else if (disp->IsFloating()) {
|
||||
|
Loading…
Reference in New Issue
Block a user