Bug 967844. Part 3: Setup FrameMetrics from FrameLayerBuilder based on animated geometry roots. r=mattwoodrow

--HG--
extra : rebase_source : d30d2af626038cc556fcd3add9a3876be2c58239
This commit is contained in:
Robert O'Callahan 2014-08-31 15:29:24 +12:00
parent 864c99dd28
commit 2d6bf232ea
21 changed files with 470 additions and 134 deletions

View File

@ -2670,48 +2670,23 @@ nsDOMWindowUtils::SetAsyncScrollOffset(nsIDOMNode* aNode,
if (!element) {
return NS_ERROR_INVALID_ARG;
}
nsIFrame* frame = element->GetPrimaryFrame();
if (!frame) {
return NS_ERROR_UNEXPECTED;
}
nsIScrollableFrame* scrollable = do_QueryFrame(frame);
nsPresContext* presContext = frame->PresContext();
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
if (!scrollable) {
if (rootScrollFrame && rootScrollFrame->GetContent() == element) {
frame = rootScrollFrame;
scrollable = do_QueryFrame(frame);
}
}
if (!scrollable) {
return NS_ERROR_UNEXPECTED;
}
Layer* layer = FrameLayerBuilder::GetDedicatedLayer(scrollable->GetScrolledFrame(),
nsDisplayItem::TYPE_SCROLL_LAYER);
if (!layer) {
if (rootScrollFrame == frame && !presContext->GetParentPresContext()) {
nsIWidget* widget = GetWidget();
if (widget) {
LayerManager* manager = widget->GetLayerManager();
if (manager) {
layer = manager->GetRoot();
}
}
}
if (!layer) {
return NS_ERROR_UNEXPECTED;
}
}
FrameMetrics::ViewID viewId;
if (!nsLayoutUtils::FindIDFor(element, &viewId)) {
return NS_ERROR_UNEXPECTED;
}
ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
nsIWidget* widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
LayerManager* manager = widget->GetLayerManager();
if (!manager) {
return NS_ERROR_FAILURE;
}
ShadowLayerForwarder* forwarder = manager->AsShadowForwarder();
if (!forwarder || !forwarder->HasShadowManager()) {
return NS_ERROR_UNEXPECTED;
}
forwarder->GetShadowManager()->SendSetAsyncScrollOffset(
layer->AsShadowableLayer()->GetShadow(), viewId, aX, aY);
forwarder->GetShadowManager()->SendSetAsyncScrollOffset(viewId, aX, aY);
return NS_OK;
}

View File

@ -123,6 +123,7 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m,
AppendToString(aStream, m.GetScrollOffset(), " s=");
AppendToString(aStream, m.mDisplayPort, " dp=");
AppendToString(aStream, m.mCriticalDisplayPort, " cdp=");
AppendToString(aStream, m.GetBackgroundColor(), " color=");
if (!detailed) {
AppendToString(aStream, m.GetScrollId(), " scrollId=");
if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) {

View File

@ -687,26 +687,35 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
return true;
}
static AsyncPanZoomController*
GetAPZCForViewID(Layer* aLayer, FrameMetrics::ViewID aScrollID)
{
for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
if (aLayer->GetFrameMetrics(i).GetScrollId() == aScrollID) {
return aLayer->GetAsyncPanZoomController(i);
}
}
ContainerLayer* container = aLayer->AsContainerLayer();
if (container) {
for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
AsyncPanZoomController* c = GetAPZCForViewID(l, aScrollID);
if (c) {
return c;
}
}
}
return nullptr;
}
bool
LayerTransactionParent::RecvSetAsyncScrollOffset(PLayerParent* aLayer,
const FrameMetrics::ViewID& aId,
LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID,
const int32_t& aX, const int32_t& aY)
{
if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
return false;
}
Layer* layer = cast(aLayer)->AsLayer();
if (!layer) {
return false;
}
AsyncPanZoomController* controller = nullptr;
for (uint32_t i = 0; i < layer->GetFrameMetricsCount(); i++) {
if (layer->GetFrameMetrics(i).GetScrollId() == aId) {
controller = layer->GetAsyncPanZoomController(i);
break;
}
}
AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID);
if (!controller) {
return false;
}

View File

@ -126,7 +126,7 @@ protected:
virtual bool RecvGetAnimationTransform(PLayerParent* aParent,
MaybeTransform* aTransform)
MOZ_OVERRIDE;
virtual bool RecvSetAsyncScrollOffset(PLayerParent* aLayer, const FrameMetrics::ViewID& aId,
virtual bool RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aId,
const int32_t& aX, const int32_t& aY) MOZ_OVERRIDE;
virtual bool RecvGetAPZTestData(APZTestData* aOutData);

View File

@ -81,10 +81,10 @@ parent:
// be void_t.
sync GetAnimationTransform(PLayer layer) returns (MaybeTransform transform);
// The next time this layer is composited, add this async scroll offset in
// CSS pixels.
// The next time the layer tree is composited, add this async scroll offset in
// CSS pixels for the given ViewID.
// Useful for testing rendering of async scrolling.
async SetAsyncScrollOffset(PLayer layer, ViewID id, int32_t x, int32_t y);
async SetAsyncScrollOffset(ViewID id, int32_t x, int32_t y);
// Drop any front buffers that might be retained on the compositor
// side.

View File

@ -259,6 +259,7 @@ public:
mNeedComponentAlpha(false),
mForceTransparentSurface(false),
mHideAllLayersBelow(false),
mOpaqueForAnimatedGeometryRootParent(false),
mImage(nullptr),
mCommonClipCount(-1),
mNewChildLayersIndex(-1),
@ -458,6 +459,13 @@ public:
* Set if all layers below this ThebesLayer should be hidden.
*/
bool mHideAllLayersBelow;
/**
* Set if the opaque region for this layer can be applied to the parent
* animated geometry root of this layer's animated geometry root.
* We set this when a ThebesLayer's animated geometry root is a scrollframe
* and the ThebesLayer completely fills the displayport of the scrollframe.
*/
bool mOpaqueForAnimatedGeometryRootParent;
/**
* Stores the pointer to the nsDisplayImage if we want to
@ -532,6 +540,9 @@ struct NewLayerEntry {
nsRefPtr<Layer> mLayer;
const nsIFrame* mAnimatedGeometryRoot;
const nsIFrame* mFixedPosFrameForLayerData;
// If non-null, this FrameMetrics is set to the be the first FrameMetrics
// on the layer.
UniquePtr<FrameMetrics> mBaseFrameMetrics;
// The following are only used for retained layers (for occlusion
// culling of those layers). These regions are all relative to the
// container reference frame.
@ -756,14 +767,22 @@ protected:
bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque);
/**
* Set FrameMetrics and scroll-induced clipping on aEntry's layer.
*/
void SetupScrollingMetadata(NewLayerEntry* aEntry);
/**
* Applies occlusion culling.
* For each layer in mNewChildLayers, remove from its visible region the
* opaque regions of the layers at higher z-index, but only if they have
* the same animated geometry root and fixed-pos frame ancestor.
* The opaque region for the child layers that share the same animated
* geometry root as the container frame is returned in
* *aOpaqueRegionForContainer.
*
* Also sets scroll metadata on the layers.
*/
void ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer);
void PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer);
/**
* Computes the snapped opaque area of aItem. Sets aList's opaque flag
@ -776,7 +795,8 @@ protected:
const nsIFrame* aFixedPosFrame,
const DisplayItemClip& aClip,
nsDisplayList* aList,
bool* aHideAllLayersBelow);
bool* aHideAllLayersBelow,
bool* aOpaqueForAnimatedGeometryRootParent);
/**
* Indicate that we are done adding items to the ThebesLayer at the top of
@ -2140,12 +2160,7 @@ ContainerState::PopThebesLayerData()
newLayerEntry->mVisibleRegion = data->mVisibleRegion;
newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
if (nsLayoutUtils::GetScrollableFrameFor(newLayerEntry->mAnimatedGeometryRoot) &&
!nsDisplayScrollLayer::IsConstructingScrollLayerForScrolledFrame(newLayerEntry->mAnimatedGeometryRoot)) {
// Async scrolling not currently active so we can propagate our opaque region
// up to the parent animated geometry root.
newLayerEntry->mOpaqueForAnimatedGeometryRootParent = true;
}
newLayerEntry->mOpaqueForAnimatedGeometryRootParent = data->mOpaqueForAnimatedGeometryRootParent;
} else {
SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion);
}
@ -2662,7 +2677,8 @@ ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
const nsIFrame* aFixedPosFrame,
const DisplayItemClip& aClip,
nsDisplayList* aList,
bool* aHideAllLayersBelow)
bool* aHideAllLayersBelow,
bool* aOpaqueForAnimatedGeometryRootParent)
{
bool snapOpaque;
nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque);
@ -2690,6 +2706,23 @@ ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
if (aFixedPosFrame && ItemCoversScrollableArea(aItem, opaque)) {
*aHideAllLayersBelow = true;
}
nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(aAnimatedGeometryRoot);
if (sf) {
nsRect displayport;
bool usingDisplayport =
nsLayoutUtils::GetDisplayPort(aAnimatedGeometryRoot->GetContent(), &displayport);
if (!usingDisplayport) {
// No async scrolling, so all that matters is that the layer contents
// cover the scrollport.
displayport = sf->GetScrollPortRect();
}
nsIFrame* scrollFrame = do_QueryFrame(sf);
displayport += scrollFrame->GetOffsetToCrossDoc(mContainerReferenceFrame);
if (opaque.Contains(displayport)) {
*aOpaqueForAnimatedGeometryRootParent = true;
}
}
}
return opaquePixels;
}
@ -2970,15 +3003,22 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList,
newLayerEntry->mVisibleRegion = itemVisibleRect;
newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item,
animatedGeometryRoot, fixedPosFrame, itemClip, aList,
&newLayerEntry->mHideAllLayersBelow);
&newLayerEntry->mHideAllLayersBelow,
&newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
} else {
SetOuterVisibleRegionForLayer(ownLayer, itemVisibleRect,
layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr);
}
if (itemType == nsDisplayItem::TYPE_SCROLL_LAYER) {
if (itemType == nsDisplayItem::TYPE_SCROLL_LAYER ||
itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
nsDisplayScrollLayer* scrollItem = static_cast<nsDisplayScrollLayer*>(item);
newLayerEntry->mOpaqueForAnimatedGeometryRootParent =
scrollItem->IsDisplayPortOpaque();
newLayerEntry->mBaseFrameMetrics =
scrollItem->ComputeFrameMetrics(ownLayer, mParameters);
} else if (itemType == nsDisplayItem::TYPE_SUBDOCUMENT) {
newLayerEntry->mBaseFrameMetrics =
static_cast<nsDisplaySubDocument*>(item)->ComputeFrameMetrics(ownLayer, mParameters);
}
/**
@ -3011,7 +3051,8 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList,
nsIntRegion opaquePixels = ComputeOpaqueRect(item,
animatedGeometryRoot, thebesLayerData->mFixedPosFrameForLayerData,
itemClip, aList,
&thebesLayerData->mHideAllLayersBelow);
&thebesLayerData->mHideAllLayersBelow,
&thebesLayerData->mOpaqueForAnimatedGeometryRootParent);
thebesLayerData->Accumulate(this, item, opaquePixels,
itemVisibleRect, itemDrawRect, itemClip);
}
@ -3437,7 +3478,63 @@ FindOpaqueRegionEntry(nsTArray<OpaqueRegionEntry>& aEntries,
}
void
ContainerState::ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer)
ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
{
nsAutoTArray<FrameMetrics,2> metricsArray;
if (aEntry->mBaseFrameMetrics) {
metricsArray.AppendElement(*aEntry->mBaseFrameMetrics);
}
uint32_t baseLength = metricsArray.Length();
nsIntRect tmpClipRect;
const nsIntRect* layerClip = aEntry->mLayer->GetClipRect();
nsIFrame* fParent;
for (const nsIFrame* f = aEntry->mAnimatedGeometryRoot;
f != mContainerAnimatedGeometryRoot;
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(
fParent, mContainerAnimatedGeometryRoot)) {
fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
if (!fParent) {
// This means mContainerAnimatedGeometryRoot was not an ancestor
// of aEntry->mAnimatedGeometryRoot. This is a weird case but it
// can happen, e.g. when a scrolled frame contains a frame with opacity
// which contains a frame that is not scrolled by the scrolled frame.
// For now, we just don't apply any specific async scrolling to this layer.
// It will async-scroll with mContainerAnimatedGeometryRoot, which
// is substandard but not fatal.
metricsArray.SetLength(baseLength);
aEntry->mLayer->SetFrameMetrics(metricsArray);
return;
}
nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(f);
if (!scrollFrame) {
continue;
}
nsRect clipRect(0, 0, -1, -1);
scrollFrame->ComputeFrameMetrics(aEntry->mLayer, mContainerReferenceFrame,
mParameters, &clipRect, &metricsArray);
if (clipRect.width >= 0) {
nsIntRect pixClip = ScaleToNearestPixels(clipRect);
if (layerClip) {
tmpClipRect.IntersectRect(pixClip, *layerClip);
} else {
tmpClipRect = pixClip;
}
layerClip = &tmpClipRect;
// XXX this could cause IPC churn due to cliprects being updated
// twice during layer building --- for non-ThebesLayers that have
// both CSS and scroll clipping.
}
}
aEntry->mLayer->SetClipRect(layerClip);
// Watch out for FrameMetrics copies in profiles
aEntry->mLayer->SetFrameMetrics(metricsArray);
}
void
ContainerState::PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer)
{
nsAutoTArray<OpaqueRegionEntry,4> opaqueRegions;
bool hideAll = false;
@ -3458,6 +3555,10 @@ ContainerState::ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer)
e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
}
SetOuterVisibleRegionForLayer(e->mLayer, e->mVisibleRegion,
e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr);
SetupScrollingMetadata(e);
if (!e->mOpaqueRegion.IsEmpty()) {
const nsIFrame* animatedGeometryRootToCover = e->mAnimatedGeometryRoot;
if (e->mOpaqueForAnimatedGeometryRootParent &&
@ -3485,9 +3586,6 @@ ContainerState::ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer)
}
}
SetOuterVisibleRegionForLayer(e->mLayer, e->mVisibleRegion,
e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr);
if (e->mLayer->GetType() == Layer::TYPE_READBACK) {
// ReadbackLayers need to accurately read what's behind them. So,
// we don't want to do any occlusion culling of layers behind them.
@ -3518,7 +3616,7 @@ ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData,
if (mLayerBuilder->IsBuildingRetainedLayers()) {
nsIntRegion containerOpaqueRegion;
ApplyOcclusionCulling(&containerOpaqueRegion);
PostprocessRetainedLayers(&containerOpaqueRegion);
if (containerOpaqueRegion.Contains(aContainerPixelBounds)) {
aChildItems->SetIsOpaque();
}

View File

@ -647,15 +647,17 @@ static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
}
}
static void RecordFrameMetrics(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
const nsIFrame* aReferenceFrame,
ContainerLayer* aRoot,
ViewID aScrollParentId,
const nsRect& aViewport,
bool aForceNullScrollId,
bool aIsRoot,
const ContainerLayerParameters& aContainerParameters) {
/* static */ FrameMetrics
nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
const nsIFrame* aReferenceFrame,
Layer* aLayer,
ViewID aScrollParentId,
const nsRect& aViewport,
bool aForceNullScrollId,
bool aIsRoot,
const ContainerLayerParameters& aContainerParameters)
{
nsPresContext* presContext = aForFrame->PresContext();
int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
LayoutDeviceToLayerScale resolution(aContainerParameters.mXScale, aContainerParameters.mYScale);
@ -673,7 +675,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
nsRect dp;
if (nsLayoutUtils::GetDisplayPort(content, &dp)) {
metrics.mDisplayPort = CSSRect::FromAppUnits(dp);
nsLayoutUtils::LogTestDataForPaint(aRoot->Manager(), scrollId, "displayport",
nsLayoutUtils::LogTestDataForPaint(aLayer->Manager(), scrollId, "displayport",
metrics.mDisplayPort);
}
if (nsLayoutUtils::GetCriticalDisplayPort(content, &dp)) {
@ -861,7 +863,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
}
}
aRoot->SetFrameMetrics(metrics);
return metrics;
}
nsDisplayListBuilder::~nsDisplayListBuilder() {
@ -1292,10 +1294,11 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
nsRect viewport(aBuilder->ToReferenceFrame(aForFrame), aForFrame->GetSize());
RecordFrameMetrics(aForFrame, rootScrollFrame,
aBuilder->FindReferenceFrameFor(aForFrame),
root, FrameMetrics::NULL_SCROLL_ID, viewport,
!isRoot, isRoot, containerParameters);
root->SetFrameMetrics(
nsDisplayScrollLayer::ComputeFrameMetrics(aForFrame, rootScrollFrame,
aBuilder->FindReferenceFrameFor(aForFrame),
root, FrameMetrics::NULL_SCROLL_ID, viewport,
!isRoot, isRoot, containerParameters));
// NS_WARNING is debug-only, so don't even bother checking the conditions in
// a release build.
@ -3668,28 +3671,35 @@ nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder* aBuilder,
params.mInLowPrecisionDisplayPort = true;
}
nsRefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer(
aBuilder, aManager, params);
return nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, params);
}
UniquePtr<FrameMetrics>
nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters)
{
if (!(mFlags & GENERATE_SCROLLABLE_LAYER)) {
return layer.forget();
return UniquePtr<FrameMetrics>(nullptr);
}
NS_ASSERTION(layer->AsContainerLayer(), "nsDisplayOwnLayer should have made a ContainerLayer");
if (ContainerLayer* container = layer->AsContainerLayer()) {
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
bool isRootContentDocument = presContext->IsRootContentDocument();
nsRect viewport = mFrame->GetRect() -
mFrame->GetPosition() +
mFrame->GetOffsetToCrossDoc(ReferenceFrame());
RecordFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(),
container, mScrollParentId, viewport,
false, isRootContentDocument, params);
nsPresContext* presContext = mFrame->PresContext();
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
bool isRootContentDocument = presContext->IsRootContentDocument();
ContainerLayerParameters params = aContainerParameters;
if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
rootScrollFrame->GetContent() &&
nsLayoutUtils::GetCriticalDisplayPort(rootScrollFrame->GetContent(), nullptr)) {
params.mInLowPrecisionDisplayPort = true;
}
return layer.forget();
nsRect viewport = mFrame->GetRect() -
mFrame->GetPosition() +
mFrame->GetOffsetToCrossDoc(ReferenceFrame());
return MakeUnique<FrameMetrics>(
nsDisplayScrollLayer::ComputeFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(),
aLayer, mScrollParentId, viewport,
false, isRootContentDocument, params));
}
nsRect
@ -3978,25 +3988,14 @@ nsDisplayScrollLayer::GetScrolledContentRectToDraw(nsDisplayListBuilder* aBuilde
already_AddRefed<Layer>
nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) {
const ContainerLayerParameters& aContainerParameters)
{
ContainerLayerParameters params = aContainerParameters;
if (mScrolledFrame->GetContent() &&
nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame->GetContent(), nullptr)) {
params.mInLowPrecisionDisplayPort = true;
}
nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
params, nullptr);
nsRect viewport = mScrollFrame->GetRect() -
mScrollFrame->GetPosition() +
mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
RecordFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), layer,
mScrollParentId, viewport, false, false, params);
if (mList.IsOpaque()) {
nsRect displayport;
bool usingDisplayport =
@ -4007,14 +4006,28 @@ nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
mDisplayPortContentsOpaque = false;
}
return layer.forget();
return aManager->GetLayerBuilder()->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
params, nullptr);
}
bool
nsDisplayScrollLayer::IsConstructingScrollLayerForScrolledFrame(const nsIFrame* aScrolledFrame)
UniquePtr<FrameMetrics>
nsDisplayScrollLayer::ComputeFrameMetrics(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters)
{
FrameProperties props = aScrolledFrame->Properties();
return reinterpret_cast<intptr_t>(props.Get(nsIFrame::ScrollLayerCount())) != 0;
ContainerLayerParameters params = aContainerParameters;
if (mScrolledFrame->GetContent() &&
nsLayoutUtils::GetCriticalDisplayPort(mScrolledFrame->GetContent(), nullptr)) {
params.mInLowPrecisionDisplayPort = true;
}
nsRect viewport = mScrollFrame->GetRect() -
mScrollFrame->GetPosition() +
mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
return UniquePtr<FrameMetrics>(new FrameMetrics(
ComputeFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), aLayer,
mScrollParentId, viewport, false, false, params)));
}
bool

View File

@ -24,6 +24,8 @@
#include "nsDisplayListInvalidation.h"
#include "DisplayListClipState.h"
#include "LayerState.h"
#include "FrameMetrics.h"
#include "mozilla/UniquePtr.h"
#include <stdint.h>
@ -43,8 +45,8 @@ namespace layers {
class Layer;
class ImageLayer;
class ImageContainer;
} //namepsace
} //namepsace
} //namespace
} //namespace
// A set of blend modes, that never includes OP_OVER (since it's
// considered the default, rather than a specific blend mode).
@ -806,6 +808,7 @@ class nsDisplayItem : public nsDisplayItemLink {
public:
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
typedef mozilla::DisplayItemClip DisplayItemClip;
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
@ -2885,6 +2888,10 @@ public:
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters);
protected:
ViewID mScrollParentId;
};
@ -3011,8 +3018,6 @@ public:
// after merging, all the nsDisplayScrollLayers should flatten away.
intptr_t GetScrollLayerCount();
static bool IsConstructingScrollLayerForScrolledFrame(const nsIFrame* aScrolledFrame);
virtual nsIFrame* GetScrollFrame() { return mScrollFrame; }
virtual nsIFrame* GetScrolledFrame() { return mScrolledFrame; }
@ -3022,6 +3027,19 @@ public:
bool IsDisplayPortOpaque() { return mDisplayPortContentsOpaque; }
static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
const nsIFrame* aReferenceFrame,
Layer* aLayer,
ViewID aScrollParentId,
const nsRect& aViewport,
bool aForceNullScrollId,
bool aIsRoot,
const ContainerLayerParameters& aContainerParameters);
mozilla::UniquePtr<FrameMetrics> ComputeFrameMetrics(Layer* aLayer,
const ContainerLayerParameters& aContainerParameters);
protected:
nsRect GetScrolledContentRectToDraw(nsDisplayListBuilder* aBuilder,
nsRect* aDisplayPort);

View File

@ -63,6 +63,22 @@ using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layout;
static bool
BuildScrollContainerLayers()
{
static bool sContainerlessScrollingEnabled;
static bool sContainerlessScrollingPrefCached = false;
if (!sContainerlessScrollingPrefCached) {
sContainerlessScrollingPrefCached = true;
Preferences::AddBoolVarCache(&sContainerlessScrollingEnabled,
"layout.async-containerless-scrolling.enabled",
true);
}
return !sContainerlessScrollingEnabled;
}
//----------------------------------------------------------------------
//----------nsHTMLScrollFrame-------------------------------------------
@ -2886,6 +2902,8 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
(!mIsRoot || aBuilder->RootReferenceFrame()->PresContext() != mOuter->PresContext());
}
mScrollParentID = aBuilder->GetCurrentScrollParentId();
nsDisplayListCollection scrolledContent;
{
// Note that setting the current scroll parent id here means that positioned children
@ -2954,7 +2972,7 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// scroll layer count. The display lists depend on this.
ScrollLayerWrapper wrapper(mOuter, mScrolledFrame);
if (mShouldBuildScrollableLayer) {
if (mShouldBuildScrollableLayer && BuildScrollContainerLayers()) {
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
// For root scrollframes in documents where the CSS viewport has been
@ -2996,6 +3014,31 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
scrolledContent.MoveTo(aLists);
}
void
ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
nsIFrame* aContainerReferenceFrame,
const ContainerLayerParameters& aParameters,
nsRect* aClipRect,
nsTArray<FrameMetrics>* aOutput) const
{
if (!mShouldBuildScrollableLayer || BuildScrollContainerLayers()) {
return;
}
MOZ_ASSERT(mScrolledFrame->GetContent());
nsRect viewport = mScrollPort +
mOuter->GetOffsetToCrossDoc(aContainerReferenceFrame);
if (!(mIsRoot && mOuter->PresContext()->PresShell()->GetIsViewportOverridden())) {
*aClipRect = viewport;
}
*aOutput->AppendElement() =
nsDisplayScrollLayer::ComputeFrameMetrics(mScrolledFrame, mOuter,
aContainerReferenceFrame, aLayer, mScrollParentID,
viewport, false, false, aParameters);
}
bool
ScrollFrameHelper::IsRectNearlyVisible(const nsRect& aRect) const
{

View File

@ -31,6 +31,9 @@ class nsIScrollPositionListener;
struct ScrollReflowState;
namespace mozilla {
namespace layers {
class Layer;
}
namespace layout {
class ScrollbarActivity;
}
@ -43,6 +46,8 @@ public:
typedef nsIFrame::Sides Sides;
typedef mozilla::CSSIntPoint CSSIntPoint;
typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::Layer Layer;
class AsyncScroll;
class AsyncSmoothMSDScroll;
@ -325,6 +330,10 @@ public:
}
}
bool WantAsyncScroll() const;
void ComputeFrameMetrics(Layer* aLayer, nsIFrame* aContainerReferenceFrame,
const ContainerLayerParameters& aParameters,
nsRect* aClipRect,
nsTArray<FrameMetrics>* aOutput) const;
// nsIScrollbarMediator
void ScrollByPage(nsScrollbarFrame* aScrollbar, int32_t aDirection);
@ -389,6 +398,8 @@ public:
// The scroll position where we last updated image visibility.
nsPoint mLastUpdateImagesPos;
FrameMetrics::ViewID mScrollParentID;
bool mNeverHasVerticalScrollbar:1;
bool mNeverHasHorizontalScrollbar:1;
bool mHasVerticalScrollbar:1;
@ -708,6 +719,13 @@ public:
virtual bool WantAsyncScroll() const MOZ_OVERRIDE {
return mHelper.WantAsyncScroll();
}
virtual void ComputeFrameMetrics(Layer* aLayer, nsIFrame* aContainerReferenceFrame,
const ContainerLayerParameters& aParameters,
nsRect* aClipRect,
nsTArray<FrameMetrics>* aOutput) const MOZ_OVERRIDE {
mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame,
aParameters, aClipRect, aOutput);
}
// nsIStatefulFrame
NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {
@ -1047,6 +1065,13 @@ public:
virtual bool WantAsyncScroll() const MOZ_OVERRIDE {
return mHelper.WantAsyncScroll();
}
virtual void ComputeFrameMetrics(Layer* aLayer, nsIFrame* aContainerReferenceFrame,
const ContainerLayerParameters& aParameters,
nsRect* aClipRect,
nsTArray<FrameMetrics>* aOutput) const MOZ_OVERRIDE {
mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame,
aParameters, aClipRect, aOutput);
}
// nsIStatefulFrame
NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {

View File

@ -15,6 +15,7 @@
#include "mozilla/gfx/Point.h"
#include "nsIScrollbarMediator.h"
#include "Units.h"
#include "FrameMetrics.h"
#define NS_DEFAULT_VERTICAL_SCROLL_DISTANCE 3
#define NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE 5
@ -27,6 +28,13 @@ class nsIContent;
class nsRenderingContext;
class nsIAtom;
namespace mozilla {
struct ContainerLayerParameters;
namespace layers {
class Layer;
}
}
/**
* Interface for frames that are scrollable. This interface exposes
* APIs for examining scroll state, observing changes to scroll state,
@ -35,6 +43,8 @@ class nsIAtom;
class nsIScrollableFrame : public nsIScrollbarMediator {
public:
typedef mozilla::CSSIntPoint CSSIntPoint;
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
typedef mozilla::layers::FrameMetrics FrameMetrics;
NS_DECL_QUERYFRAME_TARGET(nsIScrollableFrame)
@ -340,6 +350,15 @@ public:
* scroll frame.
*/
virtual bool WantAsyncScroll() const = 0;
/**
* aLayer's animated geometry root is this frame. If there needs to be a
* FrameMetrics contributed by this frame, append it to aOutput.
*/
virtual void ComputeFrameMetrics(mozilla::layers::Layer* aLayer,
nsIFrame* aContainerReferenceFrame,
const ContainerLayerParameters& aParameters,
nsRect* aOutClipRect,
nsTArray<FrameMetrics>* aOutput) const = 0;
};
#endif

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<body>
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black">
<div style="width:300px; height:800px; overflow:hidden; border:2px solid blue; margin-top:-50px">
<div style="height:450px"></div>
<div style="height:200px; background:purple"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE HTML>
<html reftest-async-scroll>
<body>
<!-- Test that nested active scrolling elements work -->
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="50">
<div style="width:300px; height:800px; overflow:hidden; border:2px solid blue"
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="50">
<div style="height:500px"></div>
<div style="height:200px; background:purple"></div>
</div>
</div>
</html>

View File

@ -1,10 +1,26 @@
skip-if(!asyncPanZoom) == bg-fixed-1.html bg-fixed-1-ref.html
skip-if(!asyncPanZoom) == bg-fixed-cover-1.html bg-fixed-cover-1-ref.html
skip-if(!asyncPanZoom) == bg-fixed-cover-2.html bg-fixed-cover-2-ref.html
skip-if(!asyncPanZoom) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
skip-if(!asyncPanZoom) == element-1.html element-1-ref.html
skip-if(!asyncPanZoom) == position-fixed-1.html position-fixed-1-ref.html
skip-if(!asyncPanZoom) == position-fixed-2.html position-fixed-2-ref.html
skip-if(!asyncPanZoom) == position-fixed-cover-1.html position-fixed-cover-1-ref.html
skip-if(!asyncPanZoom) == position-fixed-cover-2.html position-fixed-cover-2-ref.html
skip-if(!asyncPanZoom) == position-fixed-cover-3.html position-fixed-cover-3-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-1.html bg-fixed-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-cover-1.html bg-fixed-cover-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-cover-2.html bg-fixed-cover-2-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == element-1.html element-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == nested-1.html nested-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-1.html position-fixed-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-2.html position-fixed-2-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-cover-1.html position-fixed-cover-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-cover-2.html position-fixed-cover-2-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == position-fixed-cover-3.html position-fixed-cover-3-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == split-layers-1.html split-layers-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == split-layers-multi-scrolling-1.html split-layers-multi-scrolling-1-ref.html
pref(layout.async-containerless-scrolling.enabled,true) pref(apz.subframe.enabled,true) skip-if(!asyncPanZoom) == split-opacity-layers-1.html split-opacity-layers-1-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-1.html bg-fixed-1-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-cover-1.html bg-fixed-cover-1-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-cover-2.html bg-fixed-cover-2-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == element-1.html element-1-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-1.html position-fixed-1-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-2.html position-fixed-2-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-cover-1.html position-fixed-cover-1-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-cover-2.html position-fixed-cover-2-ref.html
pref(layout.async-containerless-scrolling.enabled,false) skip-if(!asyncPanZoom) == position-fixed-cover-3.html position-fixed-cover-3-ref.html

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<body>
<!-- Test that element content scrolls asynchronously even when content
has to be split into separate layers with non-scrolling content in
between -->
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black">
<div style="height:450px"></div>
<div style="height:100px; width:200px; float:left; background:purple"></div>
<div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
<div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
</div>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html reftest-async-scroll>
<body>
<!-- Test that element content scrolls asynchronously even when content
has to be split into separate layers with non-scrolling content in
between -->
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="50">
<div style="height:500px"></div>
<div style="height:100px; width:200px; float:left; background:purple"></div>
<div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
<div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html>
<body>
<!-- Test that element content scrolls asynchronously even when content
has to be split into separate layers with non-scrolling content in
between -->
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black; margin-top:-50px;">
<div style="height:450px"></div>
<div style="height:100px; width:200px; float:left; background:purple"></div>
<div style="left:200px; top:-50px; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
<div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
</div>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html reftest-async-scroll
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="50">
<body style="height:3000px; overflow:hidden">
<!-- Test that element content scrolls asynchronously even when content
has to be split into separate layers with non-scrolling content in
between -->
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="50">
<div style="height:500px"></div>
<div style="height:100px; width:200px; float:left; background:purple"></div>
<div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
<div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
</div>

View File

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<html>
<body>
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black">
<div style="height:450px"></div>
<div style="height:100px; width:200px; float:left; background:purple"></div>
<div style="opacity:0.5">
<div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
<div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
</div>
</div>

View File

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html reftest-async-scroll>
<body>
<div style="width:400px; height:500px; overflow:hidden; border:2px solid black"
reftest-displayport-x="0" reftest-displayport-y="0"
reftest-displayport-w="800" reftest-displayport-h="2000"
reftest-async-scroll-x="0" reftest-async-scroll-y="50">
<div style="height:500px"></div>
<div style="height:100px; width:200px; float:left; background:purple"></div>
<div style="opacity:0.5">
<div style="left:200px; top:0; height:800px; width:300px; float:left; background:yellow; position:absolute; z-index:1;"></div>
<div style="height:100px; width:200px; float:left; background:purple; position:relative; z-index:2;"></div>
</div>
</div>

View File

@ -426,6 +426,9 @@ pref("media.audio_data.enabled", false);
// Whether to use async panning and zooming
pref("layers.async-pan-zoom.enabled", false);
// Whether to enable containerless async scrolling
pref("layout.async-containerless-scrolling.enabled", true);
// APZ preferences. For documentation/details on what these prefs do, check
// gfx/layers/apz/src/AsyncPanZoomController.cpp.
pref("apz.allow_checkerboarding", true);