Bug 1364295. Walk the frame tree looking for a scrollframe to add a displayport to, or one that already has a displayport before displaylist building. r=mstange

And stop creating displayports during display list building.

One thing we can investigate in the future is whether we should use the value of mHaveScrollableDisplayPort stored on the display list builder retained between paints. If it's true then we could potentially skip this pass. It would mean that if there are large changes to the page we wouldn't set a displayport. And we'd need to make sure the value is cleared when we load a new page.
This commit is contained in:
Timothy Nikkel 2017-05-19 17:04:19 -05:00
Родитель 718b6fff3e
Коммит 1402ea7c2d
4 изменённых файлов: 64 добавлений и 9 удалений

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

@ -39,6 +39,7 @@
#include "nsViewManager.h"
#include "nsPlaceholderFrame.h"
#include "nsIScrollableFrame.h"
#include "nsSubDocumentFrame.h"
#include "nsIDOMEvent.h"
#include "nsDisplayList.h"
#include "nsRegion.h"
@ -3425,13 +3426,15 @@ nsLayoutUtils::CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFram
content, presShell, displayportMargins, 0, aRepaintMode);
}
void
bool
nsLayoutUtils::MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
nsIFrame* aScrollFrame) {
nsIFrame* aScrollFrame,
RepaintMode aRepaintMode)
{
nsIContent* content = aScrollFrame->GetContent();
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
if (!content || !scrollableFrame) {
return;
return false;
}
bool haveDisplayPort = HasDisplayPort(content);
@ -3447,7 +3450,7 @@ nsLayoutUtils::MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
// If we don't already have a displayport, calculate and set one.
if (!haveDisplayPort) {
CalculateAndSetDisplayPortMargins(scrollableFrame, nsLayoutUtils::RepaintMode::DoNotRepaint);
CalculateAndSetDisplayPortMargins(scrollableFrame, aRepaintMode);
#ifdef DEBUG
haveDisplayPort = HasDisplayPort(content);
MOZ_ASSERT(haveDisplayPort, "should have a displayport after having just set it");
@ -3456,7 +3459,9 @@ nsLayoutUtils::MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
// Record that the we now have a scrollable display port.
aBuilder.SetHaveScrollableDisplayPort();
return true;
}
return false;
}
nsIScrollableFrame*
@ -3495,6 +3500,43 @@ nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(nsIFrame* aFra
}
}
bool
nsLayoutUtils::MaybeCreateDisplayPortInFirstScrollFrameEncountered(
nsIFrame* aFrame, nsDisplayListBuilder& aBuilder)
{
nsIScrollableFrame* sf = do_QueryFrame(aFrame);
if (sf) {
if (MaybeCreateDisplayPort(aBuilder, aFrame, RepaintMode::Repaint)) {
return true;
}
}
if (aFrame->IsPlaceholderFrame()) {
nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(
placeholder->GetOutOfFlowFrame(), aBuilder)) {
return true;
}
}
if (aFrame->IsSubDocumentFrame()) {
nsIPresShell* presShell =
static_cast<nsSubDocumentFrame*>(aFrame)->GetSubdocumentPresShellForPainting(0);
nsIFrame* root = presShell ? presShell->GetRootFrame() : nullptr;
if (root) {
if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(root, aBuilder)) {
return true;
}
}
}
for (nsIFrame* child : aFrame->PrincipalChildList()) {
if (MaybeCreateDisplayPortInFirstScrollFrameEncountered(child, aBuilder)) {
return true;
}
}
return false;
}
void
nsLayoutUtils::ExpireDisplayPortOnAsyncScrollableAncestor(nsIFrame* aFrame)
{
@ -3685,6 +3727,11 @@ nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
}
}
builder.ClearHaveScrollableDisplayPort();
if (builder.IsPaintingToWindow()) {
MaybeCreateDisplayPortInFirstScrollFrameEncountered(aFrame, builder);
}
nsRect dirtyRect = visibleRegion.GetBounds();
{

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

@ -1066,6 +1066,10 @@ public:
const nscoord aRadii[8],
const nsRect& aTestRect);
static bool MaybeCreateDisplayPortInFirstScrollFrameEncountered(
nsIFrame* aFrame, nsDisplayListBuilder& aBuilder);
enum class PaintFrameFlags : uint32_t {
PAINT_IN_TRANSFORM = 0x01,
PAINT_SYNC_DECODE_IMAGES = 0x02,
@ -2814,10 +2818,15 @@ public:
* displayport yet (as tracked by |aBuilder|), calculate and set a
* displayport.
*
* This is intended to be called during display list building.
* If this is called during display list building pass DoNotRepaint in
* aRepaintMode.
*
* Returns true if there is a displayport on an async scrollable scrollframe
* after this call, either because one was just added or it already existed.
*/
static void MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
nsIFrame* aScrollFrame);
static bool MaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
nsIFrame* aScrollFrame,
RepaintMode aRepaintMode);
static nsIScrollableFrame* GetAsyncScrollableAncestorFrame(nsIFrame* aTarget);

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

@ -3621,8 +3621,6 @@ ScrollFrameHelper::DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
wasUsingDisplayPort = nsLayoutUtils::HasDisplayPort(content);
if (aAllowCreateDisplayPort) {
nsLayoutUtils::MaybeCreateDisplayPort(*aBuilder, mOuter);
nsRect displayportBase = *aDirtyRect;
nsPresContext* pc = mOuter->PresContext();
if (mIsRoot && (pc->IsRootContentDocument() || !pc->GetParentPresContext())) {

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

@ -586,6 +586,7 @@ public:
bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; }
void SetHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = true; }
void ClearHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = false; }
bool SetIsCompositingCheap(bool aCompositingCheap) {
bool temp = mIsCompositingCheap;