Bug 1267438 - Group ScrollMetadata's optional clip rect and mask layer index into a LayerClip structure. r=mstange
MozReview-Commit-ID: 6W0GZYkioov
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -785,32 +785,49 @@ struct ParamTraits<mozilla::layers::Scro
ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalX) &&
ReadParam(aMsg, aIter, &aResult->mScrollSnapIntervalY) &&
ReadParam(aMsg, aIter, &aResult->mScrollSnapDestination) &&
ReadParam(aMsg, aIter, &aResult->mScrollSnapCoordinates));
}
};
template <>
+struct ParamTraits<mozilla::layers::LayerClip>
+{
+ typedef mozilla::layers::LayerClip paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mClipRect);
+ WriteParam(aMsg, aParam.mMaskLayerIndex);
+ }
+
+ static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+ {
+ return (ReadParam(aMsg, aIter, &aResult->mClipRect) &&
+ ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex));
+ }
+};
+
+template <>
struct ParamTraits<mozilla::layers::ScrollMetadata>
: BitfieldHelper<mozilla::layers::ScrollMetadata>
{
typedef mozilla::layers::ScrollMetadata paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mMetrics);
WriteParam(aMsg, aParam.mSnapInfo);
WriteParam(aMsg, aParam.mScrollParentId);
WriteParam(aMsg, aParam.mBackgroundColor);
WriteParam(aMsg, aParam.GetContentDescription());
WriteParam(aMsg, aParam.mLineScrollAmount);
WriteParam(aMsg, aParam.mPageScrollAmount);
- WriteParam(aMsg, aParam.mMaskLayerIndex);
- WriteParam(aMsg, aParam.mClipRect);
+ WriteParam(aMsg, aParam.mScrollClip);
WriteParam(aMsg, aParam.mHasScrollgrab);
WriteParam(aMsg, aParam.mAllowVerticalScrollWithWheel);
WriteParam(aMsg, aParam.mIsLayersIdRoot);
WriteParam(aMsg, aParam.mUsesContainerScrolling);
WriteParam(aMsg, aParam.mForceDisableApz);
}
static bool ReadContentDescription(const Message* aMsg, void** aIter, paramType* aResult)
@@ -827,18 +844,17 @@ struct ParamTraits<mozilla::layers::Scro
{
return (ReadParam(aMsg, aIter, &aResult->mMetrics) &&
ReadParam(aMsg, aIter, &aResult->mSnapInfo) &&
ReadParam(aMsg, aIter, &aResult->mScrollParentId) &&
ReadParam(aMsg, aIter, &aResult->mBackgroundColor) &&
ReadContentDescription(aMsg, aIter, aResult) &&
ReadParam(aMsg, aIter, &aResult->mLineScrollAmount) &&
ReadParam(aMsg, aIter, &aResult->mPageScrollAmount) &&
- ReadParam(aMsg, aIter, &aResult->mMaskLayerIndex) &&
- ReadParam(aMsg, aIter, &aResult->mClipRect) &&
+ ReadParam(aMsg, aIter, &aResult->mScrollClip) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetHasScrollgrab) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetAllowVerticalScrollWithWheel) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetIsLayersIdRoot) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetUsesContainerScrolling) &&
ReadBoolForBitfield(aMsg, aIter, aResult, ¶mType::SetForceDisableApz));
}
};
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -675,16 +675,62 @@ struct ScrollSnapInfo {
nsPoint mScrollSnapDestination;
// The scroll-snap-coordinates of any descendant frames of the scroll frame,
// relative to the origin of the scrolled frame.
nsTArray<nsPoint> mScrollSnapCoordinates;
};
/**
+ * A clip that applies to a layer, that may be scrolled by some of the
+ * scroll frames associated with the layer.
+ */
+struct LayerClip {
+ friend struct IPC::ParamTraits<mozilla::layers::LayerClip>;
+
+public:
+ LayerClip()
+ : mClipRect()
+ , mMaskLayerIndex()
+ {}
+
+ explicit LayerClip(const ParentLayerIntRect& aClipRect)
+ : mClipRect(aClipRect)
+ , mMaskLayerIndex()
+ {}
+
+ bool operator==(const LayerClip& aOther) const
+ {
+ return mClipRect == aOther.mClipRect &&
+ mMaskLayerIndex == aOther.mMaskLayerIndex;
+ }
+
+ void SetClipRect(const ParentLayerIntRect& aClipRect) {
+ mClipRect = aClipRect;
+ }
+ const ParentLayerIntRect& GetClipRect() const {
+ return mClipRect;
+ }
+
+ void SetMaskLayerIndex(const Maybe<size_t>& aIndex) {
+ mMaskLayerIndex = aIndex;
+ }
+ const Maybe<size_t>& GetMaskLayerIndex() const {
+ return mMaskLayerIndex;
+ }
+
+private:
+ ParentLayerIntRect mClipRect;
+
+ // Optionally, specifies a mask layer that's part of the clip.
+ // This is an index into the MetricsMaskLayers array on the Layer.
+ Maybe<size_t> mMaskLayerIndex;
+};
+
+/**
* Metadata about a scroll frame that's stored in the layer tree for use by
* the compositor (including APZ). This includes the scroll frame's FrameMetrics,
* as well as other metadata. We don't put the other metadata into FrameMetrics
* to avoid FrameMetrics becoming too bloated (as a FrameMetrics is e.g. sent
* over IPC for every repaint request for every active scroll frame).
*/
struct ScrollMetadata {
friend struct IPC::ParamTraits<mozilla::layers::ScrollMetadata>;
@@ -696,36 +742,34 @@ public:
ScrollMetadata()
: mMetrics()
, mSnapInfo()
, mScrollParentId(FrameMetrics::NULL_SCROLL_ID)
, mBackgroundColor()
, mContentDescription()
, mLineScrollAmount(0, 0)
, mPageScrollAmount(0, 0)
- , mMaskLayerIndex()
- , mClipRect()
+ , mScrollClip()
, mHasScrollgrab(false)
, mAllowVerticalScrollWithWheel(false)
, mIsLayersIdRoot(false)
, mUsesContainerScrolling(false)
, mForceDisableApz(false)
{}
bool operator==(const ScrollMetadata& aOther) const
{
return mMetrics == aOther.mMetrics &&
mSnapInfo == aOther.mSnapInfo &&
mScrollParentId == aOther.mScrollParentId &&
mBackgroundColor == aOther.mBackgroundColor &&
// don't compare mContentDescription
mLineScrollAmount == aOther.mLineScrollAmount &&
mPageScrollAmount == aOther.mPageScrollAmount &&
- mMaskLayerIndex == aOther.mMaskLayerIndex &&
- mClipRect == aOther.mClipRect &&
+ mScrollClip == aOther.mScrollClip &&
mHasScrollgrab == aOther.mHasScrollgrab &&
mAllowVerticalScrollWithWheel == aOther.mAllowVerticalScrollWithWheel &&
mIsLayersIdRoot == aOther.mIsLayersIdRoot &&
mUsesContainerScrolling == aOther.mUsesContainerScrolling &&
mForceDisableApz == aOther.mForceDisableApz;
}
bool operator!=(const ScrollMetadata& aOther) const
@@ -775,36 +819,38 @@ public:
mLineScrollAmount = size;
}
const LayoutDeviceIntSize& GetPageScrollAmount() const {
return mPageScrollAmount;
}
void SetPageScrollAmount(const LayoutDeviceIntSize& size) {
mPageScrollAmount = size;
}
- void SetMaskLayerIndex(const Maybe<size_t>& aIndex) {
- mMaskLayerIndex = aIndex;
+
+ void SetScrollClip(const Maybe<LayerClip>& aScrollClip) {
+ mScrollClip = aScrollClip;
+ }
+ const Maybe<LayerClip>& GetScrollClip() const {
+ return mScrollClip;
}
- const Maybe<size_t>& GetMaskLayerIndex() const {
- return mMaskLayerIndex;
+ bool HasScrollClip() const {
+ return mScrollClip.isSome();
+ }
+ const LayerClip& ScrollClip() const {
+ return mScrollClip.ref();
+ }
+ LayerClip& ScrollClip() {
+ return mScrollClip.ref();
}
- void SetClipRect(const Maybe<ParentLayerIntRect>& aClipRect)
- {
- mClipRect = aClipRect;
+ bool HasMaskLayer() const {
+ return HasScrollClip() && ScrollClip().GetMaskLayerIndex();
}
- const Maybe<ParentLayerIntRect>& GetClipRect() const
- {
- return mClipRect;
- }
- bool HasClipRect() const {
- return mClipRect.isSome();
- }
- const ParentLayerIntRect& ClipRect() const {
- return mClipRect.ref();
+ Maybe<ParentLayerIntRect> GetClipRect() const {
+ return mScrollClip.isSome() ? Some(mScrollClip->GetClipRect()) : Nothing();
}
void SetHasScrollgrab(bool aHasScrollgrab) {
mHasScrollgrab = aHasScrollgrab;
}
bool GetHasScrollgrab() const {
return mHasScrollgrab;
}
@@ -851,23 +897,23 @@ private:
nsCString mContentDescription;
// The value of GetLineScrollAmount(), for scroll frames.
LayoutDeviceIntSize mLineScrollAmount;
// The value of GetPageScrollAmount(), for scroll frames.
LayoutDeviceIntSize mPageScrollAmount;
- // An extra clip mask layer to use when compositing a layer with this
- // FrameMetrics. This is an index into the MetricsMaskLayers array on
- // the Layer.
- Maybe<size_t> mMaskLayerIndex;
-
- // The clip rect to use when compositing a layer with this FrameMetrics.
- Maybe<ParentLayerIntRect> mClipRect;
+ // A clip to apply when compositing the layer bearing this ScrollMetadata,
+ // after applying any transform arising from scrolling this scroll frame.
+ // Note that, unlike most other fields of ScrollMetadata, this is allowed
+ // to differ between different layers scrolled by the same scroll frame.
+ // TODO: Group the fields of ScrollMetadata into sub-structures to separate
+ // fields with this property better.
+ Maybe<LayerClip> mScrollClip;
// Whether or not this frame is for an element marked 'scrollgrab'.
bool mHasScrollgrab:1;
// Whether or not the frame can be vertically scrolled with a mouse wheel.
bool mAllowVerticalScrollWithWheel:1;
// Whether these framemetrics are for the root scroll frame (root element if
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -149,18 +149,18 @@ AppendToString(std::stringstream& aStrea
const char* pfx, const char* sfx)
{
aStream << pfx;
AppendToString(aStream, m.GetMetrics(), "{ [metrics=");
AppendToString(aStream, m.GetBackgroundColor(), "] [color=");
if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) {
AppendToString(aStream, m.GetScrollParentId(), "] [scrollParent=");
}
- if (m.HasClipRect()) {
- AppendToString(aStream, m.ClipRect(), "] [clip=");
+ if (m.HasScrollClip()) {
+ AppendToString(aStream, m.ScrollClip().GetClipRect(), "] [clip=");
}
aStream << "] }" << sfx;
}
void
AppendToString(std::stringstream& aStream, const FrameMetrics& m,
const char* pfx, const char* sfx, bool detailed)
{
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3506,18 +3506,17 @@ void AsyncPanZoomController::NotifyLayer
mFrameMetrics.SetCompositionBounds(aLayerMetrics.GetCompositionBounds());
mFrameMetrics.SetRootCompositionSize(aLayerMetrics.GetRootCompositionSize());
mFrameMetrics.SetPresShellResolution(aLayerMetrics.GetPresShellResolution());
mFrameMetrics.SetCumulativeResolution(aLayerMetrics.GetCumulativeResolution());
mScrollMetadata.SetHasScrollgrab(aScrollMetadata.GetHasScrollgrab());
mScrollMetadata.SetLineScrollAmount(aScrollMetadata.GetLineScrollAmount());
mScrollMetadata.SetPageScrollAmount(aScrollMetadata.GetPageScrollAmount());
mScrollMetadata.SetSnapInfo(ScrollSnapInfo(aScrollMetadata.GetSnapInfo()));
- mScrollMetadata.SetClipRect(aScrollMetadata.GetClipRect());
- mScrollMetadata.SetMaskLayerIndex(aScrollMetadata.GetMaskLayerIndex());
+ mScrollMetadata.SetScrollClip(aScrollMetadata.GetScrollClip());
mScrollMetadata.SetIsLayersIdRoot(aScrollMetadata.IsLayersIdRoot());
mScrollMetadata.SetUsesContainerScrolling(aScrollMetadata.UsesContainerScrolling());
mFrameMetrics.SetIsScrollInfoLayer(aLayerMetrics.IsScrollInfoLayer());
mScrollMetadata.SetForceDisableApz(aScrollMetadata.IsApzForceDisabled());
if (scrollOffsetUpdated) {
APZC_LOG("%p updating scroll offset from %s to %s\n", this,
ToString(mFrameMetrics.GetScrollOffset()).c_str(),
--- a/gfx/layers/apz/test/gtest/TestHitTesting.cpp
+++ b/gfx/layers/apz/test/gtest/TestHitTesting.cpp
@@ -555,17 +555,17 @@ TEST_F(APZHitTestingTester, HitTestingRe
// Importantly, give the layer a layer clip which leaks outside of the
// subframe's composition bounds.
ScrollMetadata rootMetadata = BuildScrollMetadata(
FrameMetrics::START_SCROLL_ID, CSSRect(0,0,200,200),
ParentLayerRect(0,0,200,200));
ScrollMetadata subframeMetadata = BuildScrollMetadata(
FrameMetrics::START_SCROLL_ID + 1, CSSRect(0,0,200,200),
ParentLayerRect(0,0,200,100));
- subframeMetadata.SetClipRect(Some(ParentLayerIntRect(0,0,200,100)));
+ subframeMetadata.SetScrollClip(Some(LayerClip(ParentLayerIntRect(0,0,200,100))));
layers[2]->SetScrollMetadata({subframeMetadata, rootMetadata});
layers[2]->SetClipRect(Some(ParentLayerIntRect(0,0,200,200)));
SetEventRegionsBasedOnBottommostMetrics(layers[2]);
// Build the hit testing tree.
ScopedLayerTreeRegistration registration(manager, 0, root, mcc);
manager->UpdateHitTestingTree(nullptr, root, false, 0, 0);
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -927,18 +927,18 @@ AsyncCompositionManager::ApplyAsyncConte
// AlignFixedAndStickyLayers may have changed the clip rect, so we have to
// read it from the layer again.
asyncClip = aLayer->AsLayerComposite()->GetShadowClipRect();
// Combine the local clip with the ancestor scrollframe clip. This is not
// included in the async transform above, since the ancestor clip should not
// move with this APZC.
- if (scrollMetadata.HasClipRect()) {
- ParentLayerIntRect clip = scrollMetadata.ClipRect();
+ if (scrollMetadata.HasScrollClip()) {
+ ParentLayerIntRect clip = scrollMetadata.ScrollClip().GetClipRect();
if (aLayer->GetParent() && aLayer->GetParent()->GetTransformIsPerspective()) {
// If our parent layer has a perspective transform, we want to apply
// our scroll clip to it instead of to this layer (see bug 1168263).
// A layer with a perspective transform shouldn't have multiple
// children with FrameMetrics, nor a child with multiple FrameMetrics.
// (A child with multiple FrameMetrics would mean that there's *another*
// scrollable element between the one with the CSS perspective and the
// transformed element. But you'd have to use preserve-3d on the inner
@@ -956,20 +956,23 @@ AsyncCompositionManager::ApplyAsyncConte
// the ancestor mask layers for scroll frames *inside* the current scroll
// frame, so these are the ones we need to shift by our async transform.
for (Layer* ancestorMaskLayer : ancestorMaskLayers) {
SetShadowTransform(ancestorMaskLayer,
ancestorMaskLayer->GetLocalTransformTyped() * asyncTransform);
}
// Append the ancestor mask layer for this scroll frame to ancestorMaskLayers.
- if (scrollMetadata.GetMaskLayerIndex()) {
- size_t maskLayerIndex = scrollMetadata.GetMaskLayerIndex().value();
- Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex);
- ancestorMaskLayers.AppendElement(ancestorMaskLayer);
+ if (scrollMetadata.HasScrollClip()) {
+ const LayerClip& scrollClip = scrollMetadata.ScrollClip();
+ if (scrollClip.GetMaskLayerIndex()) {
+ size_t maskLayerIndex = scrollClip.GetMaskLayerIndex().value();
+ Layer* ancestorMaskLayer = aLayer->GetAncestorMaskLayerAt(maskLayerIndex);
+ ancestorMaskLayers.AppendElement(ancestorMaskLayer);
+ }
}
}
if (hasAsyncTransform || clipDeferredFromChildren) {
aLayer->AsLayerComposite()->SetShadowClipRect(asyncClip);
}
if (hasAsyncTransform) {
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -4617,17 +4617,17 @@ ContainerState::SetupScrollingMetadata(N
}
AutoTArray<ScrollMetadata,2> metricsArray;
if (aEntry->mBaseScrollMetadata) {
metricsArray.AppendElement(*aEntry->mBaseScrollMetadata);
// The base FrameMetrics was not computed by the nsIScrollableframe, so it
// should not have a mask layer.
- MOZ_ASSERT(!aEntry->mBaseScrollMetadata->GetMaskLayerIndex());
+ MOZ_ASSERT(!aEntry->mBaseScrollMetadata->HasMaskLayer());
}
// Any extra mask layers we need to attach to FrameMetrics.
nsTArray<RefPtr<Layer>> maskLayers;
for (const DisplayItemScrollClip* scrollClip = aEntry->mScrollClip;
scrollClip && scrollClip != mContainerScrollClip;
scrollClip = scrollClip->mParent) {
@@ -4654,30 +4654,31 @@ ContainerState::SetupScrollingMetadata(N
// The clip in between this scrollframe and its ancestor scrollframe
// requires a mask layer. Since this mask layer should not move with
// the APZC associated with this FrameMetrics, we attach the mask
// layer as an additional, separate clip.
Maybe<size_t> nextIndex = Some(maskLayers.Length());
RefPtr<Layer> maskLayer =
CreateMaskLayer(aEntry->mLayer, *clip, nextIndex, clip->GetRoundedRectCount());
if (maskLayer) {
- metadata->SetMaskLayerIndex(nextIndex);
+ MOZ_ASSERT(metadata->HasScrollClip());
+ metadata->ScrollClip().SetMaskLayerIndex(nextIndex);
maskLayers.AppendElement(maskLayer);
}
}
metricsArray.AppendElement(*metadata);
}
// Watch out for FrameMetrics copies in profiles
aEntry->mLayer->SetScrollMetadata(metricsArray);
aEntry->mLayer->SetAncestorMaskLayers(maskLayers);
}
-static inline const Maybe<ParentLayerIntRect>&
+static inline Maybe<ParentLayerIntRect>
GetStationaryClipInContainer(Layer* aLayer)
{
if (size_t metricsCount = aLayer->GetScrollMetadataCount()) {
return aLayer->GetScrollMetadata(metricsCount - 1).GetClipRect();
}
return aLayer->GetClipRect();
}
@@ -4701,17 +4702,17 @@ ContainerState::PostprocessRetainedLayer
mFlattenToSingleLayer ? mContainerAnimatedGeometryRoot : e->mAnimatedGeometryRoot;
OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions, animatedGeometryRootForOpaqueness);
SetupScrollingMetadata(e);
if (hideAll) {
e->mVisibleRegion.SetEmpty();
} else if (!e->mLayer->IsScrollbarContainer()) {
- const Maybe<ParentLayerIntRect>& clipRect = GetStationaryClipInContainer(e->mLayer);
+ Maybe<ParentLayerIntRect> clipRect = GetStationaryClipInContainer(e->mLayer);
if (clipRect && opaqueRegionForContainer >= 0 &&
opaqueRegions[opaqueRegionForContainer].mOpaqueRegion.Contains(clipRect->ToUnknownRect())) {
e->mVisibleRegion.SetEmpty();
} else if (data) {
e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
}
}
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -8868,17 +8868,17 @@ nsLayoutUtils::ComputeScrollMetadata(nsI
ParentLayerRect frameBounds = LayoutDeviceRect::FromAppUnits(compositionBounds, auPerDevPixel)
* metrics.GetCumulativeResolution()
* layerToParentLayerScale;
if (aClipRect) {
ParentLayerRect rect = LayoutDeviceRect::FromAppUnits(*aClipRect, auPerDevPixel)
* metrics.GetCumulativeResolution()
* layerToParentLayerScale;
- metadata.SetClipRect(Some(RoundedToInt(rect)));
+ metadata.SetScrollClip(Some(LayerClip(RoundedToInt(rect))));
}
// For the root scroll frame of the root content document (RCD-RSF), the above calculation
// will yield the size of the viewport frame as the composition bounds, which
// doesn't actually correspond to what is visible when
// nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
// the prescontext that the viewport frame is reflowed into. In that case if our
// document has a widget then the widget's bounds will correspond to what is