Bug 736729 - Fix display-port on first paint and page-size changes. r=kats

Previously, we only set the display-port in response to a page scrolling itself,
or when we adjust the viewport. This meant that the display-port could be
incorrect if a viewport adjustment was sent after a page-size changed, but
before a render had completed.

Similarly, we were not updating the display-port when the viewport of a
foreground document that hadn't been displayed yet was changing. This would
cause the first-paint to have an incorrect (and often too small) display port,
which wouldn't be corrected until the page was scrolled.
This commit is contained in:
Chris Lord 2012-03-21 14:44:33 +00:00
parent 7fbfb4bae3
commit ebc07011a5
2 changed files with 72 additions and 28 deletions

View File

@ -109,6 +109,7 @@ public class GeckoLayerClient implements GeckoEventResponder,
mLayerRenderer = new LayerRenderer(view);
GeckoAppShell.registerGeckoEventListener("Viewport:Update", this);
GeckoAppShell.registerGeckoEventListener("Viewport:PageSize", this);
GeckoAppShell.registerGeckoEventListener("Viewport:CalculateDisplayPort", this);
GeckoAppShell.registerGeckoEventListener("Checkerboard:Toggle", this);
@ -242,25 +243,55 @@ public class GeckoLayerClient implements GeckoEventResponder,
mGeckoViewport = viewportMetrics;
}
/**
* The different types of Viewport messages handled. All viewport events
* expect a display-port to be returned, but can handle one not being
* returned.
*/
private enum ViewportMessageType {
UPDATE, // The viewport has changed and should be entirely updated
PAGE_SIZE // The viewport's page-size has changed
}
/** Viewport message handler. */
private void handleViewportMessage(JSONObject message, ViewportMessageType type) throws JSONException {
ViewportMetrics messageMetrics = new ViewportMetrics(message);
synchronized (mLayerController) {
final ViewportMetrics newMetrics;
ImmutableViewportMetrics oldMetrics = mLayerController.getViewportMetrics();
switch (type) {
default:
case UPDATE:
newMetrics = messageMetrics;
// Keep the old viewport size
newMetrics.setSize(oldMetrics.getSize());
mLayerController.abortPanZoomAnimation();
break;
case PAGE_SIZE:
newMetrics = new ViewportMetrics(oldMetrics);
newMetrics.setPageSize(messageMetrics.getPageSize());
break;
}
mLayerController.post(new Runnable() {
public void run() {
mGeckoViewport = newMetrics;
}
});
mLayerController.setViewportMetrics(newMetrics);
mDisplayPort = calculateDisplayPort(mLayerController.getViewportMetrics());
}
mReturnDisplayPort = mDisplayPort;
}
/** Implementation of GeckoEventResponder/GeckoEventListener. */
public void handleMessage(String event, JSONObject message) {
try {
if ("Viewport:Update".equals(event)) {
final ViewportMetrics newMetrics = new ViewportMetrics(message);
synchronized (mLayerController) {
// keep the old viewport size, but update everything else
ImmutableViewportMetrics oldMetrics = mLayerController.getViewportMetrics();
newMetrics.setSize(oldMetrics.getSize());
mLayerController.post(new Runnable() {
public void run() {
mGeckoViewport = newMetrics;
}
});
mLayerController.setViewportMetrics(newMetrics);
mLayerController.abortPanZoomAnimation();
mDisplayPort = calculateDisplayPort(mLayerController.getViewportMetrics());
mReturnDisplayPort = mDisplayPort;
}
handleViewportMessage(message, ViewportMessageType.UPDATE);
} else if ("Viewport:PageSize".equals(event)) {
handleViewportMessage(message, ViewportMessageType.PAGE_SIZE);
} else if ("Viewport:CalculateDisplayPort".equals(event)) {
ImmutableViewportMetrics newMetrics = new ImmutableViewportMetrics(new ViewportMetrics(message));
mReturnDisplayPort = calculateDisplayPort(newMetrics);

View File

@ -1515,6 +1515,7 @@ Tab.prototype = {
this.browser.addEventListener("DOMWindowClose", this, true);
this.browser.addEventListener("DOMWillOpenModalDialog", this, true);
this.browser.addEventListener("scroll", this, true);
this.browser.addEventListener("MozScrolledAreaChanged", this, true);
this.browser.addEventListener("PluginClickToPlay", this, true);
this.browser.addEventListener("pagehide", this, true);
this.browser.addEventListener("pageshow", this, true);
@ -1562,6 +1563,7 @@ Tab.prototype = {
this.browser.removeEventListener("DOMWillOpenModalDialog", this, true);
this.browser.removeEventListener("scroll", this, true);
this.browser.removeEventListener("PluginClickToPlay", this, true);
this.browser.removeEventListener("MozScrolledAreaChanged", this, true);
this.browser.removeEventListener("pagehide", this, true);
this.browser.removeEventListener("pageshow", this, true);
@ -1689,17 +1691,16 @@ Tab.prototype = {
return viewport;
},
sendViewportUpdate: function() {
sendViewportUpdate: function(aPageSizeUpdate) {
let message;
if (BrowserApp.selectedTab == this) {
// for foreground tabs, send the viewport update unless the document
// displayed is different from the content document
if (!BrowserApp.isBrowserContentDocumentDisplayed())
return;
// for foreground tabs, send the viewport update unless the document
// displayed is different from the content document. In that case, just
// calculate the display port.
if (BrowserApp.selectedTab == this && BrowserApp.isBrowserContentDocumentDisplayed()) {
message = this.getViewport();
message.type = "Viewport:Update";
message.type = aPageSizeUpdate ? "Viewport:PageSize" : "Viewport:Update";
} else {
// for bcakground tabs, request a new display port calculation, so that
// for background tabs, request a new display port calculation, so that
// when we do switch to that tab, we have the correct display port and
// don't need to draw twice (once to allow the first-paint viewport to
// get to java, and again once java figures out the display port).
@ -1859,6 +1860,17 @@ Tab.prototype = {
break;
}
case "MozScrolledAreaChanged": {
// This event is only fired for root scroll frames, and only when the
// scrolled area has actually changed, so no need to check for that.
// Just make sure it's the event for the correct root scroll frame.
if (aEvent.originalTarget != this.browser.contentDocument)
return;
this.sendViewportUpdate(true);
break;
}
case "PluginClickToPlay": {
// Keep track of the number of plugins to know whether or not to show
// the hidden plugins doorhanger
@ -2194,11 +2206,12 @@ Tab.prototype = {
// and then use the metadata to figure out how it needs to be updated
ViewportHandler.updateMetadata(this);
// The document element must have a display port on it whenever we are about to
// paint. This is the point just before the first paint, so we set the display port
// to a default value here. Once Java is aware of this document it will overwrite
// it with a better-calculated display port.
this.setDisplayPort(0, 0, {left: 0, top: 0, right: gScreenWidth, bottom: gScreenHeight });
// If we draw without a display-port, things can go wrong. While it's
// almost certain a display-port has been set via the
// MozScrolledAreaChanged event, make sure by sending a viewport
// update here. As it's the first paint, this will end up being a
// display-port request only.
this.sendViewportUpdate();
BrowserApp.displayedDocumentChanged();
this.contentDocumentIsDisplayed = true;