Merge "Fix 3366514 (again): browser emulator crash" into honeycomb
diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp
index 07a0e00..42104dc 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -749,9 +749,11 @@
     android::AutoMutex lock(m_atomicSync);
     // we set the reservedTexture if it's different from the drawing texture
     if (m_reservedTexture != reservedTexture &&
-        ((m_reservedTexture != m_drawingTexture) ||
+        ((reservedTexture != m_drawingTexture) ||
          (m_reservedTexture == 0 && m_drawingTexture == 0))) {
-        if (m_reservedTexture)
+        // Call release on the reserved texture if it is not the same as the
+        // drawing texture.
+        if (m_reservedTexture && (m_reservedTexture != m_drawingTexture))
             m_reservedTexture->release(this);
         m_reservedTexture = reservedTexture;
     }
diff --git a/WebCore/platform/graphics/android/MediaLayer.cpp b/WebCore/platform/graphics/android/MediaLayer.cpp
index fac94f5..7a4c02d 100644
--- a/WebCore/platform/graphics/android/MediaLayer.cpp
+++ b/WebCore/platform/graphics/android/MediaLayer.cpp
@@ -40,11 +40,11 @@
 
 namespace WebCore {
 
-MediaLayer::MediaLayer() : LayerAndroid(false)
+MediaLayer::MediaLayer(jobject weakWebViewRef) : LayerAndroid(false)
 {
     m_bufferedTexture = new MediaTexture(EGL_NO_CONTEXT);
     m_bufferedTexture->incStrong(this);
-    m_videoTexture = new VideoTexture();
+    m_videoTexture = new VideoTexture(weakWebViewRef);
     m_videoTexture->incStrong(this);
 
     m_currentTextureInfo = 0;
@@ -78,6 +78,8 @@
     // draw any video content if present
     m_videoTexture->drawVideo(drawTransform());
 
+    bool needsInval = true;
+
     // draw the primary content
     if (m_bufferedTexture) {
         TextureInfo* textureInfo = m_bufferedTexture->consumerLock();
@@ -95,14 +97,13 @@
             TilesManager::instance()->shader()->drawLayerQuad(m, rect,
                                                               textureInfo->m_textureId,
                                                               1.0f); //TODO fix this m_drawOpacity
+            if (!rect.isEmpty())
+                needsInval = false;
         }
         m_bufferedTexture->consumerRelease();
     }
 
-    drawChildrenGL(matrix);
-
-    //TODO allow plugins to specify when they should be drawn
-    return true;
+    return drawChildrenGL(matrix) || needsInval;
 }
 
 ANativeWindow* MediaLayer::acquireNativeWindowForVideo()
diff --git a/WebCore/platform/graphics/android/MediaLayer.h b/WebCore/platform/graphics/android/MediaLayer.h
index dec6427..15bd6d8 100644
--- a/WebCore/platform/graphics/android/MediaLayer.h
+++ b/WebCore/platform/graphics/android/MediaLayer.h
@@ -21,6 +21,7 @@
 
 #include "MediaTexture.h"
 #include "LayerAndroid.h"
+#include <jni.h>
 
 namespace android {
     class SurfaceTexture;
@@ -31,7 +32,7 @@
 class MediaLayer : public LayerAndroid {
 
 public:
-    MediaLayer();
+    MediaLayer(jobject weakWebViewRef);
     MediaLayer(const MediaLayer& layer);
     virtual ~MediaLayer();
 
diff --git a/WebCore/platform/graphics/android/MediaTexture.cpp b/WebCore/platform/graphics/android/MediaTexture.cpp
index 8481a20..a92b570 100644
--- a/WebCore/platform/graphics/android/MediaTexture.cpp
+++ b/WebCore/platform/graphics/android/MediaTexture.cpp
@@ -24,6 +24,8 @@
 #include <gui/SurfaceTexture.h>
 #include <gui/SurfaceTextureClient.h>
 #include <wtf/CurrentTime.h>
+#include <JNIUtility.h>
+#include "WebCoreJni.h"
 
 #define LAYER_DEBUG
 #undef LAYER_DEBUG
@@ -45,8 +47,46 @@
 
 namespace WebCore {
 
-VideoTexture::VideoTexture()
+class VideoListener : public android::SurfaceTexture::FrameAvailableListener {
+
+public:
+    VideoListener(jobject weakWebViewRef)
+        : m_weakWebViewRef(weakWebViewRef)
+        , m_postInvalMethod(0)
+    {
+        if (!m_weakWebViewRef)
+            return;
+
+        JNIEnv* env = JSC::Bindings::getJNIEnv();
+        jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
+        if (localWebViewRef) {
+            jclass wvClass = env->GetObjectClass(localWebViewRef);
+            m_postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V");
+            env->DeleteLocalRef(wvClass);
+            env->DeleteLocalRef(localWebViewRef);
+        }
+        checkException(env);
+    }
+
+    virtual void onFrameAvailable()
+    {
+        JNIEnv* env = JSC::Bindings::getJNIEnv();
+        jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
+        if (localWebViewRef) {
+            env->CallVoidMethod(localWebViewRef, m_postInvalMethod);
+            env->DeleteLocalRef(localWebViewRef);
+        }
+        checkException(env);
+    }
+
+private:
+    jobject m_weakWebViewRef;
+    jmethodID m_postInvalMethod;
+};
+
+VideoTexture::VideoTexture(jobject weakWebViewRef) : android::LightRefBase<VideoTexture>()
 {
+    m_weakWebViewRef = weakWebViewRef;
     m_textureId = 0;
     m_dimensions.setEmpty();
     m_newWindowRequest = false;
@@ -58,6 +98,10 @@
     releaseNativeWindow();
     if (m_textureId)
         glDeleteTextures(1, &m_textureId);
+    if (m_weakWebViewRef) {
+        JNIEnv* env = JSC::Bindings::getJNIEnv();
+        env->DeleteWeakGlobalRef(m_weakWebViewRef);
+    }
 }
 
 void VideoTexture::initNativeWindowIfNeeded()
@@ -73,6 +117,11 @@
 
     m_surfaceTexture = new android::SurfaceTexture(m_textureId);
     m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture);
+
+    //setup callback
+    sp<VideoListener> listener = new VideoListener(m_weakWebViewRef);
+    m_surfaceTexture->setFrameAvailableListener(listener);
+
     m_newWindowRequest = false;
     m_newWindowReady = true;
     m_newVideoRequestCond.signal();
@@ -109,8 +158,23 @@
     }
 
     m_newWindowRequest = true;
+
+    // post an inval message to the UI thread to fulfill the request
+    if (m_weakWebViewRef) {
+        JNIEnv* env = JSC::Bindings::getJNIEnv();
+        jobject localWebViewRef = env->NewLocalRef(m_weakWebViewRef);
+        if (localWebViewRef) {
+            jclass wvClass = env->GetObjectClass(localWebViewRef);
+            jmethodID postInvalMethod = env->GetMethodID(wvClass, "postInvalidate", "()V");
+            env->CallVoidMethod(localWebViewRef, postInvalMethod);
+            env->DeleteLocalRef(wvClass);
+            env->DeleteLocalRef(localWebViewRef);
+        }
+        checkException(env);
+    }
+
     //block until the request can be fulfilled or we time out
-    m_newVideoRequestCond.waitRelative(m_videoLock, 1000000000); // 1 sec
+    m_newVideoRequestCond.waitRelative(m_videoLock, 500000000); // .5 sec
 
     if (m_surfaceTextureClient.get())
         m_newWindowReady = false;
@@ -128,6 +192,11 @@
 {
     android::Mutex::Autolock lock(m_videoLock);
     m_dimensions.setEmpty();
+
+    if (m_surfaceTexture.get())
+        m_surfaceTexture->setFrameAvailableListener(0);
+
+    // clear the strong pointer references
     m_surfaceTextureClient.clear();
     m_surfaceTexture.clear();
 }
diff --git a/WebCore/platform/graphics/android/MediaTexture.h b/WebCore/platform/graphics/android/MediaTexture.h
index 156a67f..189905c 100644
--- a/WebCore/platform/graphics/android/MediaTexture.h
+++ b/WebCore/platform/graphics/android/MediaTexture.h
@@ -23,6 +23,7 @@
 #include "DoubleBufferedTexture.h"
 #include "LayerAndroid.h"
 #include <utils/RefBase.h>
+#include <jni.h>
 
 namespace android {
     class SurfaceTexture;
@@ -40,7 +41,7 @@
 class VideoTexture : public android::LightRefBase<VideoTexture> {
 
 public:
-    VideoTexture();
+    VideoTexture(jobject weakWebViewRef);
     ~VideoTexture();
 
     void initNativeWindowIfNeeded();
@@ -60,6 +61,8 @@
     bool m_newWindowRequest;
     bool m_newWindowReady;
 
+    jobject m_weakWebViewRef;
+
     android::Mutex m_videoLock;
     android::Condition m_newVideoRequestCond;
 };
diff --git a/WebCore/platform/graphics/android/TilesManager.cpp b/WebCore/platform/graphics/android/TilesManager.cpp
index d64a0b1..571d9cc 100644
--- a/WebCore/platform/graphics/android/TilesManager.cpp
+++ b/WebCore/platform/graphics/android/TilesManager.cpp
@@ -70,6 +70,14 @@
 
 namespace WebCore {
 
+GLint TilesManager::getMaxTextureSize()
+{
+    static GLint maxTextureSize = 0;
+    if (!maxTextureSize)
+        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+    return maxTextureSize;
+}
+
 TilesManager::TilesManager()
     : m_layersMemoryUsage(0)
     , m_maxTextureCount(0)
@@ -84,10 +92,6 @@
     m_tilesBitmap->eraseColor(0);
     m_pixmapsGenerationThread = new TexturesGenerator();
     m_pixmapsGenerationThread->run("TexturesGenerator");
-
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
-    m_totalMaxTextureSize = m_maxTextureSize * m_maxTextureSize * BYTES_PER_PIXEL;
-    XLOG("Max texture size %d", m_maxTextureSize);
 }
 
 void TilesManager::allocateTiles()
@@ -314,11 +318,13 @@
     unsigned int size = w * h * BYTES_PER_PIXEL;
 
     // We will not allocate textures that:
-    // 1) cannot be handled by the graphic card (m_maxTextureSize &
-    // m_totalMaxTextureSize)
+    // 1) cannot be handled by the graphic card (maxTextureSize &
+    // totalMaxTextureSize)
     // 2) will make us go past our texture limit (MAX_LAYERS_ALLOCATION)
 
-    bool large = w > m_maxTextureSize || h > m_maxTextureSize || size > m_totalMaxTextureSize;
+    GLint maxTextureSize = getMaxTextureSize();
+    unsigned totalMaxTextureSize = maxTextureSize * maxTextureSize * BYTES_PER_PIXEL;
+    bool large = w > maxTextureSize || h > maxTextureSize || size > totalMaxTextureSize;
     XLOG("createTextureForLayer(%d) @scale %.2f => %d, %d (too large? %x)", layer->uniqueId(),
          layer->getScale(), w, h, large);
 
diff --git a/WebCore/platform/graphics/android/TilesManager.h b/WebCore/platform/graphics/android/TilesManager.h
index 8e8c089..eeb38fe 100644
--- a/WebCore/platform/graphics/android/TilesManager.h
+++ b/WebCore/platform/graphics/android/TilesManager.h
@@ -44,6 +44,7 @@
 class TilesManager {
 public:
     static TilesManager* instance();
+    static GLint getMaxTextureSize();
 
     static bool hardwareAccelerationEnabled()
     {
@@ -121,8 +122,6 @@
     Vector<LayerTexture*> m_layersTextures;
 
     unsigned int m_layersMemoryUsage;
-    GLint m_maxTextureSize;
-    unsigned int m_totalMaxTextureSize;
 
     int m_maxTextureCount;
     bool m_expandedTileBounds;
diff --git a/WebKit/android/WebCoreSupport/WebRequest.cpp b/WebKit/android/WebCoreSupport/WebRequest.cpp
index 9d7a88e..fd6bbe2 100644
--- a/WebKit/android/WebCoreSupport/WebRequest.cpp
+++ b/WebKit/android/WebCoreSupport/WebRequest.cpp
@@ -451,7 +451,7 @@
     if (!read(&bytesRead)) {
         if (m_request && m_request->status().is_io_pending())
             return; // Wait for OnReadCompleted()
-        finish(false);
+        return finish(false);
     }
 
     // bytesRead == 0 indicates finished
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp
index 91c2ddb..b329e3b 100644
--- a/WebKit/android/jni/WebViewCore.cpp
+++ b/WebKit/android/jni/WebViewCore.cpp
@@ -108,7 +108,6 @@
 #include "SkPicture.h"
 #include "SkUtils.h"
 #include "Text.h"
-#include "TilesManager.h"
 #include "TypingCommand.h"
 #include "WebCoreFrameBridge.h"
 #include "WebFrameView.h"
@@ -343,6 +342,7 @@
 #endif
     m_isPaused = false;
     m_screenOnCounter = 0;
+    m_onlyScrollIfImeIsShowing = false;
 
     LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
 
@@ -350,7 +350,7 @@
     m_javaGlue = new JavaGlue;
     m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
     m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
-    m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
+    m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZ)V");
     m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
     m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
     m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V");
@@ -948,9 +948,11 @@
 //    LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
 
     JNIEnv* env = JSC::Bindings::getJNIEnv();
-    env->CallVoidMethod(m_javaGlue->object(env).get(),
-            animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo,
-            x, y);
+    if (animate)
+        env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_spawnScrollTo, x, y);
+    else
+        env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo,
+                x, y, m_onlyScrollIfImeIsShowing);
     checkException(env);
 }
 
@@ -1323,8 +1325,11 @@
     // If this was in response to touching a textfield and showing the IME,
     // the IME may now cover textfield.  Bring it back into view.
     // If the scale changed, however, this was the result of a zoom.
-    if (oldScale == m_scale)
+    if (oldScale == m_scale && osh > screenHeight) {
+        m_onlyScrollIfImeIsShowing = true;
         revealSelection();
+        m_onlyScrollIfImeIsShowing = false;
+    }
     // update the currently visible screen as perceived by the plugin
     sendPluginVisibleScreen();
 }
@@ -4514,15 +4519,6 @@
 #endif
 }
 
-static void SetExpandedTileBounds(JNIEnv *env, jobject obj, jboolean enabled)
-{
-    WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
-    if (!viewImpl)
-        return;
-    TilesManager::instance()->setExpandedTileBounds(enabled);
-}
-
-
 // ----------------------------------------------------------------------------
 
 /*
@@ -4630,8 +4626,6 @@
         (void*) GetTouchHighlightRects },
     { "nativeAutoFillForm", "(I)V",
         (void*) AutoFillForm },
-    { "nativeSetExpandedTileBounds", "(Z)V",
-        (void*) SetExpandedTileBounds },
 };
 
 int registerWebViewCore(JNIEnv* env)
diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h
index 1457089..5820dc5 100644
--- a/WebKit/android/jni/WebViewCore.h
+++ b/WebKit/android/jni/WebViewCore.h
@@ -610,6 +610,9 @@
         int m_blurringNodePointer;
         int m_lastFocusedSelStart;
         int m_lastFocusedSelEnd;
+        // Pass along with a scroll message to tell the UI thread to only
+        // scroll the page if the IME is showing.
+        bool m_onlyScrollIfImeIsShowing;
         PictureSet m_content; // the set of pictures to draw
         SkRegion m_addInval; // the accumulated inval region (not yet drawn)
         SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures
diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp
index 27eebd3..b25ad7d 100644
--- a/WebKit/android/nav/CachedFrame.cpp
+++ b/WebKit/android/nav/CachedFrame.cpp
@@ -50,13 +50,17 @@
         mRoot->mViewBounds.x(), mRoot->mViewBounds.y(),
         mRoot->mViewBounds.width(), mRoot->mViewBounds.height());
 #if USE(ACCELERATED_COMPOSITING)
-    if (mRoot) {
-        const CachedLayer* cachedLayer = layer(node);
-        const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer();
-        const LayerAndroid* aLayer = cachedLayer->layer(rootLayer);
-        if (aLayer)
-            return cachedLayer->adjustBounds(rootLayer, rect);
-    }
+    if (!mRoot)
+        return rect;
+
+    const CachedLayer* cachedLayer = layer(node);
+    if (!cachedLayer)
+        return rect;
+
+    const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer();
+    const LayerAndroid* aLayer = cachedLayer->layer(rootLayer);
+    if (aLayer)
+        return cachedLayer->adjustBounds(rootLayer, rect);
 #endif
     return rect;
 }
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index f84f8b0..935aecd 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -206,7 +206,7 @@
     // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
     // do not remove it here, we risk having BaseTiles trying to paint using a
     // deallocated base layer.
-    delete m_glWebViewState;
+    stopGL();
 #endif
     delete m_frameCacheUI;
     delete m_navPictureUI;
@@ -214,6 +214,14 @@
     delete m_glDrawFunctor;
 }
 
+void stopGL()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    delete m_glWebViewState;
+    m_glWebViewState = 0;
+#endif
+}
+
 WebViewCore* getWebViewCore() const {
     return m_viewImpl;
 }
@@ -2207,6 +2215,11 @@
     delete view;
 }
 
+static void nativeStopGL(JNIEnv *env, jobject obj)
+{
+    GET_NATIVE_VIEW(env, obj)->stopGL();
+}
+
 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
 {
     WebView* view = GET_NATIVE_VIEW(env, obj);
@@ -2395,6 +2408,11 @@
     return false;
 }
 
+static void nativeSetExpandedTileBounds(JNIEnv*, jobject, jboolean enabled)
+{
+    TilesManager::instance()->setExpandedTileBounds(enabled);
+}
+
 /*
  * JNI registration
  */
@@ -2559,6 +2577,8 @@
         (void*) nativeShowCursorTimed },
     { "nativeStartSelection", "(II)Z",
         (void*) nativeStartSelection },
+    { "nativeStopGL", "()V",
+        (void*) nativeStopGL },
     { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
         (void*) nativeSubtractLayers },
     { "nativeTextGeneration", "()I",
@@ -2573,6 +2593,8 @@
         (void*) nativeScrollableLayer },
     { "nativeScrollLayer", "(III)Z",
         (void*) nativeScrollLayer },
+    { "nativeSetExpandedTileBounds", "(Z)V",
+        (void*) nativeSetExpandedTileBounds },
 };
 
 int registerWebView(JNIEnv* env)
diff --git a/WebKit/android/plugins/ANPOpenGLInterface.cpp b/WebKit/android/plugins/ANPOpenGLInterface.cpp
index 8f5f9b4..015a04c 100644
--- a/WebKit/android/plugins/ANPOpenGLInterface.cpp
+++ b/WebKit/android/plugins/ANPOpenGLInterface.cpp
@@ -87,6 +87,9 @@
     info->m_internalFormat = textureInfo->internalFormat;
 
     texture->producerReleaseAndSwap();
+
+    // invalidate the java view so that this content is drawn
+    pluginWidget->viewInvalidate();
 }
 
 static void anp_invertPluginContent(NPP instance, bool isContentInverted) {
diff --git a/WebKit/android/plugins/PluginWidgetAndroid.cpp b/WebKit/android/plugins/PluginWidgetAndroid.cpp
index 90dceba..a02047b 100644
--- a/WebKit/android/plugins/PluginWidgetAndroid.cpp
+++ b/WebKit/android/plugins/PluginWidgetAndroid.cpp
@@ -156,8 +156,14 @@
 
 bool PluginWidgetAndroid::setDrawingModel(ANPDrawingModel model) {
 
-    if (model == kOpenGL_ANPDrawingModel && m_layer == 0)
-        m_layer = new WebCore::MediaLayer();
+    if (model == kOpenGL_ANPDrawingModel && m_layer == 0) {
+        JNIEnv* env = JSC::Bindings::getJNIEnv();
+        jobject webview = m_core->getWebViewJavaObject();
+        jobject weakWebViewRef = 0;
+        if (webview)
+            weakWebViewRef = env->NewWeakGlobalRef(webview);
+        m_layer = new WebCore::MediaLayer(weakWebViewRef);
+    }
     else if (model != kOpenGL_ANPDrawingModel && m_layer != 0)
         m_layer->unref();
 
@@ -204,6 +210,12 @@
     }
 }
 
+void PluginWidgetAndroid::viewInvalidate() {
+    WebCore::IntRect rect(m_pluginBounds.fLeft, m_pluginBounds.fTop,
+            m_pluginBounds.width(), m_pluginBounds.height());
+    m_core->viewInvalidate(rect);
+}
+
 void PluginWidgetAndroid::draw(SkCanvas* canvas) {
     if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) {
         return;
diff --git a/WebKit/android/plugins/PluginWidgetAndroid.h b/WebKit/android/plugins/PluginWidgetAndroid.h
index 9726a22..5d586b1 100644
--- a/WebKit/android/plugins/PluginWidgetAndroid.h
+++ b/WebKit/android/plugins/PluginWidgetAndroid.h
@@ -177,6 +177,8 @@
 
     void setPowerState(ANPPowerState powerState);
 
+    void viewInvalidate();
+
 private:
     void computeVisiblePluginRect();
     void scrollToVisiblePluginRect();