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:
Botond Ballo 2014-03-19 13:29:24 -04:00
parent 943c061dc6
commit 30a35592c2
6 changed files with 133 additions and 47 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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()) {

View File

@ -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);