Bug 907743 - Align display port to tile boundaries when tiles are enabled. r=botond,kats

This aligns display ports to tile boundaries, taking care to compensate for
the difference between the requested scroll position and the actual scroll
position.
This commit is contained in:
Chris Lord 2013-09-10 18:21:04 -04:00
parent df8953eecb
commit 2b33da1618
7 changed files with 137 additions and 42 deletions

View File

@ -1482,9 +1482,8 @@ nsDOMWindowUtils::SuppressEventHandling(bool aSuppress)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aScrollY)
{
static nsresult
getScrollXYAppUnits(nsWeakPtr mWindow, bool aFlushLayout, nsPoint& aScrollPos) {
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
@ -1499,15 +1498,22 @@ nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aSc
doc->FlushPendingNotifications(Flush_Layout);
}
nsPoint scrollPos(0,0);
nsIPresShell *presShell = doc->GetShell();
if (presShell) {
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
if (sf) {
scrollPos = sf->GetScrollPosition();
aScrollPos = sf->GetScrollPosition();
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, int32_t* aScrollY)
{
nsPoint scrollPos(0,0);
nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
NS_ENSURE_SUCCESS(rv, rv);
*aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
*aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
@ -1531,6 +1537,18 @@ nsDOMWindowUtils::ScrollToCSSPixelsApproximate(float aX, float aY, bool* aRetVal
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX, float* aScrollY)
{
nsPoint scrollPos(0,0);
nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos);
NS_ENSURE_SUCCESS(rv, rv);
*aScrollX = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.x);
*aScrollY = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.y);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth,
int32_t* aHeight)

View File

@ -43,7 +43,7 @@ interface nsIDOMEventTarget;
interface nsIRunnable;
interface nsICompositionStringSynthesizer;
[scriptable, uuid(e12df416-e3e0-4177-b936-fa106f62ae3f)]
[scriptable, uuid(3772df78-905f-40cf-952f-e4954c63d0ec)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -652,6 +652,14 @@ interface nsIDOMWindowUtils : nsISupports {
*/
void getScrollXY(in boolean aFlushLayout, out long aScrollX, out long aScrollY);
/**
* Returns the scroll position of the window's currently loaded document.
*
* @param aFlushLayout flushes layout if true. Otherwise, no flush occurs.
* @see nsIDOMWindow::scrollX/Y
*/
void getScrollXYFloat(in boolean aFlushLayout, out float aScrollX, out float aScrollY);
/**
* Sets the scroll position of the root scroll frame of the window.
* Returns true on success, false on error (if the window didn't have a root

View File

@ -1559,44 +1559,49 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
return true;
}
CSSRect cssCompositedRect = aFrameMetrics.CalculateCompositedRectInCssPixels();
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
FrameMetrics newMetrics = aFrameMetrics;
APZCCallbackHelper::UpdateRootFrame(utils, newMetrics);
CSSRect cssCompositedRect = newMetrics.CalculateCompositedRectInCssPixels();
// The BrowserElementScrolling helper must know about these updated metrics
// for other functions it performs, such as double tap handling.
// Note, %f must not be used because it is locale specific!
nsCString data;
data.AppendPrintf("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
data.AppendPrintf(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.mScrollOffset.x));
data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.mScrollOffset.y));
data.AppendLiteral(", \"viewport\" : ");
data.AppendLiteral("{ \"width\" : ");
data.AppendFloat(aFrameMetrics.mViewport.width);
data.AppendFloat(newMetrics.mViewport.width);
data.AppendLiteral(", \"height\" : ");
data.AppendFloat(aFrameMetrics.mViewport.height);
data.AppendFloat(newMetrics.mViewport.height);
data.AppendLiteral(" }");
data.AppendLiteral(", \"displayPort\" : ");
data.AppendLiteral("{ \"x\" : ");
data.AppendFloat(aFrameMetrics.mDisplayPort.x);
data.AppendFloat(newMetrics.mDisplayPort.x);
data.AppendLiteral(", \"y\" : ");
data.AppendFloat(aFrameMetrics.mDisplayPort.y);
data.AppendFloat(newMetrics.mDisplayPort.y);
data.AppendLiteral(", \"width\" : ");
data.AppendFloat(aFrameMetrics.mDisplayPort.width);
data.AppendFloat(newMetrics.mDisplayPort.width);
data.AppendLiteral(", \"height\" : ");
data.AppendFloat(aFrameMetrics.mDisplayPort.height);
data.AppendFloat(newMetrics.mDisplayPort.height);
data.AppendLiteral(" }");
data.AppendLiteral(", \"compositionBounds\" : ");
data.AppendPrintf("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
data.AppendPrintf(", \"y\" : %d", aFrameMetrics.mCompositionBounds.y);
data.AppendPrintf(", \"width\" : %d", aFrameMetrics.mCompositionBounds.width);
data.AppendPrintf(", \"height\" : %d", aFrameMetrics.mCompositionBounds.height);
data.AppendPrintf("{ \"x\" : %d", newMetrics.mCompositionBounds.x);
data.AppendPrintf(", \"y\" : %d", newMetrics.mCompositionBounds.y);
data.AppendPrintf(", \"width\" : %d", newMetrics.mCompositionBounds.width);
data.AppendPrintf(", \"height\" : %d", newMetrics.mCompositionBounds.height);
data.AppendLiteral(" }");
data.AppendLiteral(", \"cssPageRect\" : ");
data.AppendLiteral("{ \"x\" : ");
data.AppendFloat(aFrameMetrics.mScrollableRect.x);
data.AppendFloat(newMetrics.mScrollableRect.x);
data.AppendLiteral(", \"y\" : ");
data.AppendFloat(aFrameMetrics.mScrollableRect.y);
data.AppendFloat(newMetrics.mScrollableRect.y);
data.AppendLiteral(", \"width\" : ");
data.AppendFloat(aFrameMetrics.mScrollableRect.width);
data.AppendFloat(newMetrics.mScrollableRect.width);
data.AppendLiteral(", \"height\" : ");
data.AppendFloat(aFrameMetrics.mScrollableRect.height);
data.AppendFloat(newMetrics.mScrollableRect.height);
data.AppendLiteral(" }");
data.AppendLiteral(", \"cssCompositedRect\" : ");
data.AppendLiteral("{ \"width\" : ");
@ -1608,19 +1613,7 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
APZCCallbackHelper::UpdateRootFrame(utils, aFrameMetrics);
mLastMetrics = aFrameMetrics;
// ScrollWindowTo() can make some small adjustments to the offset before
// actually scrolling the window. To ensure that the scroll offset stored
// in mLastMetrics is the same as the offset stored in the window,
// re-query the latter.
CSSIntPoint actualScrollOffset;
utils->GetScrollXY(false, &actualScrollOffset.x, &actualScrollOffset.y);
mLastMetrics.mScrollOffset = actualScrollOffset;
mLastMetrics = newMetrics;
return true;
}

View File

@ -37,6 +37,7 @@ EXPORTS += [
'opengl/TexturePoolOGL.h',
'ReadbackLayer.h',
'SharedTextureImage.h',
'TiledLayerBuffer.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':

View File

@ -137,10 +137,8 @@ public:
// Return the actual scroll value so we can use it to filter
// out scroll messages triggered by setting the display port.
CSSIntPoint actualScrollOffset;
utils->GetScrollXY(false, &actualScrollOffset.x, &actualScrollOffset.y);
if (mLastOffsetOut) {
*mLastOffsetOut = actualScrollOffset;
*mLastOffsetOut = mozilla::gfx::RoundedToInt(mFrameMetrics.mScrollOffset);
}
if (mLastScrollIdOut) {
mLastScrollIdOut->mScrollId = mFrameMetrics.mScrollId;

View File

@ -4,10 +4,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "APZCCallbackHelper.h"
#include "mozilla/Preferences.h"
#include "nsIScrollableFrame.h"
#include "nsLayoutUtils.h"
#include "nsIDOMElement.h"
#include "nsIInterfaceRequestorUtils.h"
#include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
namespace mozilla {
namespace widget {
@ -24,9 +26,69 @@ APZCCallbackHelper::HasValidPresShellId(nsIDOMWindowUtils* aUtils,
return NS_SUCCEEDED(rv) && aMetrics.mPresShellId == presShellId;
}
/**
* Expands a given rectangle to the next tile boundary. Note, this will
* expand the rectangle if it is already on tile boundaries.
*/
static CSSRect ExpandDisplayPortToTileBoundaries(
const CSSRect& aDisplayPort,
const CSSToLayerScale& aLayerPixelsPerCSSPixel)
{
// Convert the given rect to layer coordinates so we can inflate to tile
// boundaries (layer space corresponds to texture pixel space here).
LayerRect displayPortInLayerSpace = aDisplayPort * aLayerPixelsPerCSSPixel;
// Inflate the rectangle by 1 so that we always push to the next tile
// boundary. This is desirable to stop from having a rectangle with a
// moving origin occasionally being smaller when it coincidentally lines
// up to tile boundaries.
displayPortInLayerSpace.Inflate(1);
// Now nudge the rectangle to the nearest equal or larger tile boundary.
gfxFloat left = TILEDLAYERBUFFER_TILE_SIZE
* floor(displayPortInLayerSpace.x / TILEDLAYERBUFFER_TILE_SIZE);
gfxFloat top = TILEDLAYERBUFFER_TILE_SIZE
* floor(displayPortInLayerSpace.y / TILEDLAYERBUFFER_TILE_SIZE);
gfxFloat right = TILEDLAYERBUFFER_TILE_SIZE
* ceil(displayPortInLayerSpace.XMost() / TILEDLAYERBUFFER_TILE_SIZE);
gfxFloat bottom = TILEDLAYERBUFFER_TILE_SIZE
* ceil(displayPortInLayerSpace.YMost() / TILEDLAYERBUFFER_TILE_SIZE);
displayPortInLayerSpace = LayerRect(left, top, right - left, bottom - top);
CSSRect displayPort = displayPortInLayerSpace / aLayerPixelsPerCSSPixel;
return displayPort;
}
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 += aActualScrollOffset - aFrameMetrics.mScrollOffset;
// Expand the display port to the next tile boundaries, if tiled thebes layers
// are enabled.
if (Preferences::GetBool("layers.force-tiles")) {
// aFrameMetrics.mZoom is the zoom amount reported by the APZC,
// scale by ScreenToLayerScale to get the gecko zoom amount
displayPort =
ExpandDisplayPortToTileBoundaries(displayPort + aActualScrollOffset,
aFrameMetrics.mZoom * ScreenToLayerScale(1))
- aActualScrollOffset;
}
// Finally, clamp the display port to the scrollable rect.
CSSRect scrollableRect = aFrameMetrics.mScrollableRect;
displayPort = scrollableRect.ClampRect(displayPort + aActualScrollOffset)
- aActualScrollOffset;
}
void
APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
const FrameMetrics& aMetrics)
FrameMetrics& aMetrics)
{
// Precondition checks
MOZ_ASSERT(aUtils);
@ -47,6 +109,17 @@ APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
// Scroll the window to the desired spot
aUtils->ScrollToCSSPixelsApproximate(aMetrics.mScrollOffset.x, aMetrics.mScrollOffset.y, nullptr);
// Re-query the scroll position after setting it so that anything that relies on it
// can have an accurate value.
CSSPoint actualScrollOffset;
aUtils->GetScrollXYFloat(false, &actualScrollOffset.x, &actualScrollOffset.y);
// Correct the display port due to the difference between mScrollOffset and the
// actual scroll offset, possibly align it to tile boundaries (if tiled layers are
// enabled), and clamp it to the scrollable rect.
MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
aMetrics.mScrollOffset = actualScrollOffset;
// The mZoom variable on the frame metrics stores the CSS-to-screen scale for this
// frame. This scale includes all of the (cumulative) resolutions set on the presShells
// from the root down to this frame. However, when setting the resolution, we only

View File

@ -33,9 +33,13 @@ public:
const FrameMetrics& aMetrics);
/* Applies the scroll and zoom parameters from the given FrameMetrics object to
the root frame corresponding to the given DOMWindowUtils. */
the root frame corresponding to the given DOMWindowUtils. If tiled thebes
layers are enabled, this will align the displayport to tile boundaries.
Setting the scroll position can cause some small adjustments to be made
to the actual scroll position. aMetrics' display port and scroll position
will be updated with any modifications made. */
static void UpdateRootFrame(nsIDOMWindowUtils* aUtils,
const FrameMetrics& aMetrics);
FrameMetrics& aMetrics);
/* Applies the scroll parameters from the given FrameMetrics object to the subframe
corresponding to the given content object. */