Bug 824920 - Fix zoom ratio and check the zoom offset to prevent over-scroll. r=drs

This commit is contained in:
Benjamin Chen 2013-03-11 18:02:13 +08:00
Родитель 613657d2a5
Коммит 97e11e07df
1 изменённых файлов: 66 добавлений и 59 удалений

Просмотреть файл

@ -1348,72 +1348,79 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
gfx::Rect cssPageRect = mFrameMetrics.mScrollableRect; gfx::Rect cssPageRect = mFrameMetrics.mScrollableRect;
gfx::Point scrollOffset = mFrameMetrics.mScrollOffset; gfx::Point scrollOffset = mFrameMetrics.mScrollOffset;
gfxSize resolution = CalculateResolution(mFrameMetrics); gfxSize resolution = CalculateResolution(mFrameMetrics);
gfxSize currentZoom = mFrameMetrics.mZoom;
float targetZoom;
gfxFloat targetResolution;
// If the rect is empty, treat it as a request to zoom out to the full page // The minimum zoom to prevent over-zoom-out.
// size. // If the zoom factor is lower than this (i.e. we are zoomed more into the page),
if (zoomToRect.IsEmpty()) { // then the CSS content rect, in layers pixels, will be smaller than the
// composition bounds in CSS coordinates // composition bounds. If this happens, we can't fill the target composited
nsIntRect cssCompositionBounds = compositionBounds; // area with this frame.
cssCompositionBounds.ScaleInverseRoundIn(resolution.width, float localMinZoom;
resolution.height); gfx::Rect compositedRect = CalculateCompositedRectInCssPixels(mFrameMetrics);
cssCompositionBounds.MoveBy(scrollOffset.x, scrollOffset.y); localMinZoom =
std::max(currentZoom.width / (cssPageRect.width / compositedRect.width),
float y = mFrameMetrics.mScrollOffset.y; currentZoom.height / (cssPageRect.height / compositedRect.height));
float newHeight = localMinZoom = std::max(localMinZoom, mMinZoom);
cssCompositionBounds.height * cssPageRect.width / cssCompositionBounds.width;
float dh = cssCompositionBounds.height - newHeight;
zoomToRect = gfx::Rect(0.0f,
y + dh/2,
cssPageRect.width,
y + dh/2 + newHeight);
}
gfxFloat targetResolution =
std::min(compositionBounds.width / zoomToRect.width,
compositionBounds.height / zoomToRect.height);
// Recalculate the zoom to rect using the new dimensions.
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.
targetResolution = std::max(compositionBounds.width / zoomToRect.width,
compositionBounds.height / zoomToRect.height);
float targetZoom = float(targetResolution / resolution.width) * mFrameMetrics.mZoom.width;
// If current zoom is equal to mMaxZoom,
// user still double-tapping it, just zoom-out to the full page size
if (mFrameMetrics.mZoom.width == mMaxZoom && targetZoom >= mMaxZoom) {
nsIntRect cssCompositionBounds = compositionBounds;
cssCompositionBounds.ScaleInverseRoundIn(resolution.width,
resolution.height);
cssCompositionBounds.MoveBy(scrollOffset.x, scrollOffset.y);
float y = mFrameMetrics.mScrollOffset.y;
float newHeight =
cssCompositionBounds.height * cssPageRect.width / cssCompositionBounds.width;
float dh = cssCompositionBounds.height - newHeight;
zoomToRect = gfx::Rect(0.0f,
y + dh/2,
cssPageRect.width,
y + dh/2 + newHeight);
if (!zoomToRect.IsEmpty()) {
// Intersect the zoom-to-rect to the CSS rect to make sure it fits.
zoomToRect = zoomToRect.Intersect(cssPageRect); zoomToRect = zoomToRect.Intersect(cssPageRect);
// assign 1 to targetZoom is a shortcut targetResolution =
targetZoom = 1; std::min(compositionBounds.width / zoomToRect.width,
compositionBounds.height / zoomToRect.height);
targetZoom = float(targetResolution / resolution.width) * currentZoom.width;
}
// 1. If the rect is empty, request received from browserElementScrolling.js
// 2. currentZoom is equal to mMaxZoom and user still double-tapping it
// 3. currentZoom is equal to localMinZoom and user still double-tapping it
// Treat these three cases as a request to zoom out as much as possible.
if (zoomToRect.IsEmpty() ||
(currentZoom.width == mMaxZoom && targetZoom >= mMaxZoom) ||
(currentZoom.width == localMinZoom && targetZoom <= localMinZoom)) {
nsIntRect cssCompositionBounds = compositionBounds;
cssCompositionBounds.ScaleInverseRoundIn(resolution.width,
resolution.height);
float y = scrollOffset.y;
float newHeight =
cssCompositionBounds.height * cssPageRect.width / cssCompositionBounds.width;
float dh = cssCompositionBounds.height - newHeight;
zoomToRect = gfx::Rect(0.0f,
y + dh/2,
cssPageRect.width,
newHeight);
zoomToRect = zoomToRect.Intersect(cssPageRect);
targetResolution =
std::min(compositionBounds.width / zoomToRect.width,
compositionBounds.height / zoomToRect.height);
targetZoom = float(targetResolution / resolution.width) * currentZoom.width;
} }
gfxFloat targetFinalZoom = clamped(targetZoom, mMinZoom, mMaxZoom); targetZoom = clamped(targetZoom, localMinZoom, mMaxZoom);
mEndZoomToMetrics.mZoom = gfxSize(targetFinalZoom, targetFinalZoom); mEndZoomToMetrics.mZoom = gfxSize(targetZoom, targetZoom);
// Adjust the zoomToRect to a sensible position to prevent overscrolling.
FrameMetrics metricsAfterZoom = mFrameMetrics;
metricsAfterZoom.mZoom = mEndZoomToMetrics.mZoom;
gfx::Rect rectAfterZoom
= CalculateCompositedRectInCssPixels(metricsAfterZoom);
// If either of these conditions are met, the page will be
// overscrolled after zoomed
if (zoomToRect.y + rectAfterZoom.height > cssPageRect.height) {
zoomToRect.y = cssPageRect.height - rectAfterZoom.height;
zoomToRect.y = zoomToRect.y > 0 ? zoomToRect.y : 0;
}
if (zoomToRect.x + rectAfterZoom.width > cssPageRect.width) {
zoomToRect.x = cssPageRect.width - rectAfterZoom.width;
zoomToRect.x = zoomToRect.x > 0 ? zoomToRect.x : 0;
}
mStartZoomToMetrics = mFrameMetrics; mStartZoomToMetrics = mFrameMetrics;
mEndZoomToMetrics.mScrollOffset = mEndZoomToMetrics.mScrollOffset = gfx::Point(zoomToRect.x, zoomToRect.y);
gfx::Point(zoomToRect.x, zoomToRect.y);
mAnimationStartTime = TimeStamp::Now(); mAnimationStartTime = TimeStamp::Now();