Merge "Revert "[Android WebView] Make web contents debugging controllable"" into klp-dev
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc
index 7c84cc9..68beacf 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/in_process_view_renderer.cc
@@ -377,12 +377,10 @@
   gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
   ScopedAllowGL allow_gl;
 
-  if (attached_to_window_ && compositor_ && !hardware_initialized_) {
-    if (InitializeHwDraw()) {
-      last_egl_context_ = current_context;
-    } else {
-      return;
-    }
+  if (!attached_to_window_) {
+    TRACE_EVENT_INSTANT0(
+        "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD);
+    return;
   }
 
   if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
@@ -391,6 +389,17 @@
     return;
   }
 
+  if (compositor_ && !hardware_initialized_) {
+    if (InitializeHwDraw()) {
+      last_egl_context_ = current_context;
+    } else {
+      TRACE_EVENT_INSTANT0(
+          "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD);
+      LOG(ERROR) << "WebView hardware initialization failed";
+      return;
+    }
+  }
+
   UpdateCachedGlobalVisibleRect();
   if (cached_global_visible_rect_.IsEmpty()) {
     TRACE_EVENT_INSTANT0("android_webview",
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
index dff3b81..5ea13e2 100644
--- a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
+++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
@@ -141,6 +141,8 @@
                         OnPageScaleFactorChanged)
     IPC_MESSAGE_HANDLER(AwViewHostMsg_OnContentsSizeChanged,
                         OnContentsSizeChanged)
+    IPC_MESSAGE_HANDLER(AwViewHostMsg_ShouldOverrideUrlLoading,
+                        OnShouldOverrideUrlLoading)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -176,4 +178,10 @@
   client_->OnWebLayoutContentsSizeChanged(contents_size);
 }
 
+void AwRenderViewHostExt::OnShouldOverrideUrlLoading(const base::string16& url,
+                                                     bool* ignore_navigation) {
+
+  *ignore_navigation = client_->OnShouldOverrideUrlLoading(url);
+}
+
 }  // namespace android_webview
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.h b/android_webview/browser/renderer_host/aw_render_view_host_ext.h
index d4e0256..1917d18 100644
--- a/android_webview/browser/renderer_host/aw_render_view_host_ext.h
+++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.h
@@ -28,6 +28,8 @@
   virtual void OnWebLayoutPageScaleFactorChanged(float page_scale_factor) = 0;
   virtual void OnWebLayoutContentsSizeChanged(
       const gfx::Size& contents_size) = 0;
+  // Called when there is a top level navigation.
+  virtual bool OnShouldOverrideUrlLoading(const base::string16& url) = 0;
 
  protected:
   virtual ~AwRenderViewHostExtClient() {}
@@ -92,6 +94,8 @@
   void OnUpdateHitTestData(const AwHitTestData& hit_test_data);
   void OnPageScaleFactorChanged(float page_scale_factor);
   void OnContentsSizeChanged(const gfx::Size& contents_size);
+  void OnShouldOverrideUrlLoading(const base::string16& url,
+                                  bool* ignore_navigation);
 
   bool IsRenderViewReady() const;
 
diff --git a/android_webview/common/render_view_messages.h b/android_webview/common/render_view_messages.h
index 80e2471..2c4ea67 100644
--- a/android_webview/common/render_view_messages.h
+++ b/android_webview/common/render_view_messages.h
@@ -99,3 +99,10 @@
 // Sent whenever the contents size (as seen by RenderView) is changed.
 IPC_MESSAGE_ROUTED1(AwViewHostMsg_OnContentsSizeChanged,
                     gfx::Size /* contents_size */)
+
+// Sent when there is a top level navigation. Returning true means
+// the application will handle this request and so will cancel the
+// navigation within Blink.
+IPC_SYNC_MESSAGE_ROUTED1_1(AwViewHostMsg_ShouldOverrideUrlLoading,
+                           string16 /* in - url */,
+                           bool /* out - result */)
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 121badd..c4c798a 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -48,7 +48,6 @@
 import org.chromium.content.browser.NavigationHistory;
 import org.chromium.content.browser.PageTransitionTypes;
 import org.chromium.content.common.CleanupReference;
-import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
 import org.chromium.components.navigation_interception.NavigationParams;
 import org.chromium.net.GURLUtils;
 import org.chromium.ui.gfx.DeviceDisplayInfo;
@@ -149,7 +148,6 @@
     private final AwContentsClientBridge mContentsClientBridge;
     private final AwWebContentsDelegate mWebContentsDelegate;
     private final AwContentsIoThreadClient mIoThreadClient;
-    private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
     private final InternalAccessDelegate mInternalAccessAdapter;
     private final AwLayoutSizer mLayoutSizer;
     private final AwZoomControls mZoomControls;
@@ -272,67 +270,6 @@
     }
 
     //--------------------------------------------------------------------------------------------
-    private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
-        private String mLastLoadUrlAddress;
-
-        public void onUrlLoadRequested(String url) {
-            mLastLoadUrlAddress = url;
-        }
-
-        @Override
-        public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
-            final String url = navigationParams.url;
-            final int transitionType = navigationParams.pageTransitionType;
-            final boolean isLoadUrl =
-                    (transitionType & PageTransitionTypes.PAGE_TRANSITION_FROM_API) != 0;
-            final boolean isBackForward =
-                    (transitionType & PageTransitionTypes.PAGE_TRANSITION_FORWARD_BACK) != 0;
-            final boolean isReload =
-                    (transitionType & PageTransitionTypes.PAGE_TRANSITION_CORE_MASK) ==
-                    PageTransitionTypes.PAGE_TRANSITION_RELOAD;
-            final boolean isRedirect = navigationParams.isRedirect;
-
-            boolean ignoreNavigation = false;
-
-            // Any navigation from loadUrl, goBack/Forward, or reload, are considered application
-            // initiated and hence will not yield a shouldOverrideUrlLoading() callback.
-            // TODO(joth): Using PageTransitionTypes should be sufficient to determine all app
-            // initiated navigations, and so mLastLoadUrlAddress should be removed.
-            if ((isLoadUrl && !isRedirect) || isBackForward || isReload ||
-                    mLastLoadUrlAddress != null && mLastLoadUrlAddress.equals(url)) {
-                // Support the case where the user clicks on a link that takes them back to the
-                // same page.
-                mLastLoadUrlAddress = null;
-
-                // If the embedder requested the load of a certain URL via the loadUrl API, then we
-                // do not offer it to AwContentsClient.shouldOverrideUrlLoading.
-                // The embedder is also not allowed to intercept POST requests because of
-                // crbug.com/155250.
-            } else if (!navigationParams.isPost) {
-                ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url);
-            }
-
-            // The existing contract is that shouldOverrideUrlLoading callbacks are delivered before
-            // onPageStarted callbacks; third party apps depend on this behavior.
-            // Using a ResouceThrottle to implement the navigation interception feature results in
-            // the WebContentsObserver.didStartLoading callback happening before the
-            // ResourceThrottle has a chance to run.
-            // To preserve the ordering the onPageStarted callback is synthesized from the
-            // shouldOverrideUrlLoading, and only if the navigation was not ignored (this
-            // balances out with the onPageFinished callback, which is suppressed in the
-            // AwContentsClient if the navigation was ignored).
-            if (!ignoreNavigation) {
-                // The shouldOverrideUrlLoading call might have resulted in posting messages to the
-                // UI thread. Using sendMessage here (instead of calling onPageStarted directly)
-                // will allow those to run in order.
-                mContentsClient.getCallbackHelper().postOnPageStarted(url);
-            }
-
-            return ignoreNavigation;
-        }
-    }
-
-    //--------------------------------------------------------------------------------------------
     private class AwLayoutSizerDelegate implements AwLayoutSizer.Delegate {
         @Override
         public void requestLayout() {
@@ -498,7 +435,6 @@
         mContentsClientBridge = new AwContentsClientBridge(contentsClient);
         mZoomControls = new AwZoomControls(this);
         mIoThreadClient = new IoThreadClientImpl();
-        mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
 
         boolean hasInternetPermission = containerView.getContext().checkPermission(
                     android.Manifest.permission.INTERNET,
@@ -558,7 +494,7 @@
                 new AwGestureStateListener(), mContentsClient.getContentViewClient(),
                 mZoomControls);
         nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
-                mIoThreadClient, mInterceptNavigationDelegate);
+                mIoThreadClient);
         mContentsClient.installWebContentsObserver(mContentViewCore);
         mContentViewCore.setUpdateFrameInfoListener(new AwContentUpdateFrameInfoListener());
         mSettings.setWebContents(nativeWebContents);
@@ -867,8 +803,6 @@
 
         mContentViewCore.loadUrl(params);
 
-        suppressInterceptionForThisNavigation();
-
         // The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit.
         // Chromium does not use this use code path and the best emulation of this behavior to call
         // request visited links once on the first URL load of the WebView.
@@ -878,14 +812,6 @@
         }
     }
 
-    private void suppressInterceptionForThisNavigation() {
-        if (mInterceptNavigationDelegate != null) {
-            // getUrl returns a sanitized address in the same format that will be used for
-            // callbacks, so it's safe to use string comparison as an equality check later on.
-            mInterceptNavigationDelegate.onUrlLoadRequested(mContentViewCore.getUrl());
-        }
-    }
-
     /**
      * Get the URL of the current page.
      *
@@ -1097,8 +1023,6 @@
      */
     public void goBack() {
         mContentViewCore.goBack();
-
-        suppressInterceptionForThisNavigation();
     }
 
     /**
@@ -1113,8 +1037,6 @@
      */
     public void goForward() {
         mContentViewCore.goForward();
-
-        suppressInterceptionForThisNavigation();
     }
 
     /**
@@ -1129,8 +1051,6 @@
      */
     public void goBackOrForward(int steps) {
         mContentViewCore.goToOffset(steps);
-
-        suppressInterceptionForThisNavigation();
     }
 
     /**
@@ -1807,6 +1727,11 @@
     }
 
     @CalledByNative
+    private boolean onShouldOverrideUrlLoading(String url) {
+        return mContentsClient.shouldOverrideUrlLoading(url);
+    }
+
+    @CalledByNative
     private void scrollContainerViewTo(int x, int y) {
         mScrollOffsetManager.scrollContainerViewTo(x, y);
     }
@@ -1894,8 +1819,7 @@
     private native void nativeSetJavaPeers(int nativeAwContents, AwContents awContents,
             AwWebContentsDelegate webViewWebContentsDelegate,
             AwContentsClientBridge contentsClientBridge,
-            AwContentsIoThreadClient ioThreadClient,
-            InterceptNavigationDelegate navigationInterceptionDelegate);
+            AwContentsIoThreadClient ioThreadClient);
     private native int nativeGetWebContents(int nativeAwContents);
 
     private native void nativeDocumentHasImages(int nativeAwContents, Message message);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
index 3f2245c..bd6dfd4 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
@@ -64,6 +64,11 @@
         }
 
         @Override
+        public void didStartLoading(String url) {
+            AwContentsClient.this.onPageStarted(url);
+        }
+
+        @Override
         public void didStopLoading(String url) {
             AwContentsClient.this.onPageFinished(url);
         }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
index 20ac8b5..97efee1 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwLayoutSizer.java
@@ -38,7 +38,7 @@
 
     private double mDIPScale;
 
-    // Was our heightSpec is AT_MOST the last time onMeasure was called?
+    // Was our height larger than the AT_MOST constraint the last time onMeasure was called?
     private boolean mHeightMeasurementLimited;
     // If mHeightMeasurementLimited is true then this contains the height limit.
     private int mHeightMeasurementLimit;
@@ -152,12 +152,11 @@
         // Always use the given size unless unspecified. This matches WebViewClassic behavior.
         mWidthMeasurementIsFixed = (widthMode != MeasureSpec.UNSPECIFIED);
         mHeightMeasurementIsFixed = (heightMode == MeasureSpec.EXACTLY);
-        mHeightMeasurementLimited = (heightMode == MeasureSpec.AT_MOST);
+        mHeightMeasurementLimited =
+            (heightMode == MeasureSpec.AT_MOST) && (contentHeightPix > heightSize);
         mHeightMeasurementLimit = heightSize;
 
-        final boolean measuredHeightClipped =
-            mHeightMeasurementLimited && (contentHeightPix > heightSize);
-        if (mHeightMeasurementIsFixed || measuredHeightClipped) {
+        if (mHeightMeasurementIsFixed || mHeightMeasurementLimited) {
             measuredHeight = heightSize;
         }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
index 1d75dd8..327fcff 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java
@@ -151,6 +151,32 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
+    public void testContentHeightGrowthRequestsLayoutInAtMostSizeMode() {
+        AwLayoutSizer layoutSizer = new AwLayoutSizer();
+        LayoutSizerDelegate delegate = new LayoutSizerDelegate();
+        layoutSizer.setDelegate(delegate);
+        layoutSizer.setDIPScale(DIP_SCALE);
+
+        layoutSizer.onPageScaleChanged(INITIAL_PAGE_SCALE);
+        layoutSizer.onContentSizeChanged(SMALLER_CONTENT_SIZE, SMALLER_CONTENT_SIZE);
+        layoutSizer.onMeasure(
+                MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST),
+                MeasureSpec.makeMeasureSpec(AT_MOST_MEASURE_SIZE, MeasureSpec.AT_MOST));
+        assertEquals(AT_MOST_MEASURE_SIZE, delegate.measuredWidth);
+        assertEquals(SMALLER_CONTENT_SIZE, delegate.measuredHeight);
+
+        int requestLayoutCallCount = delegate.requestLayoutCallCount;
+        layoutSizer.onContentSizeChanged(SMALLER_CONTENT_SIZE, AT_MOST_MEASURE_SIZE - 1);
+        assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount);
+
+        // Test that crossing the AT_MOST_MEASURE_SIZE threshold results in a requestLayout.
+        requestLayoutCallCount = delegate.requestLayoutCallCount;
+        layoutSizer.onContentSizeChanged(SMALLER_CONTENT_SIZE, AT_MOST_MEASURE_SIZE + 1);
+        assertEquals(requestLayoutCallCount + 1, delegate.requestLayoutCallCount);
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
     public void testContentHeightShrinksAfterAtMostSize() {
         AwLayoutSizer layoutSizer = new AwLayoutSizer();
         LayoutSizerDelegate delegate = new LayoutSizerDelegate();
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index c54fd62..0fa56df 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -40,7 +40,6 @@
 #include "components/autofill/content/browser/autofill_driver_impl.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/navigation_interception/intercept_navigation_delegate.h"
 #include "content/public/browser/android/content_view_core.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/cert_store.h"
@@ -73,7 +72,6 @@
 using base::android::JavaRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
-using navigation_interception::InterceptNavigationDelegate;
 using content::BrowserThread;
 using content::ContentViewCore;
 using content::WebContents;
@@ -204,8 +202,7 @@
                               jobject aw_contents,
                               jobject web_contents_delegate,
                               jobject contents_client_bridge,
-                              jobject io_thread_client,
-                              jobject intercept_navigation_delegate) {
+                              jobject io_thread_client) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   // The |aw_content| param is technically spurious as it duplicates |obj| but
   // is passed over anyway to make the binding more explicit.
@@ -225,12 +222,6 @@
   int child_id = web_contents_->GetRenderProcessHost()->GetID();
   int route_id = web_contents_->GetRoutingID();
   AwResourceDispatcherHostDelegate::OnIoThreadClientReady(child_id, route_id);
-
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  InterceptNavigationDelegate::Associate(
-      web_contents_.get(),
-      make_scoped_ptr(new InterceptNavigationDelegate(
-          env, intercept_navigation_delegate)));
 }
 
 void AwContents::SetSaveFormData(bool enabled) {
@@ -307,8 +298,11 @@
 }
 
 void AwContents::Destroy(JNIEnv* env, jobject obj) {
-  delete this;
-
+  java_ref_.reset();
+  // We do not delete AwContents immediately. Some applications try to delete
+  // Webview in ShouldOverrideUrlLoading callback, which is a sync IPC from
+  // Webkit.
+  BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
   // When the last WebView is destroyed free all discardable memory allocated by
   // Chromium, because the app process may continue to run for a long time
   // without ever using another WebView.
@@ -701,6 +695,12 @@
 
 void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) {
   browser_view_renderer_->SetIsPaused(paused);
+  if (paused) {
+    ContentViewCore* cvc =
+        ContentViewCore::FromWebContents(web_contents_.get());
+    if (cvc)
+      cvc->PauseVideo();
+  }
 }
 
 void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
@@ -868,6 +868,16 @@
       env, obj.obj(), contents_size.width(), contents_size.height());
 }
 
+bool AwContents::OnShouldOverrideUrlLoading(const base::string16& url) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (obj.is_null())
+    return false;
+  ScopedJavaLocalRef<jstring> jurl = ConvertUTF16ToJavaString(env, url);
+  return Java_AwContents_onShouldOverrideUrlLoading(env, obj.obj(),
+                                                    jurl.obj());
+}
+
 jint AwContents::CapturePicture(JNIEnv* env,
                                 jobject obj,
                                 int width,
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index aef1fed..6ee4764 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -79,8 +79,7 @@
                     jobject aw_contents,
                     jobject web_contents_delegate,
                     jobject contents_client_bridge,
-                    jobject io_thread_client,
-                    jobject intercept_navigation_delegate);
+                    jobject io_thread_client);
   jint GetWebContents(JNIEnv* env, jobject obj);
   jint GetAwContentsClientBridge(JNIEnv* env, jobject obj);
 
@@ -158,6 +157,7 @@
       float page_scale_factor) OVERRIDE;
   virtual void OnWebLayoutContentsSizeChanged(
       const gfx::Size& contents_size) OVERRIDE;
+  virtual bool OnShouldOverrideUrlLoading(const base::string16& url) OVERRIDE;
 
   // BrowserViewRenderer::Client implementation.
   virtual bool RequestDrawGL(jobject canvas) OVERRIDE;
diff --git a/android_webview/native/input_stream_impl.cc b/android_webview/native/input_stream_impl.cc
index 24d7be0..fca6a29 100644
--- a/android_webview/native/input_stream_impl.cc
+++ b/android_webview/native/input_stream_impl.cc
@@ -84,46 +84,48 @@
       return false;
   }
 
+  int remaining_length = length;
+  char* dest_write_ptr = dest->data();
   jbyteArray buffer = buffer_.obj();
   *bytes_read = 0;
 
-  const int read_size = std::min(length, kBufferSize);
-  int32_t byte_count;
-  do {
-    // Unfortunately it is valid for the Java InputStream to read 0 bytes some
-    // number of times before returning any more data. Because this method
-    // signals EOF by setting |bytes_read| to 0 and returning true necessary to
-    // call the Java-side read method until it returns something other than 0.
-    byte_count = Java_InputStream_readI_AB_I_I(
-        env, jobject_.obj(), buffer, 0, read_size);
+  while (remaining_length > 0) {
+    const int max_transfer_length = std::min(remaining_length, kBufferSize);
+    const int transfer_length = Java_InputStream_readI_AB_I_I(
+        env, jobject_.obj(), buffer, 0, max_transfer_length);
     if (ClearException(env))
       return false;
-  } while (byte_count == 0);
 
-  // We've reached the end of the stream.
-  if (byte_count < 0)
-    return true;
+    if (transfer_length < 0)  // EOF
+      break;
 
-#ifndef NDEBUG
-  int32_t buffer_length = env->GetArrayLength(buffer);
-  DCHECK_GE(read_size, byte_count);
-  DCHECK_GE(buffer_length, byte_count);
-#endif // NDEBUG
+    // Note: it is possible, yet unlikely, that the Java InputStream returns
+    // a transfer_length == 0 from time to time. In such cases we just continue
+    // the read until we get either valid data or reach EOF.
+    if (transfer_length == 0)
+      continue;
 
-  // The DCHECKs are in place to help Chromium developers in case of bugs,
-  // this check is to prevent a malicious InputStream implementation from
-  // overrunning the |dest| buffer.
-  if (byte_count > read_size)
-    return false;
+    DCHECK_GE(max_transfer_length, transfer_length);
+    DCHECK_GE(env->GetArrayLength(buffer), transfer_length);
 
-  // Copy the data over to the provided C++ side buffer.
-  DCHECK_GE(length, byte_count);
-  env->GetByteArrayRegion(buffer, 0, byte_count,
-      reinterpret_cast<jbyte*>(dest->data() + *bytes_read));
-  if (ClearException(env))
-    return false;
+    // This check is to prevent a malicious InputStream implementation from
+    // overrunning the |dest| buffer.
+    if (transfer_length > max_transfer_length)
+      return false;
 
-  *bytes_read = byte_count;
+    // Copy the data over to the provided C++ IOBuffer.
+    DCHECK_GE(remaining_length, transfer_length);
+    env->GetByteArrayRegion(buffer, 0, transfer_length,
+        reinterpret_cast<jbyte*>(dest_write_ptr));
+    if (ClearException(env))
+      return false;
+
+    remaining_length -= transfer_length;
+    dest_write_ptr += transfer_length;
+  }
+  // bytes_read can be strictly less than the req. length if EOF is encountered.
+  DCHECK(remaining_length >= 0 && remaining_length <= length);
+  *bytes_read = length - remaining_length;
   return true;
 }
 
diff --git a/android_webview/native/input_stream_unittest.cc b/android_webview/native/input_stream_unittest.cc
index 87b3fe3..76ca823 100644
--- a/android_webview/native/input_stream_unittest.cc
+++ b/android_webview/native/input_stream_unittest.cc
@@ -89,10 +89,10 @@
 }
 
 TEST_F(InputStreamTest, TryReadMoreThanBuffer) {
-  const int bytes_requested = 3 * InputStreamImpl::kBufferSize;
+  const int buffer_size = 3 * InputStreamImpl::kBufferSize;
   int bytes_read = 0;
-  DoReadCountedStreamTest(bytes_requested, bytes_requested, &bytes_read);
-  EXPECT_EQ(InputStreamImpl::kBufferSize, bytes_read);
+  DoReadCountedStreamTest(buffer_size, buffer_size * 2, &bytes_read);
+  EXPECT_EQ(buffer_size, bytes_read);
 }
 
 TEST_F(InputStreamTest, CheckContentsReadCorrectly) {
@@ -105,3 +105,17 @@
     EXPECT_EQ(i, (unsigned char)buffer->data()[i]);
   }
 }
+
+TEST_F(InputStreamTest, ReadLargeStreamPartial) {
+  const int bytes_requested = 3 * InputStreamImpl::kBufferSize;
+  int bytes_read = 0;
+  DoReadCountedStreamTest(bytes_requested + 32, bytes_requested, &bytes_read);
+  EXPECT_EQ(bytes_requested, bytes_read);
+}
+
+TEST_F(InputStreamTest, ReadLargeStreamCompletely) {
+  const int bytes_requested = 3 * InputStreamImpl::kBufferSize;
+  int bytes_read = 0;
+  DoReadCountedStreamTest(bytes_requested, bytes_requested, &bytes_read);
+  EXPECT_EQ(bytes_requested, bytes_read);
+}
diff --git a/android_webview/renderer/aw_content_renderer_client.cc b/android_webview/renderer/aw_content_renderer_client.cc
index 0ca5212..2419a9b 100644
--- a/android_webview/renderer/aw_content_renderer_client.cc
+++ b/android_webview/renderer/aw_content_renderer_client.cc
@@ -5,6 +5,7 @@
 #include "android_webview/renderer/aw_content_renderer_client.h"
 
 #include "android_webview/common/aw_resource.h"
+#include "android_webview/common/render_view_messages.h"
 #include "android_webview/common/url_constants.h"
 #include "android_webview/renderer/aw_render_view_ext.h"
 // START: Printing fork b/10190508
@@ -15,12 +16,17 @@
 #include "components/autofill/content/renderer/autofill_agent.h"
 #include "components/autofill/content/renderer/password_autofill_agent.h"
 #include "components/visitedlink/renderer/visitedlink_slave.h"
+#include "content/public/renderer/document_state.h"
+#include "content/public/renderer/navigation_state.h"
 #include "content/public/renderer/render_thread.h"
+#include "content/public/renderer/render_view.h"
 #include "net/base/net_errors.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/web/WebNavigationType.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
 #include "url/gurl.h"
 
@@ -46,6 +52,44 @@
   thread->AddObserver(visited_link_slave_.get());
 }
 
+bool AwContentRendererClient::HandleNavigation(
+    content::RenderView* view,
+    content::DocumentState* document_state,
+    WebKit::WebFrame* frame,
+    const WebKit::WebURLRequest& request,
+    WebKit::WebNavigationType type,
+    WebKit::WebNavigationPolicy default_policy,
+    bool is_redirect) {
+
+  // Only GETs can be overridden.
+  if (!request.httpMethod().equals("GET"))
+    return false;
+
+  // Any navigation from loadUrl, and goBack/Forward are considered application-
+  // initiated and hence will not yield a shouldOverrideUrlLoading() callback.
+  // Webview classic does not consider reload application-initiated so we
+  // continue the same behavior.
+  bool application_initiated =
+      !document_state->navigation_state()->is_content_initiated()
+      || type == WebKit::WebNavigationTypeBackForward;
+
+  // Don't offer application-initiated navigations unless it's a redirect.
+  if (application_initiated && !is_redirect)
+    return false;
+
+  // We are only interested in top-level navigation.
+  if (frame->parent())
+    return false;
+
+  bool ignore_navigation = false;
+  int routing_id = view->GetRoutingID();
+  base::string16 url =  request.url().string();
+  view->Send (new AwViewHostMsg_ShouldOverrideUrlLoading(routing_id,
+                                                         url,
+                                                         &ignore_navigation));
+  return ignore_navigation;
+}
+
 void AwContentRendererClient::RenderViewCreated(
     content::RenderView* render_view) {
   AwRenderViewExt::RenderViewCreated(render_view);
diff --git a/android_webview/renderer/aw_content_renderer_client.h b/android_webview/renderer/aw_content_renderer_client.h
index 73418d7..36e0c10 100644
--- a/android_webview/renderer/aw_content_renderer_client.h
+++ b/android_webview/renderer/aw_content_renderer_client.h
@@ -10,6 +10,10 @@
 #include "android_webview/renderer/aw_render_process_observer.h"
 #include "base/compiler_specific.h"
 
+namespace content {
+class DocumentState;
+class RenderView;
+}
 namespace visitedlink {
 class VisitedLinkSlave;
 }
@@ -37,6 +41,14 @@
                                              size_t length) OVERRIDE;
   virtual bool IsLinkVisited(unsigned long long link_hash) OVERRIDE;
 
+  virtual bool HandleNavigation(content::RenderView* view,
+                                content::DocumentState* document_state,
+                                WebKit::WebFrame* frame,
+                                const WebKit::WebURLRequest& request,
+                                WebKit::WebNavigationType type,
+                                WebKit::WebNavigationPolicy default_policy,
+                                bool is_redirect) OVERRIDE;
+
  private:
   scoped_ptr<AwRenderProcessObserver> aw_render_process_observer_;
   scoped_ptr<visitedlink::VisitedLinkSlave> visited_link_slave_;
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 27a50de..ca05938 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -196,6 +196,8 @@
   TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
   state_machine_.PollForAnticipatedDrawTriggers();
   ProcessScheduledActions();
+
+  poll_for_draw_triggers_closure_.Cancel();
 }
 
 void Scheduler::DrawAndSwapIfPossible() {
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 7761b35..d9e2b01 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -342,6 +342,13 @@
 
 void ContentViewCoreImpl::Hide() {
   GetWebContents()->WasHidden();
+  PauseVideo();
+}
+
+void ContentViewCoreImpl::PauseVideo() {
+  RenderViewHost* host = web_contents_->GetRenderViewHost();
+  if (host)
+    host->Send(new ViewMsg_PauseVideo(host->GetRoutingID()));
 }
 
 void ContentViewCoreImpl::OnTabCrashed() {
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index ffecf2b..a20365b 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -60,6 +60,7 @@
   virtual float GetDpiScale() const OVERRIDE;
   virtual void RequestContentClipping(const gfx::Rect& clipping,
                                       const gfx::Size& content_size) OVERRIDE;
+  virtual void PauseVideo() OVERRIDE;
 
   // --------------------------------------------------------------------------
   // Methods called from Java via JNI
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 537aef3..8017069 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -1315,6 +1315,9 @@
 // processed on the browser side.
 IPC_MESSAGE_ROUTED0(ViewMsg_ImeEventAck)
 
+// Sent by the browser when we should pause video playback.
+IPC_MESSAGE_ROUTED0(ViewMsg_PauseVideo);
+
 #elif defined(OS_MACOSX)
 // Let the RenderView know its window has changed visibility.
 IPC_MESSAGE_ROUTED1(ViewMsg_SetWindowVisibility,
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index dace547..c993e85 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -616,6 +616,8 @@
                                     // If OSK is newly shown, delay the form focus until
                                     // the onSizeChanged (in order to adjust relative to the
                                     // new size).
+                                    // TODO(jdduke): We should not assume that onSizeChanged will
+                                    // always be called, crbug.com/294908.
                                     getContainerView().getWindowVisibleDisplayFrame(
                                             mFocusPreOSKViewportRect);
                                 } else if (resultCode ==
@@ -1614,7 +1616,10 @@
             Rect rect = new Rect();
             getContainerView().getWindowVisibleDisplayFrame(rect);
             if (!rect.equals(mFocusPreOSKViewportRect)) {
-                scrollFocusedEditableNodeIntoView();
+                // Only assume the OSK triggered the onSizeChanged if width was preserved.
+                if (rect.width() == mFocusPreOSKViewportRect.width()) {
+                    scrollFocusedEditableNodeIntoView();
+                }
                 mFocusPreOSKViewportRect.setEmpty();
             }
         } else if (mUnfocusOnNextSizeChanged) {
diff --git a/content/public/browser/android/content_view_core.h b/content/public/browser/android/content_view_core.h
index dd3795b..79be4c4 100644
--- a/content/public/browser/android/content_view_core.h
+++ b/content/public/browser/android/content_view_core.h
@@ -54,6 +54,7 @@
   virtual float GetDpiScale() const = 0;
   virtual void RequestContentClipping(const gfx::Rect& clipping,
                                       const gfx::Size& content_size) = 0;
+  virtual void PauseVideo() = 0;
 
   // Observer callback for frame metadata updates.
   typedef base::Callback<void(
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index c190f09..a683808 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -92,6 +92,8 @@
 }
 
 bool ContentRendererClient::HandleNavigation(
+    RenderView* view,
+    DocumentState* document_state,
     WebKit::WebFrame* frame,
     const WebKit::WebURLRequest& request,
     WebKit::WebNavigationType type,
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index a00e1a9..549e44d 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -49,6 +49,7 @@
 
 namespace content {
 
+class DocumentState;
 class RenderView;
 class SynchronousCompositor;
 struct WebPluginInfo;
@@ -167,7 +168,9 @@
 
   // Returns true if the navigation was handled by the embedder and should be
   // ignored by WebKit. This method is used by CEF.
-  virtual bool HandleNavigation(WebKit::WebFrame* frame,
+  virtual bool HandleNavigation(RenderView* view,
+                                DocumentState* document_state,
+                                WebKit::WebFrame* frame,
                                 const WebKit::WebURLRequest& request,
                                 WebKit::WebNavigationType type,
                                 WebKit::WebNavigationPolicy default_policy,
diff --git a/content/renderer/media/android/renderer_media_player_manager.cc b/content/renderer/media/android/renderer_media_player_manager.cc
index 47f140f..62a99c0 100644
--- a/content/renderer/media/android/renderer_media_player_manager.cc
+++ b/content/renderer/media/android/renderer_media_player_manager.cc
@@ -33,7 +33,7 @@
   media_players_.erase(player_id);
 }
 
-void RendererMediaPlayerManager::ReleaseMediaResources() {
+void RendererMediaPlayerManager::ReleaseVideoResources() {
   std::map<int, WebMediaPlayerAndroid*>::iterator player_it;
   for (player_it = media_players_.begin();
       player_it != media_players_.end(); ++player_it) {
diff --git a/content/renderer/media/android/renderer_media_player_manager.h b/content/renderer/media/android/renderer_media_player_manager.h
index 3e5e13c..e565602 100644
--- a/content/renderer/media/android/renderer_media_player_manager.h
+++ b/content/renderer/media/android/renderer_media_player_manager.h
@@ -32,9 +32,9 @@
   int RegisterMediaPlayer(WebMediaPlayerAndroid* player);
   void UnregisterMediaPlayer(int player_id);
 
-  // Release all the media resources managed by this object unless
-  // an audio play is in progress.
-  void ReleaseMediaResources();
+  // Release the media resources managed by this object when a video
+  // is playing.
+  void ReleaseVideoResources();
 
   // Check whether a player can enter fullscreen.
   bool CanEnterFullscreen(WebKit::WebFrame* frame);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index ed8949e..9eb7d57 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1435,6 +1435,7 @@
                         OnUndoScrollFocusedEditableNodeIntoRect)
     IPC_MESSAGE_HANDLER(ViewMsg_UpdateTopControlsState,
                         OnUpdateTopControlsState)
+    IPC_MESSAGE_HANDLER(ViewMsg_PauseVideo, OnPauseVideo)
 #elif defined(OS_MACOSX)
     IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard)
     IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionCompleted,
@@ -1944,6 +1945,14 @@
   if (!node.isNull() && IsEditableNode(node))
     webview()->restoreScrollAndScaleState();
 }
+
+void RenderViewImpl::OnPauseVideo() {
+  // Inform RendererMediaPlayerManager to release all video player resources.
+  // If something is in progress the resource will not be freed, it will
+  // only be freed once the tab is destroyed or if the user navigates away
+  // via WebMediaPlayerAndroid::Destroy.
+  media_player_manager_->ReleaseVideoResources();
+}
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -3180,9 +3189,13 @@
     const WebURLRequest& request, WebNavigationType type,
     WebNavigationPolicy default_policy, bool is_redirect) {
   if (request.url() != GURL(kSwappedOutURL) &&
-      GetContentClient()->renderer()->HandleNavigation(frame, request, type,
-                                                       default_policy,
-                                                       is_redirect)) {
+      GetContentClient()->renderer()->HandleNavigation(
+          this,
+          static_cast<DocumentState*>(extraData),
+          frame,
+          request, type,
+          default_policy,
+          is_redirect)) {
     return WebKit::WebNavigationPolicyIgnore;
   }
 
@@ -5775,19 +5788,10 @@
 void RenderViewImpl::OnWasHidden() {
   RenderWidget::OnWasHidden();
 
-#if defined(OS_ANDROID)
-  // Inform RendererMediaPlayerManager to release all media player resources.
-  // unless some audio is playing.
-  // If something is in progress the resource will not be freed, it will
-  // only be freed once the tab is destroyed or if the user navigates away
-  // via WebMediaPlayerAndroid::Destroy
-  media_player_manager_->ReleaseMediaResources();
-
-#if defined(ENABLE_WEBRTC)
+#if defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
   RenderThreadImpl::current()->video_capture_impl_manager()->
       SuspendDevices(true);
 #endif
-#endif
 
   if (webview())
     webview()->setVisibilityState(visibilityState(), false);
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 4c6d77a..4464af9 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -1060,6 +1060,8 @@
   void OnUpdateTopControlsState(bool enable_hiding,
                                 bool enable_showing,
                                 bool animate);
+  void OnPauseVideo();
+
 #elif defined(OS_MACOSX)
   void OnCopyToFindPboard();
   void OnPluginImeCompositionCompleted(const string16& text, int plugin_id);