Bug 856497 - Fix dynamic viewport sizing for margin changes. r=kats

The viewport wasn't being recalculated when the viewport margins changed, and
was also subject to some rounding errors. Round off the values before
comparing them (as they're screen pixels), and make sure to update the viewport
when the margins change. Margins were also not correctly being altered when
in overscroll, which could cause bottom-aligned fixed position content to be
incorrectly offset.
This commit is contained in:
Chris Lord 2013-04-08 16:35:00 +01:00
parent 2ab966de91
commit 0bd6ff9ea7
4 changed files with 60 additions and 47 deletions

View File

@ -592,6 +592,11 @@ abstract public class BrowserApp extends GeckoApp
mBrowserToolbar.updateBackButton(false);
mBrowserToolbar.updateForwardButton(false);
// Reset mToolbarHeight before setting margins so we force the
// Viewport:FixedMarginsChanged message to be sent again now that
// Gecko has loaded.
mToolbarHeight = 0;
((BrowserToolbarLayout)mBrowserToolbar.getLayout()).refreshMargins();
mDoorHangerPopup.setAnchor(mBrowserToolbar.mFavicon);

View File

@ -259,57 +259,51 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
});
}
private boolean adjustFixedLayerMarginsForOverscroll(ImmutableViewportMetrics metrics, RectF adjustedMargins) {
private void adjustFixedLayerMarginsForOverscroll(ImmutableViewportMetrics metrics, RectF adjustedMargins) {
// When the page is in overscroll, we want that to 'eat into' the fixed
// margin on that side of the viewport. This is because overscroll
// equates to extra visible area and we use the fixed margins to stop
// fixed position elements from being obscured by chrome.
// In this situation, we also want to do the opposite adjustment to the
// other end of the axis, so that when overscroll is cancelled out by
// the margin area, the opposite side isn't pushed out of the viewport.
boolean changed = false;
// When we're overscrolled, we also want to make sure that the fixed
// content on the non-overscroll side isn't obscured by the edge of the
// window, so when adjusting one side of a margin, we apply the opposite
// adjustment to the other side of the margin.
adjustedMargins.left = metrics.fixedLayerMarginLeft;
adjustedMargins.top = metrics.fixedLayerMarginTop;
adjustedMargins.right = metrics.fixedLayerMarginRight;
adjustedMargins.bottom = metrics.fixedLayerMarginBottom;
if (metrics.getPageWidth() > metrics.getWidthWithoutMargins()) {
// Adjust for left overscroll
if (metrics.viewportRectLeft < metrics.pageRectLeft && metrics.fixedLayerMarginLeft > 0) {
adjustedMargins.left = Math.max(0, metrics.fixedLayerMarginLeft
- (metrics.pageRectLeft - metrics.viewportRectLeft));
adjustedMargins.right += metrics.fixedLayerMarginLeft - adjustedMargins.left;
changed = true;
}
// The maximum margins are determined by the scrollable area of the page.
float maxMarginWidth = Math.max(0, metrics.getPageWidth() - metrics.getWidthWithoutMargins());
float maxMarginHeight = Math.max(0, metrics.getPageHeight() - metrics.getHeightWithoutMargins());
// Adjust for right overscroll
if (metrics.viewportRectRight < metrics.pageRectRight && metrics.fixedLayerMarginRight > 0) {
adjustedMargins.right = Math.max(0, metrics.fixedLayerMarginRight
- (metrics.pageRectRight - metrics.viewportRectRight));
adjustedMargins.left += metrics.fixedLayerMarginRight - adjustedMargins.right;
changed = true;
}
// Adjust for left overscroll
float leftOverscroll = metrics.pageRectLeft - metrics.viewportRectLeft;
if (leftOverscroll > 0) {
adjustedMargins.left = FloatUtils.clamp(adjustedMargins.left - leftOverscroll, 0, maxMarginWidth);
adjustedMargins.right = FloatUtils.clamp(adjustedMargins.right + leftOverscroll, 0, maxMarginWidth - adjustedMargins.left);
}
if (metrics.getPageHeight() > metrics.getHeightWithoutMargins()) {
// Adjust for top overscroll
if (metrics.viewportRectTop < metrics.pageRectTop && metrics.fixedLayerMarginTop > 0) {
adjustedMargins.top = Math.max(0, metrics.fixedLayerMarginTop
- (metrics.pageRectTop - metrics.viewportRectTop));
adjustedMargins.bottom += metrics.fixedLayerMarginTop - adjustedMargins.top;
changed = true;
}
// Adjust for bottom overscroll
if (metrics.viewportRectBottom < metrics.pageRectBottom && metrics.fixedLayerMarginBottom > 0) {
adjustedMargins.bottom = Math.max(0, metrics.fixedLayerMarginBottom
- (metrics.pageRectBottom - metrics.viewportRectBottom));
adjustedMargins.top += metrics.fixedLayerMarginBottom - adjustedMargins.bottom;
changed = true;
}
// Adjust for right overscroll
float rightOverscroll = metrics.viewportRectRight - metrics.pageRectRight;
if (rightOverscroll > 0) {
adjustedMargins.right = FloatUtils.clamp(adjustedMargins.right - rightOverscroll, 0, maxMarginWidth);
adjustedMargins.left = FloatUtils.clamp(adjustedMargins.left + rightOverscroll, 0, maxMarginWidth - adjustedMargins.right);
}
return changed;
// Adjust for top overscroll
float topOverscroll = metrics.pageRectTop - metrics.viewportRectTop;
if (topOverscroll > 0) {
adjustedMargins.top = FloatUtils.clamp(adjustedMargins.top - topOverscroll, 0, maxMarginHeight);
adjustedMargins.bottom = FloatUtils.clamp(adjustedMargins.bottom + topOverscroll, 0, maxMarginHeight - adjustedMargins.top);
}
// Adjust for bottom overscroll
float bottomOverscroll = metrics.viewportRectBottom - metrics.pageRectBottom;
if (bottomOverscroll > 0) {
adjustedMargins.bottom = FloatUtils.clamp(adjustedMargins.bottom - bottomOverscroll, 0, maxMarginHeight);
adjustedMargins.top = FloatUtils.clamp(adjustedMargins.top + bottomOverscroll, 0, maxMarginHeight - adjustedMargins.bottom);
}
}
private void adjustViewport(DisplayPortMetrics displayPort) {
@ -317,11 +311,10 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
ImmutableViewportMetrics clampedMetrics = metrics.clamp();
RectF fixedLayerMargins = new RectF();
if (adjustFixedLayerMarginsForOverscroll(metrics, fixedLayerMargins)) {
clampedMetrics = clampedMetrics.setFixedLayerMargins(
fixedLayerMargins.left, fixedLayerMargins.top,
fixedLayerMargins.right, fixedLayerMargins.bottom);
}
adjustFixedLayerMarginsForOverscroll(metrics, fixedLayerMargins);
clampedMetrics = clampedMetrics.setFixedLayerMargins(
fixedLayerMargins.left, fixedLayerMargins.top,
fixedLayerMargins.right, fixedLayerMargins.bottom);
if (displayPort == null) {
displayPort = DisplayPortCalculator.calculate(metrics, mPanZoomController.getVelocityVector());

View File

@ -7,6 +7,8 @@ package org.mozilla.gecko.util;
import android.graphics.PointF;
import java.lang.IllegalArgumentException;
public final class FloatUtils {
private FloatUtils() {}
@ -26,4 +28,16 @@ public final class FloatUtils {
public static float interpolate(float from, float to, float t) {
return from + (to - from) * t;
}
/**
* Returns 'value', clamped so that it isn't any lower than 'low', and it
* isn't any higher than 'high'.
*/
public static float clamp(float value, float low, float high) {
if (high < low) {
throw new IllegalArgumentException(
"clamp called with invalid parameters (" + high + " < " + low + ")" );
}
return Math.max(low, Math.min(high, value));
}
}

View File

@ -1311,6 +1311,7 @@ var BrowserApp = {
case "Viewport:FixedMarginsChanged":
gViewportMargins = JSON.parse(aData);
this.selectedTab.updateViewportSize(gScreenWidth);
break;
case "nsPref:changed":
@ -2952,13 +2953,13 @@ Tab.prototype = {
// within the screen size, so remeasure when the page size remains within
// the threshold of screen + margins, in case it's sizing itself relative
// to the viewport.
if (!this.updatingViewportForPageSizeChange) {
if (!this.updatingViewportForPageSizeChange && aPageSizeUpdate) {
this.updatingViewportForPageSizeChange = true;
if (((viewport.pageBottom - viewport.pageTop
< gScreenHeight + gViewportMargins.top + gViewportMargins.bottom)
if (((Math.round(viewport.pageBottom - viewport.pageTop)
<= gScreenHeight + gViewportMargins.top + gViewportMargins.bottom)
!= this.viewportExcludesVerticalMargins) ||
((viewport.pageRight - viewport.pageLeft
< gScreenWidth + gViewportMargins.left + gViewportMargins.right)
((Math.round(viewport.pageRight - viewport.pageLeft)
<= gScreenWidth + gViewportMargins.left + gViewportMargins.right)
!= this.viewportExcludesHorizontalMargins)) {
this.updateViewportSize(gScreenWidth);
}