diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 3e2db6ee1d0c..202d32c4bec6 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -615,8 +615,11 @@ abstract public class GeckoApp if (mLastUri == lastHistoryEntry.mUri && mLastTitle == lastHistoryEntry.mTitle) return; - - mLastViewport = mSoftwareLayerClient.getGeckoViewportMetrics().toJSON(); + + ViewportMetrics viewportMetrics = mSoftwareLayerClient.getGeckoViewportMetrics(); + if (viewportMetrics != null) + mLastViewport = viewportMetrics.toJSON(); + mLastUri = lastHistoryEntry.mUri; mLastTitle = lastHistoryEntry.mTitle; Bitmap bitmap = mSoftwareLayerClient.getBitmap(); diff --git a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java index 55f8f98a261e..b01a188472e9 100644 --- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java +++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java @@ -140,7 +140,8 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL layerController.setViewportMetrics(mGeckoViewport); } - GeckoAppShell.registerGeckoEventListener("Viewport:Update", this); + GeckoAppShell.registerGeckoEventListener("Viewport:Expose", this); + GeckoAppShell.registerGeckoEventListener("Viewport:UpdateAndDraw", this); GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this); } @@ -340,19 +341,15 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL } public void handleMessage(String event, JSONObject message) { - if ("Viewport:Update".equals(event)) { - beginTransaction(mTileLayer); - try { - updateViewport(message.getString("viewport"), false); - } catch (JSONException e) { - Log.e(LOGTAG, "Unable to update viewport", e); - } finally { - endTransaction(mTileLayer); - } + if ("Viewport:Expose".equals(event)) { + GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.EXPOSE)); + } else if ("Viewport:UpdateAndDraw".equals(event)) { + mUpdateViewportOnEndDraw = true; + + // Redraw everything. + Rect rect = new Rect(0, 0, mBufferSize.width, mBufferSize.height); + GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.DRAW, rect)); } else if ("Viewport:UpdateLater".equals(event)) { - if (!mTileLayer.inTransaction()) { - Log.e(LOGTAG, "Viewport:UpdateLater called while not in transaction. You should be using Viewport:Update instead!"); - } mUpdateViewportOnEndDraw = true; } } diff --git a/mobile/android/base/ui/PanZoomController.java b/mobile/android/base/ui/PanZoomController.java index 6800252b66b5..1b879507aa5d 100644 --- a/mobile/android/base/ui/PanZoomController.java +++ b/mobile/android/base/ui/PanZoomController.java @@ -264,7 +264,10 @@ public class PanZoomController // the screen orientation changed) so abort it and start a new one to // ensure the viewport doesn't contain out-of-bounds areas case NOTHING: - bounce(); + // Don't do animations here; they're distracting and can cause flashes on page + // transitions. + mController.setViewportMetrics(getValidViewportMetrics()); + mController.notifyLayerClientOfGeometryChange(); break; } } diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 7c110f2d3d38..788ec0c85daf 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -200,6 +200,7 @@ var BrowserApp = { Services.obs.addObserver(this, "Viewport:Change", false); Services.obs.addObserver(this, "AgentMode:Change", false); Services.obs.addObserver(this, "SearchEngines:Get", false); + Services.obs.addObserver(this, "document-shown", false); function showFullScreenWarning() { NativeWindow.toast.show(Strings.browser.GetStringFromName("alertFullScreenToast"), "short"); @@ -715,6 +716,20 @@ var BrowserApp = { ViewportHandler.onResize(); } else if (aTopic == "SearchEngines:Get") { this.getSearchEngines(); + } else if (aTopic == "document-shown") { + let tab = this.selectedTab; + if (tab.browser.contentDocument != aSubject) { + return; + } + + ViewportHandler.updateMetadata(tab); + + // Unsuppress drawing unless the page was being thawed from the bfcache (which is an atomic + // operation, so there is no drawing to suppress). + if (tab.suppressDrawing) { + tab.sendExposeEvent(); + tab.suppressDrawing = false; + } } }, @@ -722,7 +737,7 @@ var BrowserApp = { delete this.defaultBrowserWidth; let width = Services.prefs.getIntPref("browser.viewport.desktopWidth"); return this.defaultBrowserWidth = width; - } + } }; var NativeWindow = { @@ -1194,6 +1209,12 @@ Tab.prototype = { this.browser.addEventListener("PluginClickToPlay", this, true); this.browser.addEventListener("pagehide", this, true); + let chromeEventHandler = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .chromeEventHandler; + chromeEventHandler.addEventListener("DOMWindowCreated", this, false); + Services.obs.addObserver(this, "http-on-modify-request", false); if (!aParams.delayLoad) { @@ -1403,8 +1424,7 @@ Tab.prototype = { return; sendMessageToJava({ gecko: { - type: "Viewport:Update", - viewport: JSON.stringify(this.viewport) + type: "Viewport:UpdateAndDraw" } }); }, @@ -1547,6 +1567,18 @@ Tab.prototype = { } break; } + + case "DOMWindowCreated": { + // Conveniently, this call to getBrowserForDocument() will return null if the document is + // not the top-level content document of the browser. + let browser = BrowserApp.getBrowserForDocument(aEvent.originalTarget); + if (!browser) + break; + + let tab = BrowserApp.getTabForBrowser(browser); + tab.suppressDrawing = true; + break; + } } }, @@ -1806,6 +1838,16 @@ Tab.prototype = { } }, + sendExposeEvent: function() { + // Now that the document is actually on the screen, send an expose event. + this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + sendMessageToJava({ + gecko: { + type: "Viewport:Expose" + } + }); + }, + QueryInterface: XPCOMUtils.generateQI([ Ci.nsIWebProgressListener, Ci.nsISHistoryListener,