--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -650,21 +650,22 @@ TabChild::HandlePossibleViewportChange()
if (!pageSize.width) {
// Return early rather than divide by 0.
return;
}
metrics.mScrollableRect = CSSRect(CSSPoint(), pageSize);
// Calculate a display port _after_ having a scrollable rect because the
// display port is clamped to the scrollable rect.
- metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
+ metrics.SetDisplayPortMargins(AsyncPanZoomController::CalculatePendingDisplayPort(
// The page must have been refreshed in some way such as a new document or
// new CSS viewport, so we know that there's no velocity, acceleration, and
// we have no idea how long painting will take.
- metrics, ScreenPoint(0.0f, 0.0f), 0.0);
+ metrics, ScreenPoint(0.0f, 0.0f), 0.0));
+ metrics.SetUseDisplayPortMargins();
// Force a repaint with these metrics. This, among other things, sets the
// displayport, so we start with async painting.
mLastRootMetrics = ProcessUpdateFrame(metrics);
if (viewportInfo.IsZoomAllowed() && scrollIdentifiersValid) {
// If the CSS viewport is narrower than the screen (i.e. width <= device-width)
// then we disable double-tap-to-zoom behaviour.
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -603,16 +603,18 @@ struct ParamTraits<mozilla::layers::Fram
typedef mozilla::layers::FrameMetrics paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mScrollableRect);
WriteParam(aMsg, aParam.mViewport);
WriteParam(aMsg, aParam.mScrollOffset);
WriteParam(aMsg, aParam.mDisplayPort);
+ WriteParam(aMsg, aParam.mDisplayPortMargins);
+ WriteParam(aMsg, aParam.mUseDisplayPortMargins);
WriteParam(aMsg, aParam.mCriticalDisplayPort);
WriteParam(aMsg, aParam.mCompositionBounds);
WriteParam(aMsg, aParam.mRootCompositionSize);
WriteParam(aMsg, aParam.mScrollId);
WriteParam(aMsg, aParam.mResolution);
WriteParam(aMsg, aParam.mCumulativeResolution);
WriteParam(aMsg, aParam.mZoom);
WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
@@ -627,16 +629,18 @@ struct ParamTraits<mozilla::layers::Fram
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
ReadParam(aMsg, aIter, &aResult->mViewport) &&
ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
+ ReadParam(aMsg, aIter, &aResult->mDisplayPortMargins) &&
+ ReadParam(aMsg, aIter, &aResult->mUseDisplayPortMargins) &&
ReadParam(aMsg, aIter, &aResult->mCriticalDisplayPort) &&
ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
ReadParam(aMsg, aIter, &aResult->mRootCompositionSize) &&
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
ReadParam(aMsg, aIter, &aResult->mResolution) &&
ReadParam(aMsg, aIter, &aResult->mCumulativeResolution) &&
ReadParam(aMsg, aIter, &aResult->mZoom) &&
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -81,27 +81,31 @@ public:
, mMayHaveTouchListeners(false)
, mIsRoot(false)
, mHasScrollgrab(false)
, mScrollOffset(0, 0)
, mZoom(1)
, mUpdateScrollOffset(false)
, mScrollGeneration(0)
, mRootCompositionSize(0, 0)
+ , mDisplayPortMargins(0, 0, 0, 0)
+ , mUseDisplayPortMargins(false)
{}
// Default copy ctor and operator= are fine
bool operator==(const FrameMetrics& aOther) const
{
// mContentDescription is not compared on purpose as it's only used
// for debugging.
return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
mRootCompositionSize == aOther.mRootCompositionSize &&
mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
+ mDisplayPortMargins == aOther.mDisplayPortMargins &&
+ mUseDisplayPortMargins == aOther.mUseDisplayPortMargins &&
mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) &&
mViewport.IsEqualEdges(aOther.mViewport) &&
mScrollId == aOther.mScrollId &&
mScrollableRect.IsEqualEdges(aOther.mScrollableRect) &&
mResolution == aOther.mResolution &&
mCumulativeResolution == aOther.mCumulativeResolution &&
mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
@@ -377,16 +381,36 @@ public:
mRootCompositionSize = aRootCompositionSize;
}
const CSSSize& GetRootCompositionSize() const
{
return mRootCompositionSize;
}
+ void SetDisplayPortMargins(const LayerMargin& aDisplayPortMargins)
+ {
+ mDisplayPortMargins = aDisplayPortMargins;
+ }
+
+ const LayerMargin& GetDisplayPortMargins() const
+ {
+ return mDisplayPortMargins;
+ }
+
+ void SetUseDisplayPortMargins()
+ {
+ mUseDisplayPortMargins = true;
+ }
+
+ bool GetUseDisplayPortMargins() const
+ {
+ return mUseDisplayPortMargins;
+ }
+
private:
// New fields from now on should be made private and old fields should
// be refactored to be private.
// The position of the top-left of the CSS viewport, relative to the document
// (or the document relative to the viewport, if that helps understand it).
//
// Thus it is relative to the document. It is in the same coordinate space as
@@ -416,16 +440,24 @@ private:
uint32_t mScrollGeneration;
// A description of the content element corresponding to this frame.
// This is empty unless the apz.printtree pref is turned on.
std::string mContentDescription;
// The size of the root scrollable's composition bounds, but in local CSS pixels.
CSSSize mRootCompositionSize;
+
+ // A display port expressed as layer margins that apply to the rect of what
+ // is drawn of the scrollable element.
+ LayerMargin mDisplayPortMargins;
+
+ // If this is true then we use the display port margins on this metrics,
+ // otherwise use the display port rect.
+ bool mUseDisplayPortMargins;
};
/**
* This class allows us to uniquely identify a scrollable layer. The
* mLayersId identifies the layer tree (corresponding to a child process
* and/or tab) that the scrollable layer belongs to. The mPresShellId
* is a temporal identifier (corresponding to the document loaded that
* contains the scrollable layer, which may change over time). The
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -61,23 +61,25 @@
#include "SharedMemoryBasic.h" // for SharedMemoryBasic
// #define APZC_ENABLE_RENDERTRACE
#define APZC_LOG(...)
// #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
#define APZC_LOG_FM(fm, prefix, ...) \
APZC_LOG(prefix ":" \
- " i=(%ld %lld) cb=(%d %d %d %d) rcs=(%.3f %.3f) dp=(%.3f %.3f %.3f %.3f) v=(%.3f %.3f %.3f %.3f) " \
- "s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %llu)\n", \
+ " i=(%ld %lld) cb=(%d %d %d %d) rcs=(%.3f %.3f) dp=(%.3f %.3f %.3f %.3f) dpm=(%.3f %.3f %.3f %.3f) um=%d " \
+ "v=(%.3f %.3f %.3f %.3f) s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %llu)\n", \
__VA_ARGS__, \
fm.mPresShellId, fm.mScrollId, \
fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \
fm.GetRootCompositionSize().width, fm.GetRootCompositionSize().height, \
fm.mDisplayPort.x, fm.mDisplayPort.y, fm.mDisplayPort.width, fm.mDisplayPort.height, \
+ fm.mDisplayPortMargins.top, fm.mDisplayPortMargins.right, fm.mDisplayPortMargins.bottom, fm.mDisplayPortMargins.left, \
+ fm.mUseDisplayPortMargins ? 1 : 0, \
fm.mViewport.x, fm.mViewport.y, fm.mViewport.width, fm.mViewport.height, \
fm.mScrollOffset.x, fm.mScrollOffset.y, \
fm.mScrollableRect.x, fm.mScrollableRect.y, fm.mScrollableRect.width, fm.mScrollableRect.height, \
fm.mDevPixelsPerCSSPixel.scale, fm.mResolution.scale, fm.mCumulativeResolution.scale, fm.mZoom.scale, \
fm.GetScrollOffsetUpdated(), fm.GetScrollGeneration()); \
// Static helper functions
namespace {
@@ -1403,17 +1405,17 @@ RedistributeDisplayPortExcess(CSSSize& a
// Reassign wasted x-axis displayport to the y-axis
aDisplayPortSize.width -= xSlack;
float yExtra = xSlack * aDisplayPortSize.height / aDisplayPortSize.width;
aDisplayPortSize.height += yExtra;
}
}
/* static */
-const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
+const LayerMargin AsyncPanZoomController::CalculatePendingDisplayPort(
const FrameMetrics& aFrameMetrics,
const ScreenPoint& aVelocity,
double aEstimatedPaintDuration)
{
CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels());
CSSSize compositionSize = aFrameMetrics.GetRootCompositionSize();
compositionSize =
CSSSize(std::min(compositionBounds.width, compositionSize.width),
@@ -1443,17 +1445,25 @@ const CSSRect AsyncPanZoomController::Ca
// Make sure the displayport remains within the scrollable rect.
displayPort = displayPort.ForceInside(scrollableRect) - scrollOffset;
APZC_LOG_FM(aFrameMetrics,
"Calculated displayport as (%f %f %f %f) from velocity (%f %f) paint time %f metrics",
displayPort.x, displayPort.y, displayPort.width, displayPort.height,
aVelocity.x, aVelocity.y, (float)estimatedPaintDurationMillis);
- return displayPort;
+ CSSMargin cssMargins;
+ cssMargins.left = -displayPort.x;
+ cssMargins.top = -displayPort.y;
+ cssMargins.right = displayPort.width - compositionSize.width - cssMargins.left;
+ cssMargins.bottom = displayPort.height - compositionSize.height - cssMargins.top;
+
+ LayerMargin layerMargins = cssMargins * aFrameMetrics.LayersPixelsPerCSSPixel();
+
+ return layerMargins;
}
void AsyncPanZoomController::ScheduleComposite() {
if (mCompositorParent) {
mCompositorParent->ScheduleRenderOnCompositorThread();
}
}
@@ -1463,20 +1473,21 @@ void AsyncPanZoomController::FlushRepain
UpdateSharedCompositorFrameMetrics();
}
void AsyncPanZoomController::RequestContentRepaint() {
RequestContentRepaint(mFrameMetrics);
}
void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) {
- aFrameMetrics.mDisplayPort =
+ aFrameMetrics.SetDisplayPortMargins(
CalculatePendingDisplayPort(aFrameMetrics,
GetVelocityVector(),
- mPaintThrottler.AverageDuration().ToSeconds());
+ mPaintThrottler.AverageDuration().ToSeconds()));
+ aFrameMetrics.SetUseDisplayPortMargins();
// If we're trying to paint what we already think is painted, discard this
// request since it's a pointless paint.
CSSRect oldDisplayPort = mLastPaintRequestMetrics.mDisplayPort
+ mLastPaintRequestMetrics.GetScrollOffset();
CSSRect newDisplayPort = aFrameMetrics.mDisplayPort
+ aFrameMetrics.GetScrollOffset();
@@ -1868,20 +1879,21 @@ void AsyncPanZoomController::ZoomToRect(
aRect.y = aRect.y > 0 ? aRect.y : 0;
}
if (aRect.x + rectAfterZoom.width > cssPageRect.width) {
aRect.x = cssPageRect.width - rectAfterZoom.width;
aRect.x = aRect.x > 0 ? aRect.x : 0;
}
endZoomToMetrics.SetScrollOffset(aRect.TopLeft());
- endZoomToMetrics.mDisplayPort =
+ endZoomToMetrics.SetDisplayPortMargins(
CalculatePendingDisplayPort(endZoomToMetrics,
ScreenPoint(0,0),
- 0);
+ 0));
+ endZoomToMetrics.SetUseDisplayPortMargins();
StartAnimation(new ZoomAnimation(
mFrameMetrics.GetScrollOffset(),
mFrameMetrics.GetZoom(),
endZoomToMetrics.GetScrollOffset(),
endZoomToMetrics.GetZoom()));
// Schedule a repaint now, so the new displayport will be painted before the
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -233,17 +233,17 @@ public:
gfx3DMatrix GetTransformToLastDispatchedPaint();
/**
* Recalculates the displayport. Ideally, this should paint an area bigger
* than the composite-to dimensions so that when you scroll down, you don't
* checkerboard immediately. This includes a bunch of logic, including
* algorithms to bias painting in the direction of the velocity.
*/
- static const CSSRect CalculatePendingDisplayPort(
+ static const LayerMargin CalculatePendingDisplayPort(
const FrameMetrics& aFrameMetrics,
const ScreenPoint& aVelocity,
double aEstimatedPaintDuration);
/**
* Send an mozbrowserasyncscroll event.
* *** The monitor must be held while calling this.
*/
--- a/widget/xpwidgets/APZCCallbackHelper.cpp
+++ b/widget/xpwidgets/APZCCallbackHelper.cpp
@@ -62,43 +62,62 @@ static CSSRect ExpandDisplayPortToTileBo
}
static void
MaybeAlignAndClampDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics,
const CSSPoint& aActualScrollOffset)
{
// Correct the display-port by the difference between the requested scroll
// offset and the resulting scroll offset after setting the requested value.
- CSSRect& displayPort = aFrameMetrics.mDisplayPort;
- displayPort += aFrameMetrics.GetScrollOffset() - aActualScrollOffset;
+ if (!aFrameMetrics.GetUseDisplayPortMargins()) {
+ CSSRect& displayPort = aFrameMetrics.mDisplayPort;
+ displayPort += aFrameMetrics.GetScrollOffset() - aActualScrollOffset;
+
+ // Expand the display port to the next tile boundaries, if tiled thebes layers
+ // are enabled.
+ if (gfxPrefs::LayersTilesEnabled()) {
+ // We don't use LayersPixelsPerCSSPixel() here as mCumulativeResolution on
+ // this FrameMetrics may be incorrect (and is about to be reset by mZoom).
+ displayPort =
+ ExpandDisplayPortToTileBoundaries(displayPort + aActualScrollOffset,
+ aFrameMetrics.GetZoom() *
+ ScreenToLayerScale(1.0))
+ - aActualScrollOffset;
+ }
- // Expand the display port to the next tile boundaries, if tiled thebes layers
- // are enabled.
- if (gfxPrefs::LayersTilesEnabled()) {
- // We don't use LayersPixelsPerCSSPixel() here as mCumulativeResolution on
- // this FrameMetrics may be incorrect (and is about to be reset by mZoom).
- displayPort =
- ExpandDisplayPortToTileBoundaries(displayPort + aActualScrollOffset,
- aFrameMetrics.GetZoom() *
- ScreenToLayerScale(1.0))
- - aActualScrollOffset;
+ // Finally, clamp the display port to the expanded scrollable rect.
+ CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect();
+ displayPort = scrollableRect.Intersect(displayPort + aActualScrollOffset)
+ - aActualScrollOffset;
+ } else {
+ LayerPoint shift =
+ (aFrameMetrics.GetScrollOffset() - aActualScrollOffset) *
+ aFrameMetrics.LayersPixelsPerCSSPixel();
+ LayerMargin margins = aFrameMetrics.GetDisplayPortMargins();
+ margins.left -= shift.x;
+ margins.right += shift.x;
+ margins.top -= shift.y;
+ margins.bottom += shift.y;
+ aFrameMetrics.SetDisplayPortMargins(margins);
}
-
- // Finally, clamp the display port to the expanded scrollable rect.
- CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect();
- displayPort = scrollableRect.Intersect(displayPort + aActualScrollOffset)
- - aActualScrollOffset;
}
static void
RecenterDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics)
{
- CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels());
- aFrameMetrics.mDisplayPort.x = (compositionBounds.width - aFrameMetrics.mDisplayPort.width) / 2;
- aFrameMetrics.mDisplayPort.y = (compositionBounds.height - aFrameMetrics.mDisplayPort.height) / 2;
+ if (!aFrameMetrics.GetUseDisplayPortMargins()) {
+ CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels());
+ aFrameMetrics.mDisplayPort.x = (compositionBounds.width - aFrameMetrics.mDisplayPort.width) / 2;
+ aFrameMetrics.mDisplayPort.y = (compositionBounds.height - aFrameMetrics.mDisplayPort.height) / 2;
+ } else {
+ LayerMargin margins = aFrameMetrics.GetDisplayPortMargins();
+ margins.right = margins.left = margins.LeftRight() / 2;
+ margins.top = margins.bottom = margins.TopBottom() / 2;
+ aFrameMetrics.SetDisplayPortMargins(margins);
+ }
}
static CSSPoint
ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccessOut)
{
aSuccessOut = false;
if (!aFrame) {
@@ -200,21 +219,39 @@ APZCCallbackHelper::UpdateRootFrame(nsID
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.mScrollId);
if (!content) {
return;
}
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content);
if (!element) {
return;
}
- aUtils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
- aMetrics.mDisplayPort.y,
- aMetrics.mDisplayPort.width,
- aMetrics.mDisplayPort.height,
- element, 0);
+ if (!aMetrics.GetUseDisplayPortMargins()) {
+ aUtils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
+ aMetrics.mDisplayPort.y,
+ aMetrics.mDisplayPort.width,
+ aMetrics.mDisplayPort.height,
+ element, 0);
+ } else {
+ uint32_t alignment = gfxPrefs::LayersTilesEnabled()
+ ? TILEDLAYERBUFFER_TILE_SIZE : 1;
+ LayerMargin margins = aMetrics.GetDisplayPortMargins();
+ aUtils->SetDisplayPortMarginsForElement(margins.left,
+ margins.top,
+ margins.right,
+ margins.bottom,
+ alignment,
+ element, 0);
+ CSSRect baseCSS = aMetrics.mCompositionBounds / aMetrics.GetZoomToParent();
+ nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(),
+ baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(),
+ baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
+ baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
+ nsLayoutUtils::SetDisplayPortBase(content, base);
+ }
}
void
APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent,
FrameMetrics& aMetrics)
{
// Precondition checks
MOZ_ASSERT(aContent);
@@ -235,21 +272,39 @@ APZCCallbackHelper::UpdateSubFrame(nsICo
CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated);
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
if (element) {
if (!scrollUpdated) {
RecenterDisplayPort(aMetrics);
}
MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
- utils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
- aMetrics.mDisplayPort.y,
- aMetrics.mDisplayPort.width,
- aMetrics.mDisplayPort.height,
- element, 0);
+ if (!aMetrics.GetUseDisplayPortMargins()) {
+ utils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
+ aMetrics.mDisplayPort.y,
+ aMetrics.mDisplayPort.width,
+ aMetrics.mDisplayPort.height,
+ element, 0);
+ } else {
+ uint32_t alignment = gfxPrefs::LayersTilesEnabled()
+ ? TILEDLAYERBUFFER_TILE_SIZE : 1;
+ LayerMargin margins = aMetrics.GetDisplayPortMargins();
+ utils->SetDisplayPortMarginsForElement(margins.left,
+ margins.top,
+ margins.right,
+ margins.bottom,
+ alignment,
+ element, 0);
+ CSSRect baseCSS = aMetrics.mCompositionBounds / aMetrics.GetZoomToParent();
+ nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(),
+ baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(),
+ baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
+ baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
+ nsLayoutUtils::SetDisplayPortBase(aContent, base);
+ }
}
aMetrics.SetScrollOffset(actualScrollOffset);
}
already_AddRefed<nsIDOMWindowUtils>
APZCCallbackHelper::GetDOMWindowUtils(const nsIDocument* aDoc)
{