mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 795657: Integrate native viewport configuration better into async pan-zoom code. r=jwir3,roc
This is a rollup of the following patches - Change the interpretation of FrameMetrics.mZoom to a "resolution-indepedent zoom", instead of a resolution-depedent scale factor. r=roc - Remove mention of "meta" from TabChild. r=roc - Remove some useless logging. r=roc - Tag FrameMetrics with its composition bounds at paint time. r=roc - Add a helper to calculate the render resolution for a FrameMetrics. r=roc - Add a helper to compute the approximate CSS dimensions a FrameMetrics will cover during composition. r=roc - BrowserElementScrolling doesn't actually care about zoom or resolution. r=roc - Accept the viewport that content has calculated, when it's received the latest widget geometry update. r=roc - Mechanically separate uses of zoom/resolution based on new definitions. r=roc - Convert GetViewportInfo()'s resolution-dependent scale into resolution-indepedent zoom. r=roc - Reinterpret defaultZoom == 0.0 as "intrinsic scale". r=jwir3,roc
This commit is contained in:
parent
d52cbd4f2e
commit
b00b1e25b0
@ -204,18 +204,9 @@ const ContentPanning = {
|
||||
|
||||
_recvViewportChange: function(data) {
|
||||
let metrics = data.json;
|
||||
let displayPort = metrics.displayPort;
|
||||
|
||||
let compositionWidth = metrics.compositionBounds.width;
|
||||
let compositionHeight = metrics.compositionBounds.height;
|
||||
|
||||
let x = metrics.x;
|
||||
let y = metrics.y;
|
||||
|
||||
this._zoom = metrics.zoom;
|
||||
this._viewport = new Rect(x, y,
|
||||
compositionWidth / metrics.zoom,
|
||||
compositionHeight / metrics.zoom);
|
||||
this._viewport = new Rect(metrics.x, metrics.y,
|
||||
metrics.viewport.width,
|
||||
metrics.viewport.height);
|
||||
this._cssPageRect = new Rect(metrics.cssPageRect.x,
|
||||
metrics.cssPageRect.y,
|
||||
metrics.cssPageRect.width,
|
||||
@ -232,7 +223,6 @@ const ContentPanning = {
|
||||
|
||||
let win = content;
|
||||
|
||||
let zoom = this._zoom;
|
||||
let element = ElementTouchHelper.anyElementFromPoint(win, data.x, data.y);
|
||||
if (!element) {
|
||||
this._zoomOut();
|
||||
|
@ -183,7 +183,7 @@ TabChild::HandleEvent(nsIDOMEvent* aEvent)
|
||||
if (eventType.EqualsLiteral("DOMMetaAdded")) {
|
||||
// This meta data may or may not have been a meta viewport tag. If it was,
|
||||
// we should handle it immediately.
|
||||
HandlePossibleMetaViewportChange();
|
||||
HandlePossibleViewportChange();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -222,21 +222,27 @@ TabChild::Observe(nsISupports *aSubject,
|
||||
|
||||
mContentDocumentIsDisplayed = true;
|
||||
|
||||
// Reset CSS viewport and zoom to default on new page, then calculate them
|
||||
// properly using the actual metadata from the page.
|
||||
// Reset CSS viewport and zoom to default on new page, then
|
||||
// calculate them properly using the actual metadata from the
|
||||
// page.
|
||||
SetCSSViewport(kDefaultViewportSize.width, kDefaultViewportSize.height);
|
||||
|
||||
// Calculate a really simple resolution that we probably won't be
|
||||
// keeping, as well as putting the scroll offset back to the top-left of
|
||||
// the page.
|
||||
float resolution = float(mInnerSize.width) / float(kDefaultViewportSize.width);
|
||||
mLastMetrics.mZoom.width = mLastMetrics.mZoom.height =
|
||||
mLastMetrics.mResolution.width = mLastMetrics.mResolution.height =
|
||||
resolution;
|
||||
// Calculate a really simple resolution that we probably won't
|
||||
// be keeping, as well as putting the scroll offset back to
|
||||
// the top-left of the page.
|
||||
mLastMetrics.mZoom = gfxSize(1.0, 1.0);
|
||||
mLastMetrics.mViewport =
|
||||
gfx::Rect(0, 0,
|
||||
kDefaultViewportSize.width, kDefaultViewportSize.height);
|
||||
mLastMetrics.mCompositionBounds = nsIntRect(nsIntPoint(0, 0),
|
||||
mInnerSize);
|
||||
mLastMetrics.mResolution =
|
||||
AsyncPanZoomController::CalculateResolution(mLastMetrics);
|
||||
mLastMetrics.mScrollOffset = gfx::Point(0, 0);
|
||||
utils->SetResolution(resolution, resolution);
|
||||
utils->SetResolution(mLastMetrics.mResolution.width,
|
||||
mLastMetrics.mResolution.height);
|
||||
|
||||
HandlePossibleMetaViewportChange();
|
||||
HandlePossibleViewportChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -350,7 +356,7 @@ TabChild::SetCSSViewport(float aWidth, float aHeight)
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::HandlePossibleMetaViewportChange()
|
||||
TabChild::HandlePossibleViewportChange()
|
||||
{
|
||||
if (!IsAsyncPanZoomEnabled()) {
|
||||
return;
|
||||
@ -362,16 +368,16 @@ TabChild::HandlePossibleMetaViewportChange()
|
||||
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||
|
||||
ViewportInfo viewportMetaData =
|
||||
ViewportInfo viewportInfo =
|
||||
nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height);
|
||||
SendUpdateZoomConstraints(viewportMetaData.allowZoom,
|
||||
viewportMetaData.minZoom,
|
||||
viewportMetaData.maxZoom);
|
||||
SendUpdateZoomConstraints(viewportInfo.allowZoom,
|
||||
viewportInfo.minZoom,
|
||||
viewportInfo.maxZoom);
|
||||
|
||||
float screenW = mInnerSize.width;
|
||||
float screenH = mInnerSize.height;
|
||||
float viewportW = viewportMetaData.width;
|
||||
float viewportH = viewportMetaData.height;
|
||||
float viewportW = viewportInfo.width;
|
||||
float viewportH = viewportInfo.height;
|
||||
|
||||
// We're not being displayed in any way; don't bother doing anything because
|
||||
// that will just confuse future adjustments.
|
||||
@ -385,8 +391,8 @@ TabChild::HandlePossibleMetaViewportChange()
|
||||
// we have to call SetCSSViewport twice - once to set the width, and the
|
||||
// second time to figure out the height based on the layout at that width.
|
||||
float oldBrowserWidth = mOldViewportWidth;
|
||||
mLastMetrics.mViewport.width = viewportMetaData.width;
|
||||
mLastMetrics.mViewport.height = viewportMetaData.height;
|
||||
mLastMetrics.mViewport.width = viewportInfo.width;
|
||||
mLastMetrics.mViewport.height = viewportInfo.height;
|
||||
if (!oldBrowserWidth) {
|
||||
oldBrowserWidth = kDefaultViewportSize.width;
|
||||
}
|
||||
@ -425,7 +431,7 @@ TabChild::HandlePossibleMetaViewportChange()
|
||||
float pageHeight = NS_MAX(htmlHeight, bodyHeight);
|
||||
|
||||
minScale = mInnerSize.width / pageWidth;
|
||||
minScale = clamped((double)minScale, viewportMetaData.minZoom, viewportMetaData.maxZoom);
|
||||
minScale = clamped((double)minScale, viewportInfo.minZoom, viewportInfo.maxZoom);
|
||||
|
||||
viewportH = NS_MAX(viewportH, screenH / minScale);
|
||||
SetCSSViewport(viewportW, viewportH);
|
||||
@ -446,23 +452,42 @@ TabChild::HandlePossibleMetaViewportChange()
|
||||
if (!oldScreenWidth) {
|
||||
oldScreenWidth = mInnerSize.width;
|
||||
}
|
||||
float zoomScale = (screenW * oldBrowserWidth) / (oldScreenWidth * viewportW);
|
||||
|
||||
float zoom = clamped(double(mLastMetrics.mZoom.width * zoomScale),
|
||||
viewportMetaData.minZoom, viewportMetaData.maxZoom);
|
||||
utils->SetResolution(zoom, zoom);
|
||||
|
||||
FrameMetrics metrics(mLastMetrics);
|
||||
metrics.mViewport = gfx::Rect(0.0f, 0.0f, viewportW, viewportH);
|
||||
metrics.mScrollableRect = gfx::Rect(0.0f, 0.0f, pageWidth, pageHeight);
|
||||
metrics.mCompositionBounds = nsIntRect(0, 0, mInnerSize.width, mInnerSize.height);
|
||||
metrics.mZoom.width = metrics.mZoom.height =
|
||||
metrics.mResolution.width = metrics.mResolution.height = zoom;
|
||||
|
||||
gfxSize intrinsicScale =
|
||||
AsyncPanZoomController::CalculateIntrinsicScale(metrics);
|
||||
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
if (viewportInfo.defaultZoom < 0.01f) {
|
||||
viewportInfo.defaultZoom = intrinsicScale.width;
|
||||
}
|
||||
MOZ_ASSERT(viewportInfo.minZoom <= viewportInfo.defaultZoom &&
|
||||
viewportInfo.defaultZoom <= viewportInfo.maxZoom);
|
||||
// GetViewportInfo() returns a resolution-dependent scale factor.
|
||||
// Convert that to a resolution-indepedent zoom.
|
||||
metrics.mZoom = gfxSize(viewportInfo.defaultZoom / intrinsicScale.width,
|
||||
viewportInfo.defaultZoom / intrinsicScale.height);
|
||||
|
||||
metrics.mDisplayPort = 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, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
|
||||
gfxSize resolution = AsyncPanZoomController::CalculateResolution(metrics);
|
||||
// XXX is this actually hysteresis? This calculation is not well
|
||||
// understood. It's taken from the previous JS implementation.
|
||||
gfxFloat hysteresis/*?*/ =
|
||||
gfxFloat(oldBrowserWidth) / gfxFloat(oldScreenWidth);
|
||||
resolution.width *= hysteresis;
|
||||
resolution.height *= hysteresis;
|
||||
metrics.mResolution = resolution;
|
||||
utils->SetResolution(metrics.mResolution.width, metrics.mResolution.height);
|
||||
|
||||
// Force a repaint with these metrics. This, among other things, sets the
|
||||
// displayport, so we start with async painting.
|
||||
RecvUpdateFrame(metrics);
|
||||
@ -1077,10 +1102,6 @@ TabChild::RecvShow(const nsIntSize& size)
|
||||
bool
|
||||
TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[TabChild] Update Dimensions to (x,y,w,h)= (%ud, %ud, %ud, %ud) and move to (w,h)= (%ud, %ud)\n", rect.x, rect.y, rect.width, rect.height, size.width, size.height);
|
||||
#endif
|
||||
|
||||
if (!mRemoteFrame) {
|
||||
return true;
|
||||
}
|
||||
@ -1098,7 +1119,7 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||
baseWin->SetPositionAndSize(0, 0, size.width, size.height,
|
||||
true);
|
||||
|
||||
HandlePossibleMetaViewportChange();
|
||||
HandlePossibleViewportChange();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1141,15 +1162,15 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
nsCString data;
|
||||
data += nsPrintfCString("{ \"x\" : %d", NS_lround(aFrameMetrics.mScrollOffset.x));
|
||||
data += nsPrintfCString(", \"y\" : %d", NS_lround(aFrameMetrics.mScrollOffset.y));
|
||||
// We don't treat the x and y scales any differently for this
|
||||
// semi-platform-specific code.
|
||||
data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mZoom.width);
|
||||
data += nsPrintfCString(", \"viewport\" : ");
|
||||
data += nsPrintfCString("{ \"width\" : %f", aFrameMetrics.mViewport.width);
|
||||
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mViewport.height);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(", \"displayPort\" : ");
|
||||
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mDisplayPort.x);
|
||||
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mDisplayPort.y);
|
||||
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mDisplayPort.width);
|
||||
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mDisplayPort.height);
|
||||
data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(", \"compositionBounds\" : ");
|
||||
data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mCompositionBounds.x);
|
||||
@ -1170,13 +1191,15 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||
nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mWebNav);
|
||||
|
||||
gfx::Rect cssCompositedRect =
|
||||
AsyncPanZoomController::CalculateCompositedRectInCssPixels(aFrameMetrics);
|
||||
utils->SetScrollPositionClampingScrollPortSize(
|
||||
aFrameMetrics.mCompositionBounds.width / aFrameMetrics.mZoom.width,
|
||||
aFrameMetrics.mCompositionBounds.height / aFrameMetrics.mZoom.width);
|
||||
cssCompositedRect.width, cssCompositedRect.height);
|
||||
window->ScrollTo(aFrameMetrics.mScrollOffset.x,
|
||||
aFrameMetrics.mScrollOffset.y);
|
||||
utils->SetResolution(aFrameMetrics.mResolution.width,
|
||||
aFrameMetrics.mResolution.width);
|
||||
gfxSize resolution = AsyncPanZoomController::CalculateResolution(
|
||||
aFrameMetrics);
|
||||
utils->SetResolution(resolution.width, resolution.height);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
nsCOMPtr<nsIDOMElement> docElement;
|
||||
|
@ -338,11 +338,12 @@ private:
|
||||
// variables local to this class before setting it.
|
||||
void SetCSSViewport(float aX, float aY);
|
||||
|
||||
// Recalculates the display state, including the CSS viewport. This should
|
||||
// be called whenever we believe the meta viewport data on a document may
|
||||
// have changed. If it didn't change, this function doesn't do anything.
|
||||
// However, it should not be called all the time as it is fairly expensive.
|
||||
void HandlePossibleMetaViewportChange();
|
||||
// Recalculates the display state, including the CSS
|
||||
// viewport. This should be called whenever we believe the
|
||||
// viewport data on a document may have changed. If it didn't
|
||||
// change, this function doesn't do anything. However, it should
|
||||
// not be called all the time as it is fairly expensive.
|
||||
void HandlePossibleViewportChange();
|
||||
|
||||
// Wraps up a JSON object as a structured clone and sends it to the browser
|
||||
// chrome script.
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
, mScrollId(NULL_SCROLL_ID)
|
||||
, mScrollableRect(0, 0, 0, 0)
|
||||
, mResolution(1, 1)
|
||||
, mZoom(1, 1)
|
||||
, mDevPixelsPerCSSPixel(1)
|
||||
, mMayHaveTouchListeners(false)
|
||||
{}
|
||||
@ -204,17 +205,19 @@ public:
|
||||
// resolution of parent layers is opaque to this metric.
|
||||
gfxSize mResolution;
|
||||
|
||||
// The amount we are currently zooming the frame. This is distinct from
|
||||
// |mResolution| as we can paint a frame at a different resolution than we
|
||||
// zoom it at. This is useful in situations where we want to zoom a frame
|
||||
// without forcing a repaint. At steady state, this and |mResolution| will be
|
||||
// equal.
|
||||
// The resolution-independent "user zoom". For example, if a page
|
||||
// configures the viewport to a zoom value of 2x, then this member
|
||||
// will always be 2.0 no matter what the viewport or composition
|
||||
// bounds.
|
||||
//
|
||||
// Every time this frame is composited and the compositor samples its
|
||||
// transform, this metric is used to create a transform which is
|
||||
// post-multiplied into the parent's transform. Since this only happens when
|
||||
// we walk the layer tree, the resulting transform isn't stored here. Thus the
|
||||
// zoom of parent layers is opaque to this metric.
|
||||
// In the steady state (no animations), and ignoring DPI, then the
|
||||
// following is usually true
|
||||
//
|
||||
// intrinsicScale = (mCompositionBounds / mViewport)
|
||||
// mResolution = mZoom * intrinsicScale
|
||||
//
|
||||
// When this is not true, we're probably asynchronously sampling a
|
||||
// zoom animation for content.
|
||||
gfxSize mZoom;
|
||||
|
||||
// The conversion factor between CSS pixels and device pixels for this frame.
|
||||
|
@ -142,11 +142,11 @@ nsEventStatus
|
||||
AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
nsInputEvent* aOutEvent)
|
||||
{
|
||||
float currentZoom;
|
||||
gfxFloat currentResolution;
|
||||
gfx::Point currentScrollOffset, lastScrollOffset;
|
||||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
currentZoom = mFrameMetrics.mZoom.width;
|
||||
currentResolution = CalculateResolution(mFrameMetrics).width;
|
||||
currentScrollOffset = gfx::Point(mFrameMetrics.mScrollOffset.x,
|
||||
mFrameMetrics.mScrollOffset.y);
|
||||
lastScrollOffset = gfx::Point(mLastContentPaintMetrics.mScrollOffset.x,
|
||||
@ -179,7 +179,7 @@ AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
if (touch) {
|
||||
gfx::Point refPoint = WidgetSpaceToCompensatedViewportSpace(
|
||||
gfx::Point(touch->mRefPoint.x, touch->mRefPoint.y),
|
||||
currentZoom);
|
||||
currentResolution);
|
||||
touch->mRefPoint = nsIntPoint(refPoint.x, refPoint.y);
|
||||
}
|
||||
}
|
||||
@ -188,7 +188,7 @@ AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
||||
default: {
|
||||
gfx::Point refPoint = WidgetSpaceToCompensatedViewportSpace(
|
||||
gfx::Point(aOutEvent->refPoint.x, aOutEvent->refPoint.y),
|
||||
currentZoom);
|
||||
currentResolution);
|
||||
aOutEvent->refPoint = nsIntPoint(refPoint.x, refPoint.y);
|
||||
break;
|
||||
}
|
||||
@ -444,10 +444,11 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
float scale = mFrameMetrics.mZoom.width;
|
||||
|
||||
gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
|
||||
gfxFloat userZoom = mFrameMetrics.mZoom.width;
|
||||
nsIntPoint focusPoint = aEvent.mFocusPoint;
|
||||
float xFocusChange = (mLastZoomFocus.x - focusPoint.x) / scale, yFocusChange = (mLastZoomFocus.y - focusPoint.y) / scale;
|
||||
gfxFloat xFocusChange = (mLastZoomFocus.x - focusPoint.x) / resolution;
|
||||
gfxFloat yFocusChange = (mLastZoomFocus.y - focusPoint.y) / resolution;
|
||||
// If displacing by the change in focus point will take us off page bounds,
|
||||
// then reduce the displacement such that it doesn't.
|
||||
if (mX.DisplacementWillOverscroll(xFocusChange) != Axis::OVERSCROLL_NONE) {
|
||||
@ -461,17 +462,18 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
// When we zoom in with focus, we can zoom too much towards the boundaries
|
||||
// that we actually go over them. These are the needed displacements along
|
||||
// either axis such that we don't overscroll the boundaries when zooming.
|
||||
float neededDisplacementX = 0, neededDisplacementY = 0;
|
||||
gfxFloat neededDisplacementX = 0, neededDisplacementY = 0;
|
||||
|
||||
// Only do the scaling if we won't go over 8x zoom in or out.
|
||||
bool doScale = (scale < mMaxZoom && spanRatio > 1.0f) || (scale > mMinZoom && spanRatio < 1.0f);
|
||||
bool doScale = (spanRatio > 1.0 && userZoom < mMaxZoom) ||
|
||||
(spanRatio < 1.0 && userZoom > mMinZoom);
|
||||
|
||||
// If this zoom will take it over 8x zoom in either direction, but it's not
|
||||
// already there, then normalize it.
|
||||
if (scale * spanRatio > mMaxZoom) {
|
||||
spanRatio = scale / mMaxZoom;
|
||||
} else if (scale * spanRatio < mMinZoom) {
|
||||
spanRatio = scale / mMinZoom;
|
||||
if (userZoom * spanRatio > mMaxZoom) {
|
||||
spanRatio = userZoom / mMaxZoom;
|
||||
} else if (userZoom * spanRatio < mMinZoom) {
|
||||
spanRatio = userZoom / mMinZoom;
|
||||
}
|
||||
|
||||
if (doScale) {
|
||||
@ -509,8 +511,7 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
}
|
||||
|
||||
if (doScale) {
|
||||
ScaleWithFocus(scale * spanRatio,
|
||||
focusPoint);
|
||||
ScaleWithFocus(userZoom * spanRatio, focusPoint);
|
||||
|
||||
if (neededDisplacementX != 0 || neededDisplacementY != 0) {
|
||||
ScrollBy(gfx::Point(neededDisplacementX, neededDisplacementY));
|
||||
@ -549,10 +550,12 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven
|
||||
if (mGeckoContentController) {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
|
||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
||||
mFrameMetrics.mZoom.width);
|
||||
mGeckoContentController->HandleSingleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
||||
resolution);
|
||||
mGeckoContentController->HandleSingleTap(nsIntPoint(NS_lround(point.x),
|
||||
NS_lround(point.y)));
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
@ -568,10 +571,12 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
if (mAllowZoom) {
|
||||
gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
|
||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
||||
mFrameMetrics.mZoom.width);
|
||||
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
||||
resolution);
|
||||
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x),
|
||||
NS_lround(point.y)));
|
||||
}
|
||||
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
@ -643,10 +648,12 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
||||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
float inverseScale = 1 / mFrameMetrics.mZoom.width;
|
||||
gfxFloat inverseResolution = 1 / CalculateResolution(mFrameMetrics).width;
|
||||
|
||||
int32_t xDisplacement = mX.GetDisplacementForDuration(inverseScale, timeDelta);
|
||||
int32_t yDisplacement = mY.GetDisplacementForDuration(inverseScale, timeDelta);
|
||||
int32_t xDisplacement = mX.GetDisplacementForDuration(inverseResolution,
|
||||
timeDelta);
|
||||
int32_t yDisplacement = mY.GetDisplacementForDuration(inverseResolution,
|
||||
timeDelta);
|
||||
if (!xDisplacement && !yDisplacement) {
|
||||
return;
|
||||
}
|
||||
@ -681,11 +688,11 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
||||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
float inverseScale = 1 / mFrameMetrics.mZoom.width;
|
||||
gfxFloat inverseResolution = 1 / CalculateResolution(mFrameMetrics).width;
|
||||
|
||||
ScrollBy(gfx::Point(
|
||||
mX.GetDisplacementForDuration(inverseScale, aDelta),
|
||||
mY.GetDisplacementForDuration(inverseScale, aDelta)
|
||||
mX.GetDisplacementForDuration(inverseResolution, aDelta),
|
||||
mY.GetDisplacementForDuration(inverseResolution, aDelta)
|
||||
));
|
||||
RequestContentRepaint();
|
||||
|
||||
@ -711,23 +718,26 @@ void AsyncPanZoomController::ScrollBy(const gfx::Point& aOffset) {
|
||||
void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
|
||||
FrameMetrics metrics = mFrameMetrics;
|
||||
gfx::Rect pageSize = aCSSPageRect;
|
||||
float scale = mFrameMetrics.mZoom.width;
|
||||
gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
|
||||
|
||||
// The page rect is the css page rect scaled by the current zoom.
|
||||
pageSize.ScaleInverseRoundOut(scale);
|
||||
pageSize.ScaleInverseRoundOut(resolution);
|
||||
|
||||
// Round the page rect so we don't get any truncation, then get the nsIntRect
|
||||
// from this.
|
||||
metrics.mContentRect = nsIntRect(pageSize.x, pageSize.y, pageSize.width, pageSize.height);
|
||||
metrics.mContentRect = nsIntRect(pageSize.x, pageSize.y,
|
||||
pageSize.width, pageSize.height);
|
||||
metrics.mScrollableRect = aCSSPageRect;
|
||||
|
||||
mFrameMetrics = metrics;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFocus) {
|
||||
float scaleFactor = aScale / mFrameMetrics.mZoom.width;
|
||||
void AsyncPanZoomController::ScaleWithFocus(float aZoom,
|
||||
const nsIntPoint& aFocus) {
|
||||
float zoomFactor = aZoom / mFrameMetrics.mZoom.width;
|
||||
gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
|
||||
|
||||
SetZoomAndResolution(aScale);
|
||||
SetZoomAndResolution(aZoom);
|
||||
|
||||
// Force a recalculation of the page rect based on the new zoom and the
|
||||
// current CSS page rect (which is unchanged since it's not affected by zoom).
|
||||
@ -735,9 +745,11 @@ void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFoc
|
||||
|
||||
// If the new scale is very small, we risk multiplying in huge rounding
|
||||
// errors, so don't bother adjusting the scroll offset.
|
||||
if (aScale >= 0.01f) {
|
||||
mFrameMetrics.mScrollOffset.x += float(aFocus.x) * (scaleFactor - 1.0f) / aScale;
|
||||
mFrameMetrics.mScrollOffset.y += float(aFocus.y) * (scaleFactor - 1.0f) / aScale;
|
||||
if (resolution >= 0.01f) {
|
||||
mFrameMetrics.mScrollOffset.x +=
|
||||
gfxFloat(aFocus.x) * (zoomFactor - 1.0) / resolution;
|
||||
mFrameMetrics.mScrollOffset.y +=
|
||||
gfxFloat(aFocus.y) * (zoomFactor - 1.0) / resolution;
|
||||
}
|
||||
}
|
||||
|
||||
@ -804,9 +816,9 @@ const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
double estimatedPaintDuration =
|
||||
aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0;
|
||||
|
||||
float scale = aFrameMetrics.mZoom.width;
|
||||
gfxFloat resolution = CalculateResolution(aFrameMetrics).width;
|
||||
nsIntRect compositionBounds = aFrameMetrics.mCompositionBounds;
|
||||
compositionBounds.ScaleInverseRoundIn(scale);
|
||||
compositionBounds.ScaleInverseRoundIn(resolution);
|
||||
const gfx::Rect& scrollableRect = aFrameMetrics.mScrollableRect;
|
||||
|
||||
gfx::Point scrollOffset = aFrameMetrics.mScrollOffset;
|
||||
@ -864,6 +876,35 @@ const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
return displayPort;
|
||||
}
|
||||
|
||||
/*static*/ gfxSize
|
||||
AsyncPanZoomController::CalculateIntrinsicScale(const FrameMetrics& aMetrics)
|
||||
{
|
||||
gfxFloat intrinsicScale = (gfxFloat(aMetrics.mCompositionBounds.width) /
|
||||
gfxFloat(aMetrics.mViewport.width));
|
||||
return gfxSize(intrinsicScale, intrinsicScale);
|
||||
}
|
||||
|
||||
/*static*/ gfxSize
|
||||
AsyncPanZoomController::CalculateResolution(const FrameMetrics& aMetrics)
|
||||
{
|
||||
gfxSize intrinsicScale = CalculateIntrinsicScale(aMetrics);
|
||||
gfxSize userZoom = aMetrics.mZoom;
|
||||
return gfxSize(intrinsicScale.width * userZoom.width,
|
||||
intrinsicScale.height * userZoom.height);
|
||||
}
|
||||
|
||||
/*static*/ gfx::Rect
|
||||
AsyncPanZoomController::CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics)
|
||||
{
|
||||
gfxSize resolution = CalculateResolution(aMetrics);
|
||||
gfx::Rect rect(aMetrics.mCompositionBounds.x,
|
||||
aMetrics.mCompositionBounds.y,
|
||||
aMetrics.mCompositionBounds.width,
|
||||
aMetrics.mCompositionBounds.height);
|
||||
rect.ScaleInverseRoundIn(resolution.width, resolution.height);
|
||||
return rect;
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetDPI(int aDPI) {
|
||||
mDPI = aDPI;
|
||||
}
|
||||
@ -916,27 +957,26 @@ void AsyncPanZoomController::RequestContentRepaint() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the resolution since we're temporarily changing it to accomodate
|
||||
// mixed resolution/zoom (normally we make them the same thing).
|
||||
float actualResolution = mFrameMetrics.mResolution.width;
|
||||
// Cache the zoom since we're temporarily changing it for
|
||||
// acceleration-scaled painting.
|
||||
gfxFloat actualZoom = mFrameMetrics.mZoom.width;
|
||||
// Calculate the factor of acceleration based on the faster of the two axes.
|
||||
float accelerationFactor =
|
||||
clamped(NS_MAX(mX.GetAccelerationFactor(), mY.GetAccelerationFactor()),
|
||||
float(MIN_ZOOM) / 2.0f, float(MAX_ZOOM));
|
||||
// Scale down the resolution a bit based on acceleration.
|
||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||
actualResolution / accelerationFactor;
|
||||
mFrameMetrics.mZoom.width = mFrameMetrics.mZoom.height =
|
||||
actualZoom / accelerationFactor;
|
||||
|
||||
// This message is compressed, so fire whether or not we already have a paint
|
||||
// queued up. We need to know whether or not a paint was requested anyways,
|
||||
// ofr the purposes of content calling window.scrollTo().
|
||||
// for the purposes of content calling window.scrollTo().
|
||||
mGeckoContentController->RequestContentRepaint(mFrameMetrics);
|
||||
mLastPaintRequestMetrics = mFrameMetrics;
|
||||
mWaitingForContentToPaint = true;
|
||||
|
||||
// Set the resolution back to what it was for the purpose of logic control.
|
||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||
actualResolution;
|
||||
// Set the zoom back to what it was for the purpose of logic control.
|
||||
mFrameMetrics.mZoom = gfxSize(actualZoom, actualZoom);
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
|
||||
@ -962,11 +1002,10 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
switch (mState) {
|
||||
case FLING:
|
||||
// If a fling is currently happening, apply it now. We can pull the updated
|
||||
// metrics afterwards.
|
||||
// If a fling is currently happening, apply it now. We can pull
|
||||
// the updated metrics afterwards.
|
||||
requestAnimationFrame |= DoFling(aSampleTime - mLastSampleTime);
|
||||
break;
|
||||
case ANIMATING_ZOOM: {
|
||||
@ -974,11 +1013,15 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
if (animPosition > 1.0) {
|
||||
animPosition = 1.0;
|
||||
}
|
||||
// Sample the zoom at the current time point. The sampled zoom
|
||||
// will affect the final computed resolution.
|
||||
double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
|
||||
|
||||
mFrameMetrics.mZoom.width = mFrameMetrics.mZoom.height =
|
||||
mEndZoomToMetrics.mZoom.width * sampledPosition +
|
||||
mStartZoomToMetrics.mZoom.width * (1 - sampledPosition);
|
||||
gfxFloat startZoom = mStartZoomToMetrics.mZoom.width;
|
||||
gfxFloat endZoom = mEndZoomToMetrics.mZoom.width;
|
||||
gfxFloat sampledZoom = (endZoom * sampledPosition +
|
||||
startZoom * (1 - sampledPosition));
|
||||
mFrameMetrics.mZoom = gfxSize(sampledZoom, sampledZoom);
|
||||
|
||||
mFrameMetrics.mScrollOffset = gfx::Point(
|
||||
mEndZoomToMetrics.mScrollOffset.x * sampledPosition +
|
||||
@ -1002,12 +1045,13 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
break;
|
||||
}
|
||||
|
||||
// Current local transform; this is not what's painted but rather what PZC has
|
||||
// transformed due to touches like panning or pinching. Eventually, the root
|
||||
// layer transform will become this during runtime, but we must wait for Gecko
|
||||
// to repaint.
|
||||
localScaleX = mFrameMetrics.mZoom.width;
|
||||
localScaleY = mFrameMetrics.mZoom.height;
|
||||
// Current local transform; this is not what's painted but rather
|
||||
// what PZC has transformed due to touches like panning or
|
||||
// pinching. Eventually, the root layer transform will become this
|
||||
// during runtime, but we must wait for Gecko to repaint.
|
||||
gfxSize localScale = CalculateResolution(mFrameMetrics);
|
||||
localScaleX = localScale.width;
|
||||
localScaleY = localScale.height;
|
||||
|
||||
if (frame.IsScrollable()) {
|
||||
metricsScrollOffset = frame.GetScrollOffsetInLayerPixels();
|
||||
@ -1073,6 +1117,16 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
}
|
||||
|
||||
mWaitingForContentToPaint = false;
|
||||
bool needContentRepaint = false;
|
||||
if (aViewportFrame.mCompositionBounds.width == mFrameMetrics.mCompositionBounds.width &&
|
||||
aViewportFrame.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
|
||||
// Remote content has sync'd up to the composition geometry
|
||||
// change, so we can accept the viewport it's calculated.
|
||||
gfxSize previousResolution = CalculateResolution(mFrameMetrics);
|
||||
mFrameMetrics.mViewport = aViewportFrame.mViewport;
|
||||
gfxSize newResolution = CalculateResolution(mFrameMetrics);
|
||||
needContentRepaint |= (previousResolution != newResolution);
|
||||
}
|
||||
|
||||
if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
|
||||
mPreviousPaintDurations.Clear();
|
||||
@ -1080,14 +1134,8 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
mX.CancelTouch();
|
||||
mY.CancelTouch();
|
||||
|
||||
// The composition bounds are not stored within the layers code, so we have
|
||||
// to reset them back to what they were every time we overwrite them.
|
||||
nsIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
|
||||
mFrameMetrics = aViewportFrame;
|
||||
mFrameMetrics.mCompositionBounds = compositionBounds;
|
||||
|
||||
// On first paint, we want to bring zoom back in sync with resolution.
|
||||
mFrameMetrics.mZoom = mFrameMetrics.mResolution;
|
||||
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||
|
||||
mState = NOTHING;
|
||||
@ -1095,6 +1143,10 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
mFrameMetrics.mScrollableRect = aViewportFrame.mScrollableRect;
|
||||
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||
}
|
||||
|
||||
if (needContentRepaint) {
|
||||
RequestContentRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
|
||||
@ -1114,11 +1166,7 @@ void AsyncPanZoomController::UpdateCompositionBounds(const nsIntRect& aCompositi
|
||||
// has gone out of view, the buffer will be cleared elsewhere anyways.
|
||||
if (aCompositionBounds.width && aCompositionBounds.height &&
|
||||
oldCompositionBounds.width && oldCompositionBounds.height) {
|
||||
// Alter the zoom such that we can see the same width of the page as we used
|
||||
// to be able to.
|
||||
SetZoomAndResolution(mFrameMetrics.mResolution.width *
|
||||
aCompositionBounds.width /
|
||||
oldCompositionBounds.width);
|
||||
SetZoomAndResolution(mFrameMetrics.mZoom.width);
|
||||
|
||||
// Repaint on a rotation so that our new resolution gets properly updated.
|
||||
RequestContentRepaint();
|
||||
@ -1143,13 +1191,15 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
||||
nsIntRect compositionBounds = mFrameMetrics.mCompositionBounds;
|
||||
gfx::Rect cssPageRect = mFrameMetrics.mScrollableRect;
|
||||
gfx::Point scrollOffset = mFrameMetrics.mScrollOffset;
|
||||
gfxSize resolution = CalculateResolution(mFrameMetrics);
|
||||
|
||||
// If the rect is empty, treat it as a request to zoom out to the full page
|
||||
// size.
|
||||
if (zoomToRect.IsEmpty()) {
|
||||
// composition bounds in CSS coordinates
|
||||
nsIntRect cssCompositionBounds = compositionBounds;
|
||||
cssCompositionBounds.ScaleInverseRoundIn(mFrameMetrics.mZoom.width);
|
||||
cssCompositionBounds.ScaleInverseRoundIn(resolution.width,
|
||||
resolution.height);
|
||||
cssCompositionBounds.MoveBy(scrollOffset.x, scrollOffset.y);
|
||||
|
||||
float y = mFrameMetrics.mScrollOffset.y;
|
||||
@ -1182,24 +1232,25 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||
}
|
||||
|
||||
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||
NS_MIN(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height);
|
||||
|
||||
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||
clamped(float(mEndZoomToMetrics.mZoom.width),
|
||||
mMinZoom,
|
||||
mMaxZoom);
|
||||
gfxFloat targetResolution =
|
||||
NS_MIN(compositionBounds.width / zoomToRect.width,
|
||||
compositionBounds.height / zoomToRect.height);
|
||||
gfxFloat targetZoom = clamped(float(targetResolution / resolution.width),
|
||||
mMinZoom, mMaxZoom);
|
||||
mEndZoomToMetrics.mZoom = gfxSize(targetZoom, targetZoom);
|
||||
|
||||
// Recalculate the zoom to rect using the new dimensions.
|
||||
zoomToRect.width = compositionBounds.width / mEndZoomToMetrics.mZoom.width;
|
||||
zoomToRect.height = compositionBounds.height / mEndZoomToMetrics.mZoom.height;
|
||||
zoomToRect.width = compositionBounds.width / targetResolution;
|
||||
zoomToRect.height = compositionBounds.height / targetResolution;
|
||||
|
||||
// Clamp the zoom to rect to the CSS rect to make sure it fits.
|
||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||
|
||||
// Do one final recalculation to get the resolution.
|
||||
mEndZoomToMetrics.mZoom.width = mEndZoomToMetrics.mZoom.height =
|
||||
NS_MAX(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height);
|
||||
targetResolution = NS_MAX(compositionBounds.width / zoomToRect.width,
|
||||
compositionBounds.height / zoomToRect.height);
|
||||
targetZoom = targetResolution / resolution.width;
|
||||
mEndZoomToMetrics.mZoom = gfxSize(targetZoom, targetZoom);
|
||||
|
||||
mStartZoomToMetrics = mFrameMetrics;
|
||||
mEndZoomToMetrics.mScrollOffset =
|
||||
@ -1256,10 +1307,10 @@ void AsyncPanZoomController::TimeoutTouchListeners() {
|
||||
ContentReceivedTouch(false);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetZoomAndResolution(float aScale) {
|
||||
void AsyncPanZoomController::SetZoomAndResolution(float aZoom) {
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||
mFrameMetrics.mZoom.width = mFrameMetrics.mZoom.height = aScale;
|
||||
mFrameMetrics.mZoom = gfxSize(aZoom, aZoom);
|
||||
mFrameMetrics.mResolution = CalculateResolution(mFrameMetrics);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,
|
||||
|
@ -209,6 +209,22 @@ public:
|
||||
const gfx::Point& aAcceleration,
|
||||
double aEstimatedPaintDuration);
|
||||
|
||||
/**
|
||||
* Return the scale factor needed to fit the viewport in |aMetrics|
|
||||
* into its compositiong bounds.
|
||||
*/
|
||||
static gfxSize CalculateIntrinsicScale(const FrameMetrics& aMetrics);
|
||||
|
||||
/**
|
||||
* Return the resolution that content should be rendered at given
|
||||
* the configuration in aFrameMetrics: viewport dimensions, zoom
|
||||
* factor, etc. (The mResolution member of aFrameMetrics is
|
||||
* ignored.)
|
||||
*/
|
||||
static gfxSize CalculateResolution(const FrameMetrics& aMetrics);
|
||||
|
||||
static gfx::Rect CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Internal handler for ReceiveInputEvent(). Does all the actual work.
|
||||
|
@ -253,14 +253,10 @@ float Axis::GetOrigin() {
|
||||
}
|
||||
|
||||
float Axis::GetCompositionLength() {
|
||||
nsIntRect compositionBounds =
|
||||
mAsyncPanZoomController->GetFrameMetrics().mCompositionBounds;
|
||||
gfx::Rect scaledCompositionBounds =
|
||||
gfx::Rect(compositionBounds.x, compositionBounds.y,
|
||||
compositionBounds.width, compositionBounds.height);
|
||||
scaledCompositionBounds.ScaleInverseRoundIn(
|
||||
mAsyncPanZoomController->GetFrameMetrics().mZoom.width);
|
||||
return GetRectLength(scaledCompositionBounds);
|
||||
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
|
||||
gfx::Rect cssCompositedRect =
|
||||
AsyncPanZoomController::CalculateCompositedRectInCssPixels(metrics);
|
||||
return GetRectLength(cssCompositedRect);
|
||||
}
|
||||
|
||||
float Axis::GetPageStart() {
|
||||
|
@ -637,6 +637,10 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
|
||||
metrics.mMayHaveTouchListeners = aMayHaveTouchListeners;
|
||||
|
||||
if (nsIWidget* widget = aForFrame->GetNearestWidget()) {
|
||||
widget->GetBounds(metrics.mCompositionBounds);
|
||||
}
|
||||
|
||||
aRoot->SetFrameMetrics(metrics);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user