diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-09-23 19:12:41 +0200 |
---|---|---|
committer | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-09-24 20:43:02 +0200 |
commit | cc2f2afd7e2fd3d34ccdcba2a3d25887bd9d5197 (patch) | |
tree | 219eedc36ba4982de2aba4443a6e1172336252e3 /android | |
parent | b85c779595d679a3d24de37751b27fe70e878149 (diff) |
android: add DisplayPortCalculator and DisplayPortMetrics
Change-Id: I1418023011cf0ef3611e3fda6f313d9fcb9ccea7
Diffstat (limited to 'android')
4 files changed, 157 insertions, 67 deletions
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DisplayPortCalculator.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DisplayPortCalculator.java new file mode 100644 index 000000000000..4895858ea198 --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DisplayPortCalculator.java @@ -0,0 +1,101 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.gfx; + +import android.graphics.RectF; +import org.mozilla.gecko.util.FloatUtils; + +final class DisplayPortCalculator { + private static final String LOGTAG = "GeckoDisplayPortCalculator"; + + private static final int DEFAULT_DISPLAY_PORT_MARGIN = 300; + + /* If the visible rect is within the danger zone (measured in pixels from each edge of a tile), + * we start aggressively redrawing to minimize checkerboarding. */ + private static final int DANGER_ZONE_X = 75; + private static final int DANGER_ZONE_Y = 150; + + static DisplayPortMetrics calculate(ImmutableViewportMetrics metrics) { + float desiredXMargins = 2 * DEFAULT_DISPLAY_PORT_MARGIN; + float desiredYMargins = 2 * DEFAULT_DISPLAY_PORT_MARGIN; + + // we need to avoid having a display port that is larger than the page, or we will end up + // painting things outside the page bounds (bug 729169). we simultaneously need to make + // the display port as large as possible so that we redraw less. + + // figure out how much of the desired buffer amount we can actually use on the horizontal axis + float xBufferAmount = Math.min(desiredXMargins, metrics.pageSizeWidth - metrics.getWidth()); + // if we reduced the buffer amount on the horizontal axis, we should take that saved memory and + // use it on the vertical axis + float savedPixels = (desiredXMargins - xBufferAmount) * (metrics.getHeight() + desiredYMargins); + float extraYAmount = (float)Math.floor(savedPixels / (metrics.getWidth() + xBufferAmount)); + float yBufferAmount = Math.min(desiredYMargins + extraYAmount, metrics.pageSizeHeight - metrics.getHeight()); + // and the reverse - if we shrunk the buffer on the vertical axis we can add it to the horizontal + if (xBufferAmount == desiredXMargins && yBufferAmount < desiredYMargins) { + savedPixels = (desiredYMargins - yBufferAmount) * (metrics.getWidth() + xBufferAmount); + float extraXAmount = (float)Math.floor(savedPixels / (metrics.getHeight() + yBufferAmount)); + xBufferAmount = Math.min(xBufferAmount + extraXAmount, metrics.pageSizeWidth - metrics.getWidth()); + } + + // and now calculate the display port margins based on how much buffer we've decided to use and + // the page bounds, ensuring we use all of the available buffer amounts on one side or the other + // on any given axis. (i.e. if we're scrolled to the top of the page, the vertical buffer is + // entirely below the visible viewport, but if we're halfway down the page, the vertical buffer + // is split). + float leftMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.viewportRectLeft); + float rightMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.pageSizeWidth - (metrics.viewportRectLeft + metrics.getWidth())); + if (leftMargin < DEFAULT_DISPLAY_PORT_MARGIN) { + rightMargin = xBufferAmount - leftMargin; + } else if (rightMargin < DEFAULT_DISPLAY_PORT_MARGIN) { + leftMargin = xBufferAmount - rightMargin; + } else if (!FloatUtils.fuzzyEquals(leftMargin + rightMargin, xBufferAmount)) { + float delta = xBufferAmount - leftMargin - rightMargin; + leftMargin += delta / 2; + rightMargin += delta / 2; + } + + float topMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.viewportRectTop); + float bottomMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.pageSizeHeight - (metrics.viewportRectTop + metrics.getHeight())); + if (topMargin < DEFAULT_DISPLAY_PORT_MARGIN) { + bottomMargin = yBufferAmount - topMargin; + } else if (bottomMargin < DEFAULT_DISPLAY_PORT_MARGIN) { + topMargin = yBufferAmount - bottomMargin; + } else if (!FloatUtils.fuzzyEquals(topMargin + bottomMargin, yBufferAmount)) { + float delta = yBufferAmount - topMargin - bottomMargin; + topMargin += delta / 2; + bottomMargin += delta / 2; + } + + // note that unless the viewport size changes, or the page dimensions change (either because of + // content changes or zooming), the size of the display port should remain constant. this + // is intentional to avoid re-creating textures and all sorts of other reallocations in the + // draw and composition code. + return new DisplayPortMetrics(metrics.viewportRectLeft - leftMargin, + metrics.viewportRectTop - topMargin, + metrics.viewportRectRight + rightMargin, + metrics.viewportRectBottom + bottomMargin, + metrics.zoomFactor); + } + + // Returns true if a checkerboard is about to be visible. + static boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, DisplayPortMetrics displayPort) { + if (displayPort == null) { + return true; + } + + // Increase the size of the viewport (and clamp to page boundaries), and + // intersect it with the tile's displayport to determine whether we're + // close to checkerboarding. + FloatSize pageSize = metrics.getPageSize(); + RectF adjustedViewport = RectUtils.expand(metrics.getViewport(), DANGER_ZONE_X, DANGER_ZONE_Y); + if (adjustedViewport.top < 0) adjustedViewport.top = 0; + if (adjustedViewport.left < 0) adjustedViewport.left = 0; + if (adjustedViewport.right > pageSize.width) adjustedViewport.right = pageSize.width; + if (adjustedViewport.bottom > pageSize.height) adjustedViewport.bottom = pageSize.height; + + return !displayPort.contains(adjustedViewport); + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DisplayPortMetrics.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DisplayPortMetrics.java new file mode 100644 index 000000000000..c657deacfc4b --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DisplayPortMetrics.java @@ -0,0 +1,51 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.gfx; + +import android.graphics.RectF; + +/* + * This class keeps track of the area we request Gecko to paint, as well + * as the resolution of the paint. The area may be different from the visible + * area of the page, and the resolution may be different from the resolution + * used in the compositor to render the page. This is so that we can ask Gecko + * to paint a much larger area without using extra memory, and then render some + * subsection of that with compositor scaling. + */ +public final class DisplayPortMetrics { + private final RectF mPosition; + private final float mResolution; + + public DisplayPortMetrics() { + this(0, 0, 0, 0, 1); + } + + public DisplayPortMetrics(float left, float top, float right, float bottom, float resolution) { + mPosition = new RectF(left, top, right, bottom); + mResolution = resolution; + } + + public boolean contains(RectF rect) { + return mPosition.contains(rect); + } + + public String toJSON() { + StringBuffer sb = new StringBuffer(256); + sb.append("{ \"left\": ").append(mPosition.left) + .append(", \"top\": ").append(mPosition.top) + .append(", \"right\": ").append(mPosition.right) + .append(", \"bottom\": ").append(mPosition.bottom) + .append(", \"resolution\": ").append(mResolution) + .append('}'); + return sb.toString(); + } + + public String toString() { + return "DisplayPortMetrics(" + mPosition.left + "," + + mPosition.top + "," + mPosition.right + "," + + mPosition.bottom + "," + mResolution + ")"; + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java index e7a9059a953b..06613a4739de 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java @@ -54,13 +54,12 @@ import java.util.List; public class GeckoLayerClient { private static final String LOGTAG = "GeckoLayerClient"; - private static final int DEFAULT_DISPLAY_PORT_MARGIN = 300; private static final long MIN_VIEWPORT_CHANGE_DELAY = 25L; private static final IntSize TILE_SIZE = new IntSize(256, 256); protected IntSize mScreenSize; - private RectF mDisplayPort; + private DisplayPortMetrics mDisplayPort; protected Layer mTileLayer; /* The viewport that Gecko is currently displaying. */ protected ViewportMetrics mGeckoViewport; @@ -82,7 +81,7 @@ public class GeckoLayerClient { public GeckoLayerClient(Context context) { mContext = context; mScreenSize = new IntSize(0, 0); - mDisplayPort = new RectF(); + mDisplayPort = new DisplayPortMetrics(); } protected void setupLayer() { @@ -136,7 +135,7 @@ public class GeckoLayerClient { Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - endDrawing"); } - RectF getDisplayPort() { + DisplayPortMetrics getDisplayPort() { return mDisplayPort; } @@ -221,74 +220,13 @@ public class GeckoLayerClient { mViewportSizeChanged = true; } - private static RectF calculateDisplayPort(ImmutableViewportMetrics metrics) { - float desiredXMargins = 2 * DEFAULT_DISPLAY_PORT_MARGIN; - float desiredYMargins = 2 * DEFAULT_DISPLAY_PORT_MARGIN; - - // we need to avoid having a display port that is larger than the page, or we will end up - // painting things outside the page bounds (bug 729169). we simultaneously need to make - // the display port as large as possible so that we redraw less. - - // figure out how much of the desired buffer amount we can actually use on the horizontal axis - float xBufferAmount = Math.min(desiredXMargins, metrics.pageSizeWidth - metrics.getWidth()); - // if we reduced the buffer amount on the horizontal axis, we should take that saved memory and - // use it on the vertical axis - float savedPixels = (desiredXMargins - xBufferAmount) * (metrics.getHeight() + desiredYMargins); - float extraYAmount = (float)Math.floor(savedPixels / (metrics.getWidth() + xBufferAmount)); - float yBufferAmount = Math.min(desiredYMargins + extraYAmount, metrics.pageSizeHeight - metrics.getHeight()); - // and the reverse - if we shrunk the buffer on the vertical axis we can add it to the horizontal - if (xBufferAmount == desiredXMargins && yBufferAmount < desiredYMargins) { - savedPixels = (desiredYMargins - yBufferAmount) * (metrics.getWidth() + xBufferAmount); - float extraXAmount = (float)Math.floor(savedPixels / (metrics.getHeight() + yBufferAmount)); - xBufferAmount = Math.min(xBufferAmount + extraXAmount, metrics.pageSizeWidth - metrics.getWidth()); - } - - // and now calculate the display port margins based on how much buffer we've decided to use and - // the page bounds, ensuring we use all of the available buffer amounts on one side or the other - // on any given axis. (i.e. if we're scrolled to the top of the page, the vertical buffer is - // entirely below the visible viewport, but if we're halfway down the page, the vertical buffer - // is split). - float leftMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.viewportRectLeft); - float rightMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.pageSizeWidth - (metrics.viewportRectLeft + metrics.getWidth())); - if (leftMargin < DEFAULT_DISPLAY_PORT_MARGIN) { - rightMargin = xBufferAmount - leftMargin; - } else if (rightMargin < DEFAULT_DISPLAY_PORT_MARGIN) { - leftMargin = xBufferAmount - rightMargin; - } else if (!FloatUtils.fuzzyEquals(leftMargin + rightMargin, xBufferAmount)) { - float delta = xBufferAmount - leftMargin - rightMargin; - leftMargin += delta / 2; - rightMargin += delta / 2; - } - - float topMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.viewportRectTop); - float bottomMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, metrics.pageSizeHeight - (metrics.viewportRectTop + metrics.getHeight())); - if (topMargin < DEFAULT_DISPLAY_PORT_MARGIN) { - bottomMargin = yBufferAmount - topMargin; - } else if (bottomMargin < DEFAULT_DISPLAY_PORT_MARGIN) { - topMargin = yBufferAmount - bottomMargin; - } else if (!FloatUtils.fuzzyEquals(topMargin + bottomMargin, yBufferAmount)) { - float delta = yBufferAmount - topMargin - bottomMargin; - topMargin += delta / 2; - bottomMargin += delta / 2; - } - - // note that unless the viewport size changes, or the page dimensions change (either because of - // content changes or zooming), the size of the display port should remain constant. this - // is intentional to avoid re-creating textures and all sorts of other reallocations in the - // draw and composition code. - return new RectF(metrics.viewportRectLeft - leftMargin, - metrics.viewportRectTop - topMargin, - metrics.viewportRectRight + rightMargin, - metrics.viewportRectBottom + bottomMargin); - } - private void adjustViewport() { ViewportMetrics viewportMetrics = new ViewportMetrics(mLayerController.getViewportMetrics()); viewportMetrics.setViewport(viewportMetrics.getClampedViewport()); - mDisplayPort = calculateDisplayPort(mLayerController.getViewportMetrics()); + mDisplayPort = DisplayPortCalculator.calculate(mLayerController.getViewportMetrics()); LOKitShell.sendEvent(LOEvent.viewport(viewportMetrics)); if (mViewportSizeChanged) { diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java index b9d80d9de7e3..461b53cde760 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java @@ -358,7 +358,7 @@ public class LayerController { if (adjustedViewport.right > pageSize.width) adjustedViewport.right = pageSize.width; if (adjustedViewport.bottom > pageSize.height) adjustedViewport.bottom = pageSize.height; - RectF displayPort = (mLayerClient == null ? new RectF() : mLayerClient.getDisplayPort()); + DisplayPortMetrics displayPort = (mLayerClient == null ? new DisplayPortMetrics() : mLayerClient.getDisplayPort()); return !displayPort.contains(adjustedViewport); } |