diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index 5e39d7b69ab..68215e42e01 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -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); diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java index cd0ef0b565a..b9f9aed7da2 100644 --- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -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()); diff --git a/mobile/android/base/util/FloatUtils.java b/mobile/android/base/util/FloatUtils.java index 804f25b2bc4..fbcd7254f62 100644 --- a/mobile/android/base/util/FloatUtils.java +++ b/mobile/android/base/util/FloatUtils.java @@ -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)); + } } diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 3f102bc7908..da5111fd435 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -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); }