mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Bug 982141 - Make sure the primary async-scrollable frame has a displayport set. r=tn
--HG-- extra : rebase_source : 6ceb20abb14f3e829ea06c3b3b911455cff9db23
This commit is contained in:
parent
567dc92376
commit
ce19e926e0
@ -522,7 +522,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
mIsCompositingCheap(false),
|
||||
mContainsPluginItem(false),
|
||||
mContainsBlendMode(false),
|
||||
mAncestorHasTouchEventHandler(false)
|
||||
mAncestorHasTouchEventHandler(false),
|
||||
mHaveScrollableDisplayPort(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayListBuilder);
|
||||
PL_InitArenaPool(&mPool, "displayListArena", 1024,
|
||||
|
@ -317,6 +317,9 @@ public:
|
||||
mAncestorHasTouchEventHandler = aValue;
|
||||
}
|
||||
|
||||
bool HaveScrollableDisplayPort() const { return mHaveScrollableDisplayPort; }
|
||||
void SetHaveScrollableDisplayPort() { mHaveScrollableDisplayPort = true; }
|
||||
|
||||
bool SetIsCompositingCheap(bool aCompositingCheap) {
|
||||
bool temp = mIsCompositingCheap;
|
||||
mIsCompositingCheap = aCompositingCheap;
|
||||
@ -723,6 +726,10 @@ private:
|
||||
bool mContainsPluginItem;
|
||||
bool mContainsBlendMode;
|
||||
bool mAncestorHasTouchEventHandler;
|
||||
// True when the first async-scrollable scroll frame for which we build a
|
||||
// display list has a display port. An async-scrollable scroll frame is one
|
||||
// which WantsAsyncScroll().
|
||||
bool mHaveScrollableDisplayPort;
|
||||
};
|
||||
|
||||
class nsDisplayItem;
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include "gfx2DGlue.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "UnitTransforms.h"
|
||||
#include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
@ -88,6 +89,11 @@
|
||||
#include "nsTransitionManager.h"
|
||||
#include "RestyleManager.h"
|
||||
|
||||
// Additional includes used on B2G by code in GetOrMaybeCreateDisplayPort().
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "mozilla/layers/AsyncPanZoomController.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::css;
|
||||
using namespace mozilla::dom;
|
||||
@ -2490,6 +2496,59 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
||||
nsIFrame* aScrollFrame,
|
||||
nsRect aDisplayPortBase,
|
||||
nsRect* aOutDisplayport) {
|
||||
nsIContent* content = aScrollFrame->GetContent();
|
||||
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollFrame);
|
||||
if (!content || !scrollableFrame) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the base rect. Note that this will not influence 'haveDisplayPort',
|
||||
// which is based on either the whole rect or margins being set, but it
|
||||
// will affect what is returned in 'aOutDisplayPort' if margins are set.
|
||||
SetDisplayPortBase(content, aDisplayPortBase);
|
||||
|
||||
bool haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// On B2G, we perform an optimization where we ensure that at least one
|
||||
// async-scrollable frame (i.e. one that WantsAsyncScroll()) has a displayport.
|
||||
// If that's not the case yet, and we are async-scrollable, we will get a
|
||||
// displayport.
|
||||
// Note: we only do this in processes where we do subframe scrolling to
|
||||
// begin with (i.e., not in the parent process on B2G).
|
||||
if (WantSubAPZC() &&
|
||||
!aBuilder.HaveScrollableDisplayPort() &&
|
||||
scrollableFrame->WantAsyncScroll()) {
|
||||
|
||||
// If we don't already have a displayport, calculate and set one.
|
||||
if (!haveDisplayPort) {
|
||||
FrameMetrics metrics = CalculateFrameMetricsForDisplayPort(aScrollFrame, scrollableFrame);
|
||||
LayerMargin displayportMargins = AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
metrics, ScreenPoint(0.0f, 0.0f), 0.0);
|
||||
nsIPresShell* presShell = aScrollFrame->PresContext()->GetPresShell();
|
||||
gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled()
|
||||
? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) :
|
||||
gfx::IntSize(1, 1);
|
||||
nsLayoutUtils::SetDisplayPortMargins(
|
||||
content, presShell, displayportMargins, alignment.width,
|
||||
alignment.height, 0, nsLayoutUtils::RepaintMode::DoNotRepaint);
|
||||
haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
|
||||
NS_ASSERTION(haveDisplayPort, "should have a displayport after having just set it");
|
||||
}
|
||||
|
||||
// Record that the we now have a scrollable display port.
|
||||
aBuilder.SetHaveScrollableDisplayPort();
|
||||
}
|
||||
#endif
|
||||
|
||||
return haveDisplayPort;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
|
||||
const nsRegion& aDirtyRegion, nscolor aBackstop,
|
||||
@ -2511,19 +2570,18 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::PAINTING,
|
||||
!(aFlags & PAINT_HIDE_CARET));
|
||||
|
||||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
bool usingDisplayPort = false;
|
||||
nsRect displayport;
|
||||
if (rootScrollFrame && !aFrame->GetParent()) {
|
||||
nsIContent* content = rootScrollFrame->GetContent();
|
||||
if (content) {
|
||||
usingDisplayPort = nsLayoutUtils::GetDisplayPort(content);
|
||||
if (usingDisplayPort) {
|
||||
nsLayoutUtils::SetDisplayPortBase(content,
|
||||
nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)));
|
||||
nsLayoutUtils::GetDisplayPort(content, &displayport);
|
||||
}
|
||||
}
|
||||
nsRect displayportBase(
|
||||
nsPoint(0,0),
|
||||
nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame));
|
||||
usingDisplayPort = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
|
||||
builder, rootScrollFrame, displayportBase, &displayport);
|
||||
}
|
||||
|
||||
nsRegion visibleRegion;
|
||||
@ -2548,9 +2606,6 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
||||
// *and after* we draw.
|
||||
bool willFlushRetainedLayers = (aFlags & PAINT_HIDE_CARET) != 0;
|
||||
|
||||
nsDisplayListBuilder builder(aFrame, nsDisplayListBuilder::PAINTING,
|
||||
!(aFlags & PAINT_HIDE_CARET));
|
||||
|
||||
nsDisplayList list;
|
||||
if (aFlags & PAINT_IN_TRANSFORM) {
|
||||
builder.SetInTransform(true);
|
||||
|
@ -2167,6 +2167,26 @@ public:
|
||||
*/
|
||||
static bool WantSubAPZC();
|
||||
|
||||
/**
|
||||
* Get the display port for |aScrollFrame|'s content. If |aScrollFrame|
|
||||
* WantsAsyncScroll() and we don't have a scrollable displayport yet (as
|
||||
* tracked by |aBuilder|), calculate and set a display port. Returns true if
|
||||
* there is (now) a displayport, and if so the displayport is returned in
|
||||
* |aOutDisplayport|.
|
||||
*
|
||||
* Note that a displayport can either be stored as a rect, or as a base
|
||||
* rect + margins. If it is stored as a base rect + margins, the base rect
|
||||
* is updated to |aDisplayPortBase|, and the rect assembled from the
|
||||
* base rect and margins is returned. If this function creates a displayport,
|
||||
* it computes margins and stores |aDisplayPortBase| as the base rect.
|
||||
*
|
||||
* This is intended to be called during display list building.
|
||||
*/
|
||||
static bool GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
||||
nsIFrame* aScrollFrame,
|
||||
nsRect aDisplayPortBase,
|
||||
nsRect* aOutDisplayport);
|
||||
|
||||
private:
|
||||
static uint32_t sFontSizeInflationEmPerLine;
|
||||
static uint32_t sFontSizeInflationMinTwips;
|
||||
|
@ -2488,27 +2488,31 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
// dirty rect here.
|
||||
nsRect dirtyRect = aDirtyRect.Intersect(mScrollPort);
|
||||
|
||||
// Override the dirty rectangle if the displayport has been set.
|
||||
bool usingDisplayport =
|
||||
nsLayoutUtils::GetDisplayPort(mOuter->GetContent()) &&
|
||||
!aBuilder->IsForEventDelivery();
|
||||
|
||||
// don't set the display port base rect for root scroll frames,
|
||||
// nsLayoutUtils::PaintFrame or nsSubDocumentFrame::BuildDisplayList
|
||||
// does that for root scroll frames before it expands the dirty rect
|
||||
// to the display port.
|
||||
if (usingDisplayport && !mIsRoot) {
|
||||
nsLayoutUtils::SetDisplayPortBase(mOuter->GetContent(), dirtyRect);
|
||||
}
|
||||
|
||||
// now that we have an updated base rect we can get the display port
|
||||
nsRect displayPort;
|
||||
nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort);
|
||||
if (usingDisplayport && DisplayportExceedsMaxTextureSize(mOuter->PresContext(), displayPort)) {
|
||||
usingDisplayport = false;
|
||||
}
|
||||
if (usingDisplayport) {
|
||||
dirtyRect = displayPort;
|
||||
bool usingDisplayport = false;
|
||||
if (!aBuilder->IsForEventDelivery()) {
|
||||
if (!mIsRoot) {
|
||||
// For a non-root scroll frame, override the value of the display port
|
||||
// base rect, and possibly create a display port if there isn't one
|
||||
// already. For root scroll frame, nsLayoutUtils::PaintFrame or
|
||||
// nsSubDocumentFrame::BuildDisplayList takes care of this.
|
||||
nsRect displayportBase = dirtyRect;
|
||||
usingDisplayport = nsLayoutUtils::GetOrMaybeCreateDisplayPort(
|
||||
*aBuilder, mOuter, displayportBase, &displayPort);
|
||||
} else {
|
||||
// For a root frmae, just get the value of the existing of the display
|
||||
// port, if any.
|
||||
usingDisplayport = nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort);
|
||||
}
|
||||
|
||||
if (usingDisplayport && DisplayportExceedsMaxTextureSize(mOuter->PresContext(), displayPort)) {
|
||||
usingDisplayport = false;
|
||||
}
|
||||
|
||||
// Override the dirty rectangle if the displayport has been set.
|
||||
if (usingDisplayport) {
|
||||
dirtyRect = displayPort;
|
||||
}
|
||||
}
|
||||
|
||||
if (aBuilder->IsForImageVisibility()) {
|
||||
|
@ -381,24 +381,23 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
// and convert into the appunits of the subdoc
|
||||
dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
|
||||
|
||||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
if (nsLayoutUtils::ViewportHasDisplayPort(presContext)) {
|
||||
haveDisplayPort = true;
|
||||
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
|
||||
// for root content documents we want the base to be the composition bounds
|
||||
nsLayoutUtils::SetDisplayPortBase(rootScrollFrame->GetContent(),
|
||||
presContext->IsRootContentDocument() ?
|
||||
nsRect displayportBase = presContext->IsRootContentDocument() ?
|
||||
nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) :
|
||||
dirty);
|
||||
dirty;
|
||||
nsRect displayPort;
|
||||
nsLayoutUtils::ViewportHasDisplayPort(presContext, &displayPort);
|
||||
dirty = displayPort;
|
||||
}
|
||||
if (nsLayoutUtils::GetOrMaybeCreateDisplayPort(
|
||||
*aBuilder, rootScrollFrame, displayportBase, &displayPort)) {
|
||||
haveDisplayPort = true;
|
||||
dirty = displayPort;
|
||||
}
|
||||
|
||||
ignoreViewportScrolling =
|
||||
rootScrollFrame && presShell->IgnoringViewportScrolling();
|
||||
if (ignoreViewportScrolling) {
|
||||
savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
|
||||
aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
|
||||
ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
|
||||
if (ignoreViewportScrolling) {
|
||||
savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
|
||||
aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
|
||||
}
|
||||
}
|
||||
|
||||
aBuilder->EnterPresShell(subdocRootFrame, dirty);
|
||||
|
Loading…
Reference in New Issue
Block a user