Index: android_webview/java/src/org/chromium/android_webview/AwContents.java |
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java |
index 3ee10deafe17e003768787f98b007027fe113eda..d8b6e51058500bd01a68bf65a49d62807f579c94 100644 |
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java |
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java |
@@ -92,6 +92,8 @@ public class AwContents implements SmartClipProvider { |
// produce little visible difference. |
private static final float ZOOM_CONTROLS_EPSILON = 0.007f; |
+ private static final String BLANK_URL = "about:blank"; |
+ |
/** |
* WebKit hit test related data strcutre. These are used to implement |
* getHitTestResult, requestFocusNodeHref, requestImageRef methods in WebView. |
@@ -254,6 +256,9 @@ public class AwContents implements SmartClipProvider { |
// when in this state. |
private boolean mTemporarilyDetached; |
+ // This flag indicates that we're currently loading BLANK_URL. |
+ private boolean mIsLoadingBlank = false; |
+ |
// True when this AwContents has been destroyed. |
// Do not use directly, call isDestroyed() instead. |
private boolean mIsDestroyed = false; |
@@ -833,7 +838,7 @@ public class AwContents implements SmartClipProvider { |
if (mWebContentsObserver != null) { |
mWebContentsObserver.detachFromWebContents(); |
} |
- mWebContentsObserver = new AwWebContentsObserver(mWebContents, mContentsClient); |
+ mWebContentsObserver = new AwWebContentsObserver(mWebContents, this, mContentsClient); |
} |
/** |
@@ -1078,6 +1083,24 @@ public class AwContents implements SmartClipProvider { |
mScrollOffsetManager.computeVerticalScrollRange())); |
} |
+ void onPageFinished(String url) { |
+ if (mIsLoadingBlank) { |
+ // Waiting for onPageFinished before flashing ensures that the DOM tree |
+ // does not contain stale content. |
+ flushVisualState(new VisualStateFlushCallback() { |
+ @Override |
+ public void onFailure(int reason) { |
+ mIsLoadingBlank = false; |
+ } |
+ |
+ @Override |
+ public void onComplete() { |
+ mIsLoadingBlank = false; |
+ } |
+ }); |
+ } |
+ } |
+ |
public void clearView() { |
if (!isDestroyed()) nativeClearView(mNativeAwContents); |
} |
@@ -1142,6 +1165,17 @@ public class AwContents implements SmartClipProvider { |
} |
/** |
+ * Short-hand to load "about:blank". When "about:blank" is loaded AwContents will draw |
+ * the background color specified by {@link AwContents#setBackgroundColor(int)}. This method |
+ * guarantees that the next frame after invocation will draw the background |
+ * color immediately without having to wait for the actual load to complete |
+ * ({@link AwContentsClient#onPageFinished(String)}) or similar events. |
+ */ |
+ public void loadBlank() { |
+ loadUrl(new LoadUrlParams(BLANK_URL)); |
+ } |
+ |
+ /** |
* Load url without fixing up the url string. Consumers of ContentView are responsible for |
* ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left |
* off during user input). |
@@ -1151,6 +1185,10 @@ public class AwContents implements SmartClipProvider { |
public void loadUrl(LoadUrlParams params) { |
if (isDestroyed()) return; |
+ if (BLANK_URL.equals(params.getUrl())) { |
+ mIsLoadingBlank = true; |
+ } |
+ |
if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA |
&& !params.isBaseUrlDataScheme()) { |
// This allows data URLs with a non-data base URL access to file:///android_asset/ and |
@@ -1243,7 +1281,9 @@ public class AwContents implements SmartClipProvider { |
// Do not ask the ContentViewCore for the background color, as it will always |
// report white prior to initial navigation or post destruction, whereas we want |
// to use the client supplied base value in those cases. |
- if (isDestroyed() || !mContentsClient.isCachedRendererBackgroundColorValid()) { |
+ // When loading BLANK_URL we want to draw the client supplied base color immediately. |
+ if (isDestroyed() || !mContentsClient.isCachedRendererBackgroundColorValid() |
+ || mIsLoadingBlank) { |
return mBaseBackgroundColor; |
} |
return mContentsClient.getCachedRendererBackgroundColor(); |
@@ -2020,6 +2060,31 @@ public class AwContents implements SmartClipProvider { |
if (!isDestroyed()) nativeSetJsOnlineProperty(mNativeAwContents, networkUp); |
} |
+ /** |
+ * Callback used when flushing the visual state, see {@link #flushVisualState}. |
+ */ |
+ @VisibleForTesting |
+ public abstract static class VisualStateFlushCallback { |
+ public abstract void onComplete(); |
+ public abstract void onFailure(int reason); |
+ } |
+ |
+ /** |
+ * Flush the visual state. |
+ * |
+ * Flushing the visual state means queuing a callback in Blink that will be invoked when the |
+ * contents of the DOM tree at the moment that the callback was enqueued (or later) are drawn |
+ * into the screen. In other words, the following events need to happen before the callback is |
+ * invoked: |
+ * 1. The DOM tree is committed becoming the pending tree - see ThreadProxy::BeginMainFrame |
+ * 2. The pending tree is activated becoming the active tree |
+ * 3. A frame swap happens that draws the active tree into the screen |
+ */ |
+ @VisibleForTesting |
+ public void flushVisualState(VisualStateFlushCallback callback) { |
+ nativeFlushVisualState(mNativeAwContents, callback); |
+ } |
+ |
//-------------------------------------------------------------------------------------------- |
// Methods called from native via JNI |
//-------------------------------------------------------------------------------------------- |
@@ -2123,6 +2188,15 @@ public class AwContents implements SmartClipProvider { |
mContentsClient.getCallbackHelper().postOnNewPicture(mPictureListenerContentProvider); |
} |
+ @CalledByNative |
+ public static void flushVisualStateCallback(VisualStateFlushCallback callback, int value) { |
+ if (value == 0) { |
+ callback.onComplete(); |
+ } else { |
+ callback.onFailure(value); |
+ } |
+ } |
+ |
// Called as a result of nativeUpdateLastHitTestData. |
@CalledByNative |
private void updateHitTestData( |
@@ -2337,8 +2411,9 @@ public class AwContents implements SmartClipProvider { |
@Override |
public void onDraw(Canvas canvas) { |
- if (isDestroyed()) { |
- TraceEvent.instant("EarlyOut_destroyed"); |
+ if (isDestroyed() || mIsLoadingBlank) { |
+ String trace = isDestroyed() ? "EarlyOut_destroyed" : "EarlyOut_loadingBlank"; |
+ TraceEvent.instant(trace); |
canvas.drawColor(getEffectiveBackgroundColor()); |
return; |
} |
@@ -2688,6 +2763,8 @@ public class AwContents implements SmartClipProvider { |
private native long nativeGetAwDrawGLViewContext(long nativeAwContents); |
private native long nativeCapturePicture(long nativeAwContents, int width, int height); |
private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled); |
+ private native void nativeFlushVisualState(long nativeAwContents, |
+ VisualStateFlushCallback callback); |
private native void nativeClearView(long nativeAwContents); |
private native void nativeSetExtraHeadersForUrl(long nativeAwContents, |
String url, String extraHeaders); |