Bug 732564 - Move the display port trimming to Java so that we always have a copy of the display port being used. r=Cwiiis

This commit is contained in:
Kartikaya Gupta 2012-03-12 12:03:38 -04:00
parent f247ed9193
commit aae04c16b7
5 changed files with 108 additions and 101 deletions

View File

@ -381,7 +381,7 @@ public class GeckoEvent {
return event;
}
public static GeckoEvent createViewportEvent(ViewportMetrics viewport, Rect displayPortMargins) {
public static GeckoEvent createViewportEvent(ViewportMetrics viewport, RectF displayPort) {
GeckoEvent event = new GeckoEvent(VIEWPORT);
event.mCharacters = "Viewport:Change";
PointF origin = viewport.getOrigin();
@ -389,7 +389,7 @@ public class GeckoEvent {
sb.append("{ \"x\" : ").append(origin.x)
.append(", \"y\" : ").append(origin.y)
.append(", \"zoom\" : ").append(viewport.getZoomFactor())
.append(", \"displayPortMargins\" :").append(RectUtils.toJSON(displayPortMargins))
.append(", \"displayPort\" :").append(RectUtils.toJSON(displayPort))
.append('}');
event.mCharactersExtra = sb.toString();
return event;

View File

@ -69,7 +69,7 @@ public class GeckoLayerClient implements GeckoEventResponder,
private IntSize mScreenSize;
private IntSize mWindowSize;
private IntSize mBufferSize;
private Rect mDisplayPortMargins;
private RectF mDisplayPort;
private VirtualLayer mRootLayer;
@ -87,14 +87,11 @@ public class GeckoLayerClient implements GeckoEventResponder,
private ViewTransform mCurrentViewTransform;
public GeckoLayerClient(Context context) {
// we can fill these in with dummy values because they are always written
// to before being read
mScreenSize = new IntSize(0, 0);
mBufferSize = new IntSize(0, 0);
mDisplayPortMargins = new Rect(DEFAULT_DISPLAY_PORT_MARGIN,
DEFAULT_DISPLAY_PORT_MARGIN,
DEFAULT_DISPLAY_PORT_MARGIN,
DEFAULT_DISPLAY_PORT_MARGIN);
// we can fill this in with dummy values because it is always written
// to before being read
mDisplayPort = new RectF();
mCurrentViewTransform = new ViewTransform(0, 0, 1);
}
@ -155,12 +152,7 @@ public class GeckoLayerClient implements GeckoEventResponder,
}
RectF getDisplayPort() {
RectF displayPort = new RectF(mRootLayer.getPosition());
displayPort.left -= mDisplayPortMargins.left;
displayPort.top -= mDisplayPortMargins.top;
displayPort.right += mDisplayPortMargins.right;
displayPort.bottom += mDisplayPortMargins.bottom;
return displayPort;
return mDisplayPort;
}
/* Informs Gecko that the screen size has changed. */
@ -221,13 +213,78 @@ public class GeckoLayerClient implements GeckoEventResponder,
mViewportSizeChanged = true;
}
private void updateDisplayPort() {
float desiredXMargins = 2 * DEFAULT_DISPLAY_PORT_MARGIN;
float desiredYMargins = 2 * DEFAULT_DISPLAY_PORT_MARGIN;
ImmutableViewportMetrics metrics = mLayerController.getViewportMetrics();
// 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, Math.max(0, 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, Math.max(0, 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, Math.max(0, 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, Math.max(0, metrics.viewportRectLeft));
float rightMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, Math.max(0, 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, Math.max(0, metrics.viewportRectTop));
float bottomMargin = Math.min(DEFAULT_DISPLAY_PORT_MARGIN, Math.max(0, 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.
mDisplayPort.left = metrics.viewportRectLeft - leftMargin;
mDisplayPort.top = metrics.viewportRectTop - topMargin;
mDisplayPort.right = metrics.viewportRectRight + rightMargin;
mDisplayPort.bottom = metrics.viewportRectBottom + bottomMargin;
}
private void adjustViewport() {
ViewportMetrics viewportMetrics =
new ViewportMetrics(mLayerController.getViewportMetrics());
viewportMetrics.setViewport(viewportMetrics.getClampedViewport());
GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(viewportMetrics, mDisplayPortMargins));
updateDisplayPort();
GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(viewportMetrics, mDisplayPort));
if (mViewportSizeChanged) {
mViewportSizeChanged = false;
GeckoAppShell.viewSizeChanged();
@ -254,11 +311,12 @@ public class GeckoLayerClient implements GeckoEventResponder,
/** Implementation of GeckoEventResponder. */
public String getResponse() {
// We are responding to the events handled in handleMessage() above with
// the display port margins we want. Note that all messages we are currently
// handling (Viewport:Update) require this response, so we can just return
// this indiscriminately.
return RectUtils.toJSON(mDisplayPortMargins);
// We are responding to the events handled in handleMessage() above with the
// display port we want. Note that all messages we are currently handling
// (just Viewport:Update) require this response, so we can just return this
// indiscriminately.
updateDisplayPort();
return RectUtils.toJSON(mDisplayPort);
}
void geometryChanged() {

View File

@ -41,6 +41,14 @@ public class ImmutableViewportMetrics {
allowZoom = m.getAllowZoom();
}
public float getWidth() {
return viewportRectRight - viewportRectLeft;
}
public float getHeight() {
return viewportRectBottom - viewportRectTop;
}
// some helpers to make ImmutableViewportMetrics act more like ViewportMetrics
public PointF getOrigin() {

View File

@ -58,7 +58,7 @@ public final class RectUtils {
}
}
public static String toJSON(Rect rect) {
public static String toJSON(RectF rect) {
StringBuffer sb = new StringBuffer(256);
sb.append("{ \"left\": ").append(rect.left)
.append(", \"top\": ").append(rect.top)

View File

@ -1589,94 +1589,35 @@ Tab.prototype = {
}
},
refreshDisplayPort: function(aDisplayPortMargins) {
if (this._zoom <= 0)
return;
if (!this.browser.contentDocument.documentElement)
setDisplayPort: function(aViewportX, aViewportY, aDisplayPortRect) {
let zoom = this._zoom;
if (zoom <= 0)
return;
let viewport = this.getViewport();
let element = this.browser.contentDocument.documentElement;
if (!element)
return;
// 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)
let requestedXAmount = Math.max(0, aDisplayPortMargins.left + aDisplayPortMargins.right);
let requestedYAmount = Math.max(0, aDisplayPortMargins.top + aDisplayPortMargins.bottom);
// figure out how much of the specified buffer amount we can actually use on the horizontal axis
let xBufferAmount = Math.min(requestedXAmount, Math.max(0, viewport.pageWidth - viewport.width));
// if we reduced the buffer amount on the horizontal axis, we should take that saved memory and
// use it on the vertical axis
let savedPixels = (requestedXAmount - xBufferAmount) * (viewport.height + requestedYAmount);
let extraYAmount = Math.floor(savedPixels / (viewport.width + xBufferAmount));
let yBufferAmount = Math.min(requestedYAmount + extraYAmount, Math.max(0, viewport.pageHeight - viewport.height));
// and the reverse - if we shrunk the buffer on the vertical axis we can add it to the horizontal
if (xBufferAmount == requestedXAmount && yBufferAmount < requestedYAmount) {
savedPixels = (requestedYAmount - yBufferAmount) * (viewport.width + xBufferAmount);
let extraXAmount = Math.floor(savedPixels / (viewport.height + yBufferAmount));
xBufferAmount = Math.min(xBufferAmount + extraXAmount, Math.max(0, viewport.pageWidth - viewport.width));
}
// 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 as specified in the aDisplayPortMargins parameter).
let leftMargin = Math.min(aDisplayPortMargins.left, Math.max(0, viewport.x));
let rightMargin = Math.min(aDisplayPortMargins.right, Math.max(0, viewport.pageWidth - (viewport.x + viewport.width)));
if (leftMargin < aDisplayPortMargins.left) {
rightMargin = xBufferAmount - leftMargin;
} else if (rightMargin < aDisplayPortMargins.right) {
leftMargin = xBufferAmount - rightMargin;
} else if (Math.abs(leftMargin + rightMargin - xBufferAmount) >= 1e-6) {
let delta = xBufferAmount - leftMargin - rightMargin;
leftMargin += delta / 2;
rightMargin += delta / 2;
}
let topMargin = Math.min(aDisplayPortMargins.top, Math.max(0, viewport.y));
let bottomMargin = Math.min(aDisplayPortMargins.bottom, Math.max(0, viewport.pageHeight - (viewport.y + viewport.height)));
if (topMargin < aDisplayPortMargins.top) {
bottomMargin = yBufferAmount - topMargin;
} else if (bottomMargin < aDisplayPortMargins.bottom) {
topMargin = yBufferAmount - bottomMargin;
} else if (Math.abs(topMargin + bottomMargin - yBufferAmount) >= 1e-6) {
let delta = yBufferAmount - topMargin - bottomMargin;
topMargin += delta / 2;
bottomMargin += delta / 2;
}
dump("### displayport margins=(" + leftMargin + ", " + topMargin + ", " + rightMargin + ", " + bottomMargin + ") at zoom=" + viewport.zoom
+ " and buffer amounts=(" + xBufferAmount + ", " + yBufferAmount + ")");
// 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.
let cwu = window.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
cwu.setDisplayPortForElement(-leftMargin / viewport.zoom,
-topMargin / viewport.zoom,
(leftMargin + viewport.width + rightMargin) / viewport.zoom,
(topMargin + viewport.height + bottomMargin) / viewport.zoom,
this.browser.contentDocument.documentElement);
let cwu = window.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
cwu.setDisplayPortForElement((aDisplayPortRect.left - aViewportX) / zoom,
(aDisplayPortRect.top - aViewportY) / zoom,
(aDisplayPortRect.right - aDisplayPortRect.left) / zoom,
(aDisplayPortRect.bottom - aDisplayPortRect.top) / zoom,
element);
},
setViewport: function(aViewport) {
// Transform coordinates based on zoom
aViewport.x /= aViewport.zoom;
aViewport.y /= aViewport.zoom;
let x = aViewport.x / aViewport.zoom;
let y = aViewport.y / aViewport.zoom;
// Set scroll position
let win = this.browser.contentWindow;
win.scrollTo(aViewport.x, aViewport.y);
win.scrollTo(x, y);
this.userScrollPos.x = win.scrollX;
this.userScrollPos.y = win.scrollY;
this.setResolution(aViewport.zoom, false);
// always refresh display port when we scroll so that we can clip it to page bounds
this.refreshDisplayPort(aViewport.displayPortMargins);
this.setDisplayPort(aViewport.x, aViewport.y, aViewport.displayPort);
},
setResolution: function(aZoom, aForce) {
@ -1752,9 +1693,9 @@ Tab.prototype = {
return;
let message = this.getViewport();
message.type = "Viewport:Update";
let displayPortMargins = sendMessageToJava({ gecko: message });
if (displayPortMargins != null)
this.refreshDisplayPort(JSON.parse(displayPortMargins));
let displayPort = sendMessageToJava({ gecko: message });
if (displayPort != null)
this.setDisplayPort(message.x, message.y, JSON.parse(displayPort));
},
handleEvent: function(aEvent) {
@ -2017,7 +1958,7 @@ Tab.prototype = {
// XXX This code assumes that this is the earliest hook we have at which
// browser.contentDocument is changed to the new document we're loading
this.contentDocumentIsDisplayed = false;
this.refreshDisplayPort({left: 0, top: 0, right: 0, bottom: 0 });
this.setDisplayPort(0, 0, {left: 0, top: 0, right: gScreenWidth, bottom: gScreenHeight });
} else {
this.sendViewportUpdate();
}