Bug 1210578. Part 3. Create DecideScrollableLayer that encapsulates all logic to create display ports and build scrollable layers. r=mstange

For root scroll frames we need information about the async scrolling (or lack thereof) of the scroll frame before we get to ScrollFrameHelper::BuildDisplayList for the scroll frame. We need it in nsLayoutUtils::PaintFrame and nsSubdocumentFrame::BuildDisplayList. So we factor out all the code responsible for async scrolling decisions into one function we can call from all three places.
This commit is contained in:
Timothy Nikkel 2015-10-12 15:21:49 -05:00
parent efe42313c1
commit 365d409500
5 changed files with 111 additions and 70 deletions

View File

@ -3133,14 +3133,16 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
bool usingDisplayPort = false;
nsRect displayport;
if (rootScrollFrame && !aFrame->GetParent() &&
builder.IsPaintingToWindow() &&
gfxPrefs::LayoutUseContainersForRootFrames()) {
nsRect displayportBase(
nsPoint(0,0),
nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame));
usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
builder, rootScrollFrame, displayportBase, &displayport);
if (rootScrollFrame && !aFrame->GetParent()) {
nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
MOZ_ASSERT(rootScrollableFrame);
displayport = aFrame->GetVisualOverflowRectRelativeToSelf();
usingDisplayPort = rootScrollableFrame->DecideScrollableLayer(&builder,
&displayport, /* aAllowCreateDisplayPort = */ true);
if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
usingDisplayPort = false;
}
}
nsDisplayList hoistedScrollItemStorage;

View File

@ -61,6 +61,7 @@
#include "nsPluginFrame.h"
#include <mozilla/layers/AxisPhysicsModel.h>
#include <mozilla/layers/AxisPhysicsMSDModel.h>
#include "mozilla/unused.h"
#include <algorithm>
#include <cstdlib> // for std::abs(int/long)
#include <cmath> // for std::abs(float/double)
@ -2864,21 +2865,14 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
bool createLayersForScrollbars = mIsRoot &&
mOuter->PresContext()->IsRootContentDocument();
bool usingDisplayPort = aBuilder->IsPaintingToWindow() &&
nsLayoutUtils::GetDisplayPort(mOuter->GetContent());
if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
bool usingDisplayPort = aBuilder->IsPaintingToWindow() &&
nsLayoutUtils::GetDisplayPort(mOuter->GetContent());
// Root scrollframes have FrameMetrics and clipping on their container
// layers, so don't apply clipping again.
mAddClipRectToLayer = false;
if (usingDisplayPort) {
// There is a display port for this frame, so we want to appear as having
// active scrolling, so that animated geometry roots are assigned correctly.
mWillBuildScrollableLayer = true;
mIsScrollableLayerInRootContainer = true;
}
// If we are a root scroll frame that has a display port we want to add
// scrollbars, they will be children of the scrollable layer, but they get
// adjusted by the APZC automatically.
@ -2920,48 +2914,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// dirty rect here.
nsRect dirtyRect = aDirtyRect.Intersect(mScrollPort);
nsRect displayPort;
if (aBuilder->IsPaintingToWindow()) {
bool wasUsingDisplayPort = usingDisplayPort;
unused << DecideScrollableLayer(aBuilder, &dirtyRect,
/* aAllowCreateDisplayPort = */ !mIsRoot);
if (mIsRoot && gfxPrefs::LayoutUseContainersForRootFrames()) {
// For a root frame in a container, just get the value of the existing
// display port if any.
usingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort);
} else {
// Override the value of the display port base rect, and possibly create a
// display port if there isn't one already.
nsRect displayportBase = dirtyRect;
if (mIsRoot && mOuter->PresContext()->IsRootContentDocument()) {
displayportBase =
nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
}
usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
*aBuilder, mOuter, displayportBase, &displayPort);
}
bool usingDisplayPort = aBuilder->IsPaintingToWindow() &&
nsLayoutUtils::GetDisplayPort(mOuter->GetContent());
// Override the dirty rectangle if the displayport has been set.
if (usingDisplayPort) {
dirtyRect = displayPort;
// The cached animated geometry root for the display builder is out of
// date if we just introduced a new animated geometry root.
if (!wasUsingDisplayPort) {
aBuilder->RecomputeCurrentAnimatedGeometryRoot();
}
}
}
// Since making new layers is expensive, only use nsDisplayScrollLayer
// if the area is scrollable and we're the content process (unless we're on
// B2G, where we support async scrolling for scrollable elements in the
// parent process as well).
// When a displayport is being used, force building of a layer so that
// CompositorParent can always find the scrollable layer for the root content
// document.
// If the element is marked 'scrollgrab', also force building of a layer
// so that APZ can implement scroll grabbing.
mWillBuildScrollableLayer = usingDisplayPort || nsContentUtils::HasScrollgrab(mOuter->GetContent());
// Whether we might want to build a scrollable layer for this scroll frame
// at some point in the future. This controls whether we add the information
// to the layer tree (a scroll info layer if necessary, and add the right
@ -3171,6 +3129,64 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
scrolledContent.MoveTo(aLists);
}
bool
ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aDirtyRect,
bool aAllowCreateDisplayPort)
{
bool usingDisplayPort = false;
nsIContent* content = mOuter->GetContent();
if (aBuilder->IsPaintingToWindow()) {
bool wasUsingDisplayPort = nsLayoutUtils::GetDisplayPort(content);
nsRect displayportBase = *aDirtyRect;
nsPresContext* pc = mOuter->PresContext();
if (mIsRoot && (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {
displayportBase =
nsRect(nsPoint(0, 0), nsLayoutUtils::CalculateCompositionSizeForFrame(mOuter));
}
nsRect displayPort;
if (aAllowCreateDisplayPort) {
// Provide the value of the display port base rect, and possibly create a
// display port if there isn't one already.
usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
*aBuilder, mOuter, displayportBase, &displayPort);
} else {
// We should have already been called with aAllowCreateDisplayPort == true
// which should have set a displayport base.
MOZ_ASSERT(content->GetProperty(nsGkAtoms::DisplayPortBase));
usingDisplayPort = nsLayoutUtils::GetDisplayPort(content, &displayPort);
}
// Override the dirty rectangle if the displayport has been set.
if (usingDisplayPort) {
*aDirtyRect = displayPort;
// The cached animated geometry root for the display builder is out of
// date if we just introduced a new animated geometry root.
if (!wasUsingDisplayPort) {
aBuilder->RecomputeCurrentAnimatedGeometryRoot();
}
}
}
// Since making new layers is expensive, only create a scrollable layer
// for some scroll frames.
// When a displayport is being used, force building of a layer so that
// the compositor can find the scrollable layer for async scrolling.
// If the element is marked 'scrollgrab', also force building of a layer
// so that APZ can implement scroll grabbing.
mWillBuildScrollableLayer = usingDisplayPort || nsContentUtils::HasScrollgrab(content);
if (gfxPrefs::LayoutUseContainersForRootFrames() && mWillBuildScrollableLayer && mIsRoot) {
mIsScrollableLayerInRootContainer = true;
}
return mWillBuildScrollableLayer;
}
Maybe<DisplayItemClip>
ScrollFrameHelper::ComputeScrollClip(bool aIsForCaret) const
{

View File

@ -366,6 +366,10 @@ public:
bool UsesContainerScrolling() const;
bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aDirtyRect,
bool aAllowCreateDisplayPort);
void ScheduleSyntheticMouseMove();
static void ScrollActivityCallback(nsITimer *aTimer, void* anInstance);
@ -873,6 +877,11 @@ public:
virtual bool UsesContainerScrolling() const override {
return mHelper.UsesContainerScrolling();
}
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aDirtyRect,
bool aAllowCreateDisplayPort) override {
return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
}
// nsIStatefulFrame
NS_IMETHOD SaveState(nsPresState** aState) override {
@ -1351,6 +1360,12 @@ public:
void SetZoomableByAPZ(bool aZoomable) override {
mHelper.SetZoomableByAPZ(aZoomable);
}
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aDirtyRect,
bool aAllowCreateDisplayPort) override {
return mHelper.DecideScrollableLayer(aBuilder, aDirtyRect, aAllowCreateDisplayPort);
}
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override;

View File

@ -455,6 +455,19 @@ public:
virtual bool UsesContainerScrolling() const = 0;
virtual mozilla::Maybe<mozilla::DisplayItemClip> ComputeScrollClip(bool aIsForCaret) const = 0;
/**
* Determine if we should build a scrollable layer for this scroll frame and
* return the result. It will also record this result on the scroll frame.
* Pass the dirty rect in aDirtyRect. On return it will be set to the
* displayport if there is one (ie the dirty rect that should be used).
* This function may create a display port where one did not exist before if
* aAllowCreateDisplayPort is true. It is only allowed to be false if there
* has been a call with it set to true before on the same paint.
*/
virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
nsRect* aDirtyRect,
bool aAllowCreateDisplayPort) = 0;
};
#endif

View File

@ -416,18 +416,13 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
if (gfxPrefs::LayoutUseContainersForRootFrames()) {
// for root content documents we want the base to be the composition bounds
nsRect displayportBase = presContext->IsRootContentDocument() ?
nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) :
dirty.Intersect(nsRect(nsPoint(0,0), subdocRootFrame->GetSize()));
nsRect displayPort;
if (aBuilder->IsPaintingToWindow() &&
nsLayoutUtils::GetOrMaybeCreateDisplayPort(
*aBuilder, rootScrollFrame, displayportBase, &displayPort)) {
haveDisplayPort = true;
dirty = displayPort;
}
nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
MOZ_ASSERT(rootScrollableFrame);
haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
&dirty, /* aAllowCreateDisplayPort = */ true);
if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
haveDisplayPort = false;
}
ignoreViewportScrolling = presShell->IgnoringViewportScrolling();