Merge "Revert "Put canvas on a layer"" into ics-mr1
diff --git a/Source/WebCore/loader/cache/CachedImage.cpp b/Source/WebCore/loader/cache/CachedImage.cpp
index ba30860..6867302 100644
--- a/Source/WebCore/loader/cache/CachedImage.cpp
+++ b/Source/WebCore/loader/cache/CachedImage.cpp
@@ -57,6 +57,7 @@
     , m_image(0)
     , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
     , m_shouldPaintBrokenImage(true)
+    , m_autoLoadWasPreventedBySettings(false)
 {
     setStatus(Unknown);
 }
@@ -66,6 +67,7 @@
     , m_image(image)
     , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
     , m_shouldPaintBrokenImage(true)
+    , m_autoLoadWasPreventedBySettings(false)
 {
     setStatus(Cached);
     setLoading(false);
diff --git a/Source/WebCore/loader/cache/CachedImage.h b/Source/WebCore/loader/cache/CachedImage.h
index 42c7814..79643d7 100644
--- a/Source/WebCore/loader/cache/CachedImage.h
+++ b/Source/WebCore/loader/cache/CachedImage.h
@@ -75,7 +75,7 @@
 
     void clear();
     
-    bool stillNeedsLoad() const { return !errorOccurred() && status() == Unknown && !isLoading(); }
+    bool stillNeedsLoad() const { return (!errorOccurred() && status() == Unknown && !isLoading()) || (m_autoLoadWasPreventedBySettings && !inCache()); }
     void load();
 
     // ImageObserver
@@ -86,6 +86,8 @@
     virtual void animationAdvanced(const Image*);
     virtual void changedInRect(const Image*, const IntRect&);
 
+    void setAutoLoadWasPreventedBySettings(bool prevented) { m_autoLoadWasPreventedBySettings = prevented; }
+
 private:
     void createImage();
     size_t maximumDecodedImageSize();
@@ -98,6 +100,7 @@
     RefPtr<Image> m_image;
     Timer<CachedImage> m_decodedDataDeletionTimer;
     bool m_shouldPaintBrokenImage;
+    bool m_autoLoadWasPreventedBySettings;
 };
 
 }
diff --git a/Source/WebCore/loader/cache/CachedResource.cpp b/Source/WebCore/loader/cache/CachedResource.cpp
index 95f5522..e599769 100644
--- a/Source/WebCore/loader/cache/CachedResource.cpp
+++ b/Source/WebCore/loader/cache/CachedResource.cpp
@@ -261,7 +261,7 @@
 
 void CachedResource::didAddClient(CachedResourceClient* c)
 {
-    if (!isLoading())
+    if (!isLoading() && !stillNeedsLoad())
         c->notifyFinished(this);
 }
 
diff --git a/Source/WebCore/loader/cache/CachedResource.h b/Source/WebCore/loader/cache/CachedResource.h
index 72b00e5..2f33ac7 100644
--- a/Source/WebCore/loader/cache/CachedResource.h
+++ b/Source/WebCore/loader/cache/CachedResource.h
@@ -127,6 +127,7 @@
 
     bool isLoading() const { return m_loading; }
     void setLoading(bool b) { m_loading = b; }
+    virtual bool stillNeedsLoad() const { return false; }
 
     virtual bool isImage() const { return false; }
     bool isLinkResource() const
diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
index 38fcee4..91c0629 100644
--- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp
+++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
@@ -138,14 +138,21 @@
         }
     }
     CachedImage* resource = static_cast<CachedImage*>(requestResource(CachedResource::ImageResource, url, String()));
-    if (autoLoadImages() && resource && resource->stillNeedsLoad()) {
+    if (resource) {
 #ifdef ANDROID_BLOCK_NETWORK_IMAGE
-        if (shouldBlockNetworkImage(url)) {
-            return resource;
-        }
+        resource->setAutoLoadWasPreventedBySettings(!autoLoadImages() || shouldBlockNetworkImage(url));
+#else
+        resource->setAutoLoadWasPreventedBySettings(!autoLoadImages());
 #endif
-        resource->setLoading(true);
-        load(resource, true);
+        if (autoLoadImages() && resource->stillNeedsLoad()) {
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+            if (shouldBlockNetworkImage(url)) {
+                return resource;
+            }
+#endif
+            resource->setLoading(true);
+            load(resource, true);
+        }
     }
     return resource;
 }
@@ -520,9 +527,12 @@
             if (shouldBlockNetworkImage(image->url()))
                 continue;
 #endif
+            image->setAutoLoadWasPreventedBySettings(false);
 
-            if (image->stillNeedsLoad())
+            if (image->stillNeedsLoad()) {
+                image->setLoading(true);
                 load(image, true);
+            }
         }
     }
 }
@@ -536,7 +546,6 @@
     KURL kurl = m_document->completeURL(url);
     if (kurl.protocolIs("http") || kurl.protocolIs("https"))
         return true;
-
     return false;
 }
 
@@ -555,8 +564,11 @@
         CachedResource* resource = it->second.get();
         if (resource->type() == CachedResource::ImageResource) {
             CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource));
-            if (image->stillNeedsLoad())
+            image->setAutoLoadWasPreventedBySettings(false);
+            if (image->stillNeedsLoad()) {
+                image->setLoading(true);
                 load(image, true);
+            }
         }
     }
 }
diff --git a/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp b/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp
index 5601269..6b22359 100644
--- a/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp
+++ b/Source/WebCore/platform/graphics/android/AndroidAnimation.cpp
@@ -49,6 +49,8 @@
 
 namespace WebCore {
 
+static int gUniqueId;
+
 static long gDebugAndroidAnimationInstances;
 
 long AndroidAnimation::instancesCount()
@@ -69,27 +71,11 @@
     , m_timingFunction(animation->timingFunction())
     , m_type(type)
     , m_operations(operations)
+    , m_uniqueId(++gUniqueId)
+    , m_hasFinished(false)
 {
     ASSERT(m_timingFunction);
 
-    if (!static_cast<int>(beginTime)) // time not set
-        m_beginTime = WTF::currentTime();
-
-    gDebugAndroidAnimationInstances++;
-}
-
-AndroidAnimation::AndroidAnimation(AndroidAnimation* anim)
-    : m_beginTime(anim->m_beginTime)
-    , m_duration(anim->m_duration)
-    , m_fillsBackwards(anim->m_fillsBackwards)
-    , m_fillsForwards(anim->m_fillsForwards)
-    , m_iterationCount(anim->m_iterationCount)
-    , m_direction(anim->m_direction)
-    , m_timingFunction(anim->m_timingFunction)
-    , m_name(anim->name())
-    , m_type(anim->m_type)
-    , m_operations(anim->m_operations)
-{
     gDebugAndroidAnimationInstances++;
 }
 
@@ -98,20 +84,23 @@
     gDebugAndroidAnimationInstances--;
 }
 
+void AndroidAnimation::suggestBeginTime(double time)
+{
+    if (m_beginTime <= 0.000001) // overflow or not yet set
+        m_beginTime = time;
+}
+
 double AndroidAnimation::elapsedTime(double time)
 {
-    if (m_beginTime <= 0.000001) // overflow or not correctly set
-        m_beginTime = time;
-
-    m_elapsedTime = time - m_beginTime;
+    double elapsedTime = (m_beginTime < 0.000001) ? 0 : time - m_beginTime;
 
     if (m_duration <= 0)
       m_duration = 0.000001;
 
-    if (m_elapsedTime < 0) // animation not yet started.
+    if (elapsedTime < 0) // animation not yet started.
         return 0;
 
-    return m_elapsedTime;
+    return elapsedTime;
 }
 
 bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
@@ -127,6 +116,13 @@
     // If not infinite, return false if we are done
     if (m_iterationCount > 0 && progress > dur) {
         *finalProgress = 1.0;
+        if (!m_hasFinished) {
+            // first time past duration, continue with progress 1.0 so the
+            // element's final position lines up with it's last keyframe
+            m_hasFinished = true;
+            return true;
+        }
+
         return false;
     }
 
@@ -187,7 +183,7 @@
 
     if (progress < 0) {
         // The animation hasn't started yet
-        if (m_fillsBackwards) {
+        if (m_fillsBackwards || m_beginTime <= 0.000001) {
             // in this case we want to apply the initial keyframe to the layer
             applyForProgress(layer, 0);
         }
@@ -195,7 +191,7 @@
         return true;
     }
 
-    if (progress >= 1) {
+    if (progress > 1) {
         if (!m_fillsForwards)
             return false;
         progress = 1;
@@ -225,16 +221,6 @@
 {
 }
 
-AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim)
-    : AndroidAnimation(anim)
-{
-}
-
-PassRefPtr<AndroidAnimation> AndroidOpacityAnimation::copy()
-{
-    return adoptRef(new AndroidOpacityAnimation(this));
-}
-
 void AndroidAnimation::pickValues(double progress, int* start, int* end)
 {
     float distance = -1;
@@ -298,16 +284,6 @@
 {
 }
 
-AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim)
-    : AndroidAnimation(anim)
-{
-}
-
-PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy()
-{
-    return adoptRef(new AndroidTransformAnimation(this));
-}
-
 void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress)
 {
     // First, we need to get the from and to values
diff --git a/Source/WebCore/platform/graphics/android/AndroidAnimation.h b/Source/WebCore/platform/graphics/android/AndroidAnimation.h
index 16a63e8..dca769f 100644
--- a/Source/WebCore/platform/graphics/android/AndroidAnimation.h
+++ b/Source/WebCore/platform/graphics/android/AndroidAnimation.h
@@ -33,16 +33,15 @@
 
 class TimingFunction;
 
-class AndroidAnimation : public RefCounted<AndroidAnimation> {
+class AndroidAnimation : public ThreadSafeRefCounted<AndroidAnimation> {
 public:
     AndroidAnimation(AnimatedPropertyID type,
                      const Animation* animation,
                      KeyframeValueList* operations,
                      double beginTime);
-    AndroidAnimation(AndroidAnimation* anim);
 
     virtual ~AndroidAnimation();
-    virtual PassRefPtr<AndroidAnimation> copy() = 0;
+    void suggestBeginTime(double time);
     double elapsedTime(double time);
     void pickValues(double progress, int* start, int* end);
     bool checkIterationsAndProgress(double time, float* finalProgress);
@@ -56,11 +55,10 @@
     AnimatedPropertyID type() { return m_type; }
     bool fillsBackwards() { return m_fillsBackwards; }
     bool fillsForwards() { return m_fillsForwards; }
-
+    int uniqueId() { return m_uniqueId; }
 
 protected:
     double m_beginTime;
-    double m_elapsedTime;
     double m_duration;
     bool m_fillsBackwards;
     bool m_fillsForwards;
@@ -70,6 +68,8 @@
     String m_name;
     AnimatedPropertyID m_type;
     KeyframeValueList* m_operations;
+    int m_uniqueId;
+    bool m_hasFinished;
 };
 
 class AndroidOpacityAnimation : public AndroidAnimation {
@@ -80,8 +80,6 @@
     AndroidOpacityAnimation(const Animation* animation,
                             KeyframeValueList* operations,
                             double beginTime);
-    AndroidOpacityAnimation(AndroidOpacityAnimation* anim);
-    virtual PassRefPtr<AndroidAnimation> copy();
 
     virtual void applyForProgress(LayerAndroid* layer, float progress);
 };
@@ -96,9 +94,6 @@
                               KeyframeValueList* operations,
                               double beginTime);
 
-    AndroidTransformAnimation(AndroidTransformAnimation* anim);
-    virtual PassRefPtr<AndroidAnimation> copy();
-
     virtual void applyForProgress(LayerAndroid* layer, float progress);
 };
 
diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
index 8358b2a..9c7716c 100644
--- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
@@ -264,6 +264,7 @@
     // the two pages (current one and future one with the new scale factor)
     if (zoomManager->didReceivedRequest()) {
         float nextTiledPageTransparency = 1;
+        m_state->resetFrameworkInval();
         zoomManager->processTransition(currentTime, scale, &doZoomPageSwap,
                                        &nextTiledPageTransparency, &transparency);
         nextTiledPage->prepareForDrawGL(nextTiledPageTransparency, viewportTileBounds);
@@ -370,8 +371,7 @@
         updateLayerPositions(visibleRect);
         // For now, we render layers only if the rendering mode
         // is kAllTextures or kClippedTextures
-        if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers
-            && compositedRoot->drawGL()) {
+        if (compositedRoot->drawGL()) {
             if (TilesManager::instance()->layerTexturesRemain()) {
                 // only try redrawing for layers if layer textures remain,
                 // otherwise we'll repaint without getting anything done
diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp
index a331dfc..27bd482 100644
--- a/Source/WebCore/platform/graphics/android/BaseTile.cpp
+++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp
@@ -204,6 +204,7 @@
         }
         cliperator.next();
     }
+
     if (!intersect)
         return;
 
@@ -268,7 +269,7 @@
     }
 
     if (m_frontTexture->readyFor(this)) {
-        if (isLayerTile())
+        if (isLayerTile() && m_painter && m_painter->transform())
             TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(),
                                                               rect, m_frontTexture->m_ownTextureId,
                                                               transparency, true);
diff --git a/Source/WebCore/platform/graphics/android/ClassTracker.cpp b/Source/WebCore/platform/graphics/android/ClassTracker.cpp
index 92d406c..eb810a8 100644
--- a/Source/WebCore/platform/graphics/android/ClassTracker.cpp
+++ b/Source/WebCore/platform/graphics/android/ClassTracker.cpp
@@ -27,6 +27,7 @@
 #include "ClassTracker.h"
 
 #include "LayerAndroid.h"
+#include "TilesManager.h"
 
 #include <cutils/log.h>
 #include <wtf/CurrentTime.h>
@@ -35,6 +36,9 @@
 #undef XLOG
 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ClassTracker", __VA_ARGS__)
 
+#define DEBUG_LAYERS
+#undef DEBUG_LAYERS
+
 namespace WebCore {
 
 ClassTracker* ClassTracker::instance()
@@ -66,7 +70,6 @@
    m_classes.set(name, value - 1);
 }
 
-
 void ClassTracker::add(LayerAndroid* layer)
 {
    android::Mutex::Autolock lock(m_lock);
@@ -88,6 +91,21 @@
             iter->first.latin1().data(), iter->second);
    }
    XLOG("*** %d Layers ***", m_layers.size());
+   int nbTextures = 0;
+   int nbAllocatedTextures = 0;
+   int nbLayerTextures = 0;
+   int nbAllocatedLayerTextures = 0;
+   float textureSize = 256 * 256 * 4 / 1024.0 / 1024.0;
+   TilesManager::instance()->gatherTexturesNumbers(&nbTextures, &nbAllocatedTextures,
+                                                   &nbLayerTextures, &nbAllocatedLayerTextures);
+   XLOG("*** textures: %d/%d (%.2f Mb), layer textures: %d/%d (%.2f Mb) : total used %.2f Mb",
+        nbAllocatedTextures, nbTextures,
+        nbAllocatedTextures * textureSize,
+        nbAllocatedLayerTextures, nbLayerTextures,
+        nbAllocatedLayerTextures * textureSize,
+        (nbAllocatedTextures + nbAllocatedLayerTextures) * textureSize);
+
+#ifdef DEBUG_LAYERS
    for (unsigned int i = 0; i < m_layers.size(); i++) {
        LayerAndroid* layer = m_layers[i];
        XLOG("[%d/%d] layer %x (%.2f, %.2f) of type %d, refcount(%d) has texture %x has image ref %x (%x) root: %x parent: %x",
@@ -98,6 +116,7 @@
             layer->imageTexture(), (LayerAndroid*) layer->getRootLayer(),
             (LayerAndroid*) layer->getParent());
    }
+#endif
 }
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/FontAndroid.cpp b/Source/WebCore/platform/graphics/android/FontAndroid.cpp
index 81dbdae..0a8c0c1 100644
--- a/Source/WebCore/platform/graphics/android/FontAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/FontAndroid.cpp
@@ -98,6 +98,10 @@
         SkLayerDrawLooper* looper = new SkLayerDrawLooper;
         paint->setLooper(looper)->unref();
 
+        // The layerDrawLooper uses at the root paint to determine the text
+        // encoding so we need to make sure it is properly configured.
+        updateForFont(paint, font);
+
         // Specify the behavior of the looper
         SkLayerDrawLooper::LayerInfo info;
         info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits;
diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp
index d1fe51a..97a53fe 100644
--- a/Source/WebCore/platform/graphics/android/GLUtils.cpp
+++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp
@@ -562,6 +562,15 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
 }
 
+void GLUtils::convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix)
+{
+    transformMatrix.setMatrix(
+        matrix[0], matrix[1], matrix[2], matrix[3],
+        matrix[4], matrix[5], matrix[6], matrix[7],
+        matrix[8], matrix[9], matrix[10], matrix[11],
+        matrix[12], matrix[13], matrix[14], matrix[15]);
+}
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h
index b952513..68acbab 100644
--- a/Source/WebCore/platform/graphics/android/GLUtils.h
+++ b/Source/WebCore/platform/graphics/android/GLUtils.h
@@ -83,6 +83,7 @@
     static void updateSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap, GLint filter  = GL_LINEAR);
 #endif
     static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap);
+    static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix);
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
index 5206b7a..273c478 100644
--- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
+++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
@@ -84,9 +84,9 @@
     , m_goingLeft(false)
     , m_expandedTileBoundsX(0)
     , m_expandedTileBoundsY(0)
+    , m_highEndGfx(false)
     , m_scale(1)
     , m_layersRenderingMode(kAllTextures)
-    , m_highEndGfx(false)
 {
     m_viewport.setEmpty();
     m_futureViewportTileBounds.setEmpty();
@@ -150,8 +150,10 @@
     TilesManager::instance()->setShowVisualIndicator(showVisualIndicator);
 }
 
-void GLWebViewState::scrolledLayer(ScrollableLayerAndroid*)
+void GLWebViewState::scrollLayer(int layerId, int x, int y)
 {
+    m_treeManager.updateScrollableLayer(layerId, x, y);
+
     // TODO: only inval the area of the scrolled layer instead of
     // doing a fullInval()
     if (m_layersRenderingMode == kSingleSurfaceRendering)
@@ -335,20 +337,25 @@
     int top = viewRect.y();
     int width = viewRect.width();
     int height = viewRect.height();
-    glViewport(left, top, width, height);
 
     ShaderProgram* shader = TilesManager::instance()->shader();
     if (shader->program() == -1) {
         XLOG("Reinit shader");
         shader->init();
     }
+    shader->setViewport(visibleRect, scale);
     shader->setViewRect(viewRect);
-    shader->setViewport(visibleRect);
     shader->setWebViewRect(webViewRect);
     shader->setTitleBarHeight(titleBarHeight);
     shader->setScreenClip(screenClip);
     shader->resetBlending();
 
+    shader->calculateAnimationDelta();
+
+    glViewport(left + shader->getAnimationDeltaX(),
+               top - shader->getAnimationDeltaY(),
+               width, height);
+
     double currentTime = WTF::currentTime();
 
     setViewport(visibleRect, scale);
@@ -379,6 +386,9 @@
     if (nbTexturesNeeded.full < maxTextures)
         m_layersRenderingMode = kAllTextures;
 
+    if (!maxTextures && !nbTexturesNeeded.full)
+        m_layersRenderingMode = kAllTextures;
+
     if (m_layersRenderingMode < layersRenderingMode
         && m_layersRenderingMode != kAllTextures)
         invalBase = true;
@@ -428,7 +438,8 @@
 
 bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                             IntRect& webViewRect, int titleBarHeight,
-                            IntRect& clip, float scale, bool* buffersSwappedPtr)
+                            IntRect& clip, float scale,
+                            bool* treesSwappedPtr, bool* newTreeHasAnimPtr)
 {
     m_scale = scale;
     TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
@@ -470,7 +481,7 @@
     // Upload any pending ImageTexture
     // Return true if we still have some images to upload.
     // TODO: upload as many textures as possible within a certain time limit
-    bool ret = ImagesManager::instance()->uploadTextures();
+    bool ret = ImagesManager::instance()->prepareTextures(this);
 
     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
         XLOGC("WARNING, scale seems corrupted after update: %e", scale);
@@ -485,10 +496,18 @@
     bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering;
     ret |= m_treeManager.drawGL(currentTime, rect, viewport,
                                 scale, fastSwap,
-                                buffersSwappedPtr, &nbTexturesNeeded);
+                                treesSwappedPtr, newTreeHasAnimPtr,
+                                &nbTexturesNeeded);
     if (!ret)
         resetFrameworkInval();
 
+    int nbTexturesForImages = ImagesManager::instance()->nbTextures();
+    XLOG("*** We have %d textures for images, %d full, %d clipped, total %d / %d",
+          nbTexturesForImages, nbTexturesNeeded.full, nbTexturesNeeded.clipped,
+          nbTexturesNeeded.full + nbTexturesForImages,
+          nbTexturesNeeded.clipped + nbTexturesForImages);
+    nbTexturesNeeded.full += nbTexturesForImages;
+    nbTexturesNeeded.clipped += nbTexturesForImages;
     ret |= setLayersRenderingMode(nbTexturesNeeded);
 
     FloatRect extrasclip(0, 0, rect.width(), rect.height());
diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h
index 2a6c8df..8d89704 100644
--- a/Source/WebCore/platform/graphics/android/GLWebViewState.h
+++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h
@@ -214,7 +214,8 @@
 
     bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                 IntRect& webViewRect, int titleBarHeight,
-                IntRect& clip, float scale, bool* buffersSwappedPtr);
+                IntRect& clip, float scale,
+                bool* treesSwappedPtr, bool* newTreeHasAnimPtr);
 
 #ifdef MEASURES_PERF
     void dumpMeasures();
@@ -247,7 +248,7 @@
     };
 
     LayersRenderingMode layersRenderingMode() { return m_layersRenderingMode; }
-    void scrolledLayer(ScrollableLayerAndroid*);
+    void scrollLayer(int layerId, int x, int y);
 
     void invalRegion(const SkRegion& region);
 
diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
index 3e062f8..6990503 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
@@ -119,8 +119,8 @@
     m_needsRepaint(false),
     m_needsNotifyClient(false),
     m_haveContents(false),
-    m_haveImage(false),
     m_newImage(false),
+    m_image(0),
     m_foregroundLayer(0),
     m_foregroundClipLayer(0)
 {
@@ -132,6 +132,9 @@
 
 GraphicsLayerAndroid::~GraphicsLayerAndroid()
 {
+    if (m_image)
+        m_image->deref();
+
     m_contentLayer->unref();
     SkSafeUnref(m_foregroundLayer);
     SkSafeUnref(m_foregroundClipLayer);
@@ -331,6 +334,9 @@
 
 void GraphicsLayerAndroid::setBackfaceVisibility(bool b)
 {
+    if (b == m_backfaceVisibility)
+        return;
+
     GraphicsLayer::setBackfaceVisibility(b);
     m_contentLayer->setBackfaceVisibility(b);
     askForSync();
@@ -397,7 +403,7 @@
 
 void GraphicsLayerAndroid::setBackgroundColor(const Color& color)
 {
-    if (color == m_backgroundColor)
+    if (color == m_backgroundColor && m_backgroundColorSet)
         return;
     LOG("(%x) setBackgroundColor", this);
     GraphicsLayer::setBackgroundColor(color);
@@ -409,6 +415,9 @@
 
 void GraphicsLayerAndroid::clearBackgroundColor()
 {
+    if (!m_backgroundColorSet)
+        return;
+
     LOG("(%x) clearBackgroundColor", this);
     GraphicsLayer::clearBackgroundColor();
     askForSync();
@@ -551,7 +560,7 @@
     LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ",
         this, gPaused, m_needsRepaint, m_haveContents);
 
-    if (!gPaused && m_haveContents && m_needsRepaint && !m_haveImage) {
+    if (!gPaused && m_haveContents && m_needsRepaint && !m_image) {
         // with SkPicture, we request the entire layer's content.
         IntRect layerBounds(0, 0, m_size.width(), m_size.height());
 
@@ -602,7 +611,14 @@
             m_foregroundLayer->setPosition(-x, -y);
             // Set the scrollable bounds of the layer.
             m_foregroundLayer->setScrollLimits(-x, -y, m_size.width(), m_size.height());
-            m_foregroundLayer->markAsDirty(m_dirtyRegion);
+
+            // Invalidate the entire layer for now, as webkit will only send the
+            // setNeedsDisplayInRect() for the visible (clipped) scrollable area,
+            // offsetting the invals by the scroll position would not be enough.
+            // TODO: have webkit send us invals even for non visible area
+            SkRegion region;
+            region.setRect(0, 0, contentsRect.width(), contentsRect.height());
+            m_foregroundLayer->markAsDirty(region);
             m_foregroundLayer->needsRepaint();
         } else {
             // If there is no contents clip, we can draw everything into one
@@ -633,7 +649,7 @@
 
         return true;
     }
-    if (m_needsRepaint && m_haveImage && m_newImage) {
+    if (m_needsRepaint && m_image && m_newImage) {
         // We need to tell the GL thread that we will need to repaint the
         // texture. Only do so if we effectively have a new image!
         m_contentLayer->markAsDirty(m_dirtyRegion);
@@ -666,7 +682,7 @@
 {
     // rect is in the render object coordinates
 
-    if (!m_haveImage && !drawsContent()) {
+    if (!m_image && !drawsContent()) {
         LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...",
             this, rect.x(), rect.y(), rect.width(), rect.height());
         return;
@@ -830,14 +846,23 @@
 void GraphicsLayerAndroid::setContentsToImage(Image* image)
 {
     TLOG("(%x) setContentsToImage", this, image);
-    if (image) {
+    if (image && image != m_image) {
+        image->ref();
+        if (m_image)
+            m_image->deref();
+        m_image = image;
+
+        SkBitmapRef* bitmap = image->nativeImageForCurrentFrame();
+        m_contentLayer->setContentsImage(bitmap);
+
         m_haveContents = true;
-        m_haveImage = true;
         m_newImage = true;
-        m_contentLayer->setContentsImage(image->nativeImageForCurrentFrame());
     }
-    if (m_haveImage && !image)
+    if (!image && m_image) {
         m_contentLayer->setContentsImage(0);
+        m_image->deref();
+        m_image = 0;
+    }
 
     setNeedsDisplay();
     askForSync();
diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
index af8d7ce..358f674 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
@@ -145,8 +145,8 @@
     bool m_needsNotifyClient;
 
     bool m_haveContents;
-    bool m_haveImage;
     bool m_newImage;
+    Image* m_image;
 
     SkRegion m_dirtyRegion;
 
diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.cpp b/Source/WebCore/platform/graphics/android/ImageTexture.cpp
index 96f7713..23e3899 100644
--- a/Source/WebCore/platform/graphics/android/ImageTexture.cpp
+++ b/Source/WebCore/platform/graphics/android/ImageTexture.cpp
@@ -27,8 +27,11 @@
 #include "ImageTexture.h"
 
 #include "ImagesManager.h"
+#include "LayerAndroid.h"
 #include "SkDevice.h"
+#include "SkPicture.h"
 #include "TilesManager.h"
+#include "TiledTexture.h"
 
 #include <cutils/log.h>
 #include <wtf/CurrentTime.h>
@@ -51,33 +54,57 @@
 
 namespace WebCore {
 
-ImageTexture::ImageTexture(SkBitmapRef* img)
-    : m_imageRef(img)
-    , m_image(0)
-    , m_textureId(0)
-    , m_refCount(0)
+// CRC computation adapted from Tools/DumpRenderTree/CyclicRedundancyCheck.cpp
+static void makeCrcTable(unsigned crcTable[256])
+{
+    for (unsigned i = 0; i < 256; i++) {
+        unsigned c = i;
+        for (int k = 0; k < 8; k++) {
+            if (c & 1)
+                c = -306674912 ^ ((c >> 1) & 0x7fffffff);
+            else
+                c = c >> 1;
+        }
+        crcTable[i] = c;
+    }
+}
+
+unsigned computeCrc(uint8_t* buffer, size_t size)
+{
+    static unsigned crcTable[256];
+    static bool crcTableComputed = false;
+    if (!crcTableComputed) {
+        makeCrcTable(crcTable);
+        crcTableComputed = true;
+    }
+
+    unsigned crc = 0xffffffffL;
+    for (size_t i = 0; i < size; ++i)
+        crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL);
+    return crc ^ 0xffffffffL;
+}
+
+ImageTexture::ImageTexture(SkBitmap* bmp, unsigned crc)
+    : m_image(bmp)
+    , m_texture(0)
+    , m_layer(0)
+    , m_picture(0)
+    , m_crc(crc)
 {
 #ifdef DEBUG_COUNT
     ClassTracker::instance()->increment("ImageTexture");
 #endif
-    if (!m_imageRef)
+    if (!m_image)
         return;
 
-    SkBitmap* bitmap = &m_imageRef->bitmap();
-    m_image = new SkBitmap();
-    int w = bitmap->width();
-    int h = bitmap->height();
-    m_image->setConfig(SkBitmap::kARGB_8888_Config, w, h);
-    m_image->allocPixels();
-    SkDevice* device = new SkDevice(NULL, *m_image, false);
-    SkCanvas canvas;
-    canvas.setDevice(device);
-    device->unref();
-    SkRect dest;
-    dest.set(0, 0, w, h);
-    m_image->setIsOpaque(false);
-    m_image->eraseARGB(0, 0, 0, 0);
-    canvas.drawBitmapRect(*bitmap, 0, dest);
+    // NOTE: This constructor is called on the webcore thread
+
+    // Create a picture containing the image (needed for TiledTexture)
+    m_picture = new SkPicture();
+    SkCanvas* pcanvas = m_picture->beginRecording(m_image->width(), m_image->height());
+    pcanvas->clear(SkColorSetARGBInline(0, 0, 0, 0));
+    pcanvas->drawBitmap(*m_image, 0, 0);
+    m_picture->endRecording();
 }
 
 ImageTexture::~ImageTexture()
@@ -86,61 +113,142 @@
     ClassTracker::instance()->decrement("ImageTexture");
 #endif
     delete m_image;
+    delete m_texture;
+    SkSafeUnref(m_picture);
 }
 
-void ImageTexture::prepareGL()
+SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap)
 {
-    if (m_textureId)
-        return;
+    SkBitmap* img = new SkBitmap();
+    int w = bitmap->width();
+    int h = bitmap->height();
 
-    ImagesManager::instance()->scheduleTextureUpload(this);
+    // Create a copy of the image
+    img->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+    img->allocPixels();
+    SkDevice* device = new SkDevice(NULL, *img, false);
+    SkCanvas canvas;
+    canvas.setDevice(device);
+    device->unref();
+    SkRect dest;
+    dest.set(0, 0, w, h);
+    img->setIsOpaque(false);
+    img->eraseARGB(0, 0, 0, 0);
+    canvas.drawBitmapRect(*bitmap, 0, dest);
+
+    return img;
 }
 
-void ImageTexture::uploadGLTexture()
+unsigned ImageTexture::computeCRC(const SkBitmap* bitmap)
 {
-    if (m_textureId)
-        return;
+    if (!bitmap)
+        return 0;
+    bitmap->lockPixels();
+    uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels());
+    unsigned crc = computeCrc(img, bitmap->getSize());
+    bitmap->unlockPixels();
+    return crc;
+}
 
-    glGenTextures(1, &m_textureId);
-    GLUtils::createTextureWithBitmap(m_textureId, *m_image);
+bool ImageTexture::equalsCRC(unsigned crc)
+{
+    return m_crc == crc;
+}
+
+int ImageTexture::nbTextures()
+{
+    if (!hasContentToShow())
+        return 0;
+    if (!m_texture)
+        return 0;
+
+    // TODO: take in account the visible clip (need to maintain
+    // a list of the clients layer, etc.)
+    IntRect visibleArea(0, 0, m_image->width(), m_image->height());
+    int nbTextures = m_texture->nbTextures(visibleArea, 1.0);
+    XLOG("ImageTexture %p, %d x %d needs %d textures",
+          this, m_image->width(), m_image->height(),
+          nbTextures);
+    return nbTextures;
+}
+
+bool ImageTexture::hasContentToShow()
+{
+    // Don't display 1x1 image -- no need to allocate a full texture for this
+    if (!m_image)
+        return false;
+    if (m_image->width() == 1 && m_image->height() == 1)
+        return false;
+    return true;
+}
+
+bool ImageTexture::prepareGL(GLWebViewState* state)
+{
+    if (!hasContentToShow())
+        return false;
+
+    if (!m_texture && m_picture) {
+        m_texture = new TiledTexture(this);
+        SkRegion region;
+        region.setRect(0, 0, m_image->width(), m_image->height());
+        m_texture->update(region, m_picture);
+    }
+
+    if (!m_texture)
+        return false;
+
+    IntRect visibleArea(0, 0, m_image->width(), m_image->height());
+    m_texture->prepare(state, 1.0, true, true, visibleArea);
+    if (m_texture->ready()) {
+        m_texture->swapTiles();
+        return false;
+    }
+    return true;
+}
+
+const TransformationMatrix* ImageTexture::transform()
+{
+    if (!m_layer)
+        return 0;
+
+    FloatPoint p(0, 0);
+    p = m_layer->drawTransform()->mapPoint(p);
+    IntRect layerArea = m_layer->unclippedArea();
+    float scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width());
+    float scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height());
+    TransformationMatrix d = *(m_layer->drawTransform());
+    TransformationMatrix m;
+    m.scaleNonUniform(scaleW, scaleH);
+    m_layerMatrix = d.multiply(m);
+    return &m_layerMatrix;
+}
+
+float ImageTexture::opacity()
+{
+    if (!m_layer)
+        return 1.0;
+    return m_layer->drawOpacity();
 }
 
 void ImageTexture::drawGL(LayerAndroid* layer)
 {
     if (!layer)
         return;
-    if (!m_textureId)
-        return;
-    if (!m_image)
+    if (!hasContentToShow())
         return;
 
-    SkRect rect;
-    rect.fLeft = 0;
-    rect.fTop = 0;
-    rect.fRight = layer->getSize().width();
-    rect.fBottom = layer->getSize().height();
-    TilesManager::instance()->shader()->drawLayerQuad(*layer->drawTransform(),
-                                                      rect, m_textureId,
-                                                      layer->drawOpacity(), true);
+    // TiledTexture::draw() will call us back to know the
+    // transform and opacity, so we need to set m_layer
+    m_layer = layer;
+    if (m_texture)
+        m_texture->draw();
+    m_layer = 0;
 }
 
 void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect)
 {
-    canvas->drawBitmapRect(*m_image, 0, rect);
-}
-
-void ImageTexture::release()
-{
-    if (m_refCount >= 1)
-        m_refCount--;
-    if (!m_refCount)
-        deleteTexture();
-}
-
-void ImageTexture::deleteTexture()
-{
-   if (m_textureId)
-       glDeleteTextures(1, &m_textureId);
+    if (canvas && m_image)
+        canvas->drawBitmapRect(*m_image, 0, rect);
 }
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.h b/Source/WebCore/platform/graphics/android/ImageTexture.h
index cea79c3..6c6a075 100644
--- a/Source/WebCore/platform/graphics/android/ImageTexture.h
+++ b/Source/WebCore/platform/graphics/android/ImageTexture.h
@@ -29,57 +29,78 @@
 #include "GLUtils.h"
 #include "SkBitmap.h"
 #include "SkBitmapRef.h"
+#include "SkPicture.h"
 #include "SkRefCnt.h"
 #include "LayerAndroid.h"
 
 namespace WebCore {
 
 class LayerAndroid;
+class TexturesResult;
+class TiledTexture;
 
 /////////////////////////////////////////////////////////////////////////////////
 // Image sharing codepath for layers
 /////////////////////////////////////////////////////////////////////////////////
 //
-// We receive an SkBitmapRef on the webcore thread; from this we create
-// an ImageTexture instance and keep it in TilesManager in a hashmap
-// (see TilesManager::addImage())
+// Layers containing only an image take a slightly different codepath;
+// GraphicsLayer::setContentsToImage() is called on the webcore thread,
+// passing an Image instance. We get the native image (an SkBitmap) and create
+// an ImageTexture instance with it (or increment the refcount of an existing
+// instance if the SkBitmap is similar to one already stored in ImagesManager,
+// i.e. if two GraphicsLayer share the same image).
 //
-// The ImageTexture will recopy the pointed SkBitmap locally (so we can safely
-// use it on the texture generation thread), and just use the SkBitmapRef as a
-// key.
+// To detect if an image is similar, we compute and use a CRC. Each ImageTexture
+// is stored in ImagesManager using its CRC as a hash key.
+// Simply comparing the address is not enough -- different image could end up
+// at the same address (i.e. the image is deallocated then a new one is
+// reallocated at the old address)
 //
-// Layers on the shared image path will ask TilesManager for the corresponding
-// ImageTexture, instead of using a PaintedSurface+TiledTexture.
-// When the ImageTexture is prepared for the first time, we directly upload
-// the bitmap to a texture.
+// Each ImageTexture's CRC being unique, LayerAndroid instances simply store that
+// and retain/release the corresponding ImageTexture (so that
+// queued painting request will work correctly and not crash...).
+// LayerAndroid running on the UI thread will get the corresponding
+// ImageTexture at draw time.
 //
-// TODO: limit how many ImageTextures can be uploaded in one draw cycle
-// TODO: limit the size of ImageTextures (use a TiledTexture when needed)
+// ImageTexture recopy the original SkBitmap so that they can safely be used
+// on a different thread; it uses TiledTexture to allocate and paint the image,
+// so that we can share the same textures and limits as the rest of the layers.
 //
 /////////////////////////////////////////////////////////////////////////////////
-class ImageTexture {
+class ImageTexture : public SurfacePainter {
 public:
-    ImageTexture(SkBitmapRef* img);
+    ImageTexture(SkBitmap* bmp, unsigned crc);
     virtual ~ImageTexture();
 
-    void prepareGL();
-    void uploadGLTexture();
+    bool prepareGL(GLWebViewState*);
     void drawGL(LayerAndroid* painter);
     void drawCanvas(SkCanvas*, SkRect&);
-    void retain() { m_refCount++; }
-    void release();
-    unsigned int refCount() { return m_refCount; }
-    SkBitmapRef* imageRef() { return m_imageRef; }
+    bool hasContentToShow();
     SkBitmap* bitmap() { return m_image; }
+    unsigned imageCRC() { return m_crc; }
+
+    static SkBitmap* convertBitmap(SkBitmap* bitmap);
+
+    static unsigned computeCRC(const SkBitmap* bitmap);
+    bool equalsCRC(unsigned crc);
+
+    // methods used by TiledTexture
+    virtual const TransformationMatrix* transform();
+    virtual float opacity();
+
+    int nbTextures();
+
+    virtual SurfaceType type() { return SurfacePainter::ImageSurface; }
 
 private:
 
-    void deleteTexture();
-
     SkBitmapRef* m_imageRef;
     SkBitmap* m_image;
-    GLuint m_textureId;
-    unsigned int m_refCount;
+    TiledTexture* m_texture;
+    LayerAndroid* m_layer;
+    SkPicture* m_picture;
+    TransformationMatrix m_layerMatrix;
+    unsigned m_crc;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.cpp b/Source/WebCore/platform/graphics/android/ImagesManager.cpp
index 21f9fe9..65c41d1 100644
--- a/Source/WebCore/platform/graphics/android/ImagesManager.cpp
+++ b/Source/WebCore/platform/graphics/android/ImagesManager.cpp
@@ -26,6 +26,9 @@
 #include "config.h"
 #include "ImagesManager.h"
 
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkRefCnt.h"
 #include "ImageTexture.h"
 
 #include <cutils/log.h>
@@ -59,71 +62,88 @@
 
 ImagesManager* ImagesManager::gInstance = 0;
 
-void ImagesManager::addImage(SkBitmapRef* imgRef)
+ImageTexture* ImagesManager::setImage(SkBitmapRef* imgRef)
 {
     if (!imgRef)
-        return;
+        return 0;
 
-    android::Mutex::Autolock lock(m_imagesLock);
-    if (!m_images.contains(imgRef))
-        m_images.set(imgRef, new ImageTexture(imgRef));
-}
+    SkBitmap* bitmap = &imgRef->bitmap();
+    ImageTexture* image = 0;
+    SkBitmap* img = 0;
+    unsigned crc = 0;
 
-void ImagesManager::removeImage(SkBitmapRef* imgRef)
-{
-    android::Mutex::Autolock lock(m_imagesLock);
-    if (!m_images.contains(imgRef))
-        return;
+    img = ImageTexture::convertBitmap(bitmap);
+    crc = ImageTexture::computeCRC(img);
 
-    ImageTexture* image = m_images.get(imgRef);
-    image->release();
-
-    if (!image->refCount()) {
-        m_images.remove(imgRef);
-        delete image;
+    {
+        android::Mutex::Autolock lock(m_imagesLock);
+        if (m_images.contains(crc)) {
+            image = m_images.get(crc);
+            SkSafeRef(image);
+            return image;
+        }
     }
-}
 
-void ImagesManager::showImages()
-{
-    XLOGC("We have %d images", m_images.size());
-    HashMap<SkBitmapRef*, ImageTexture*>::iterator end = m_images.end();
-    int i = 0;
-    for (HashMap<SkBitmapRef*, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) {
-        XLOGC("Image %x (%d/%d) has %d references", it->first, i,
-              m_images.size(), it->second->refCount());
-        i++;
-    }
-}
+    // the image is not in the map, we add it
 
-ImageTexture* ImagesManager::getTextureForImage(SkBitmapRef* img, bool retain)
-{
+    image = new ImageTexture(img, crc);
+
     android::Mutex::Autolock lock(m_imagesLock);
-    ImageTexture* image = m_images.get(img);
-    if (retain && image)
-        image->retain();
+    m_images.set(crc, image);
+
     return image;
 }
 
-void ImagesManager::scheduleTextureUpload(ImageTexture* texture)
+ImageTexture* ImagesManager::retainImage(unsigned imgCRC)
 {
-    if (m_imagesToUpload.contains(texture))
-        return;
+    if (!imgCRC)
+        return 0;
 
-    texture->retain();
-    m_imagesToUpload.append(texture);
+    android::Mutex::Autolock lock(m_imagesLock);
+    ImageTexture* image = 0;
+    if (m_images.contains(imgCRC)) {
+        image = m_images.get(imgCRC);
+        SkSafeRef(image);
+    }
+    return image;
 }
 
-bool ImagesManager::uploadTextures()
+void ImagesManager::releaseImage(unsigned imgCRC)
 {
-    // scheduleUpload and uploadTextures are called on the same thread
-    if (!m_imagesToUpload.size())
-        return false;
-    ImageTexture* texture = m_imagesToUpload.last();
-    texture->uploadGLTexture();
-    m_imagesToUpload.removeLast();
-    removeImage(texture->imageRef());
-    return m_imagesToUpload.size();
+    if (!imgCRC)
+        return;
+
+    android::Mutex::Autolock lock(m_imagesLock);
+    if (m_images.contains(imgCRC)) {
+        ImageTexture* image = m_images.get(imgCRC);
+        if (image->getRefCnt() == 1)
+            m_images.remove(imgCRC);
+        SkSafeUnref(image);
+    }
+}
+
+int ImagesManager::nbTextures()
+{
+    android::Mutex::Autolock lock(m_imagesLock);
+    HashMap<unsigned, ImageTexture*>::iterator end = m_images.end();
+    int i = 0;
+    int nb = 0;
+    for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) {
+        nb += it->second->nbTextures();
+        i++;
+    }
+    return nb;
+}
+
+bool ImagesManager::prepareTextures(GLWebViewState* state)
+{
+    bool ret = false;
+    android::Mutex::Autolock lock(m_imagesLock);
+    HashMap<unsigned, ImageTexture*>::iterator end = m_images.end();
+    for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) {
+        ret |= it->second->prepareGL(state);
+    }
+    return ret;
 }
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.h b/Source/WebCore/platform/graphics/android/ImagesManager.h
index 2fcb9fd..a3ea859 100644
--- a/Source/WebCore/platform/graphics/android/ImagesManager.h
+++ b/Source/WebCore/platform/graphics/android/ImagesManager.h
@@ -35,17 +35,18 @@
 namespace WebCore {
 
 class ImageTexture;
+class GLWebViewState;
 
 class ImagesManager {
 public:
     static ImagesManager* instance();
 
-    void addImage(SkBitmapRef* img);
-    void removeImage(SkBitmapRef* img);
-    ImageTexture* getTextureForImage(SkBitmapRef* img, bool retain = true);
-    void showImages();
-    void scheduleTextureUpload(ImageTexture* texture);
-    bool uploadTextures();
+    ImageTexture* setImage(SkBitmapRef* imgRef);
+    ImageTexture* retainImage(unsigned imgCRC);
+    void releaseImage(unsigned imgCRC);
+
+    bool prepareTextures(GLWebViewState*);
+    int nbTextures();
 
 private:
     ImagesManager() {}
@@ -53,8 +54,7 @@
     static ImagesManager* gInstance;
 
     android::Mutex m_imagesLock;
-    HashMap<SkBitmapRef*, ImageTexture*> m_images;
-    Vector<ImageTexture*> m_imagesToUpload;
+    HashMap<unsigned, ImageTexture*> m_images;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
index 9e7626a..962bcdf 100644
--- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -149,8 +149,7 @@
     m_recordingPicture(0),
     m_uniqueId(++gUniqueId),
     m_texture(0),
-    m_imageRef(0),
-    m_imageTexture(0),
+    m_imageCRC(0),
     m_pictureUsed(0),
     m_scale(1),
     m_lastComputeTextureSize(0),
@@ -174,15 +173,15 @@
     m_isIframe(layer.m_isIframe),
     m_uniqueId(layer.m_uniqueId),
     m_texture(0),
-    m_imageTexture(0),
     m_owningLayer(layer.m_owningLayer),
     m_type(LayerAndroid::UILayer),
     m_hasText(true)
 {
     m_isFixed = layer.m_isFixed;
-    m_imageRef = layer.m_imageRef;
-    if (m_imageRef)
-        ImagesManager::instance()->addImage(m_imageRef);
+    m_imageCRC = layer.m_imageCRC;
+    if (m_imageCRC)
+        ImagesManager::instance()->retainImage(m_imageCRC);
+
     m_renderLayerPos = layer.m_renderLayerPos;
     m_transform = layer.m_transform;
     m_backfaceVisibility = layer.m_backfaceVisibility;
@@ -216,14 +215,13 @@
 
     KeyframesMap::const_iterator end = layer.m_animations.end();
     for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it) {
-        pair<String, int> key((it->second)->name(), (it->second)->type());
-        m_animations.add(key, (it->second)->copy());
+        m_animations.add(it->first, it->second);
     }
 
     m_hasText = layer.m_hasText;
 
 #ifdef DEBUG_COUNT
-    ClassTracker::instance()->increment("LayerAndroid - recopy (UI?)");
+    ClassTracker::instance()->increment("LayerAndroid - recopy (UI)");
     ClassTracker::instance()->add(this);
 #endif
 }
@@ -252,8 +250,7 @@
     m_recordingPicture(picture),
     m_uniqueId(++gUniqueId),
     m_texture(0),
-    m_imageRef(0),
-    m_imageTexture(0),
+    m_imageCRC(0),
     m_scale(1),
     m_lastComputeTextureSize(0),
     m_owningLayer(0),
@@ -272,8 +269,9 @@
 
 LayerAndroid::~LayerAndroid()
 {
-    if (m_imageTexture)
-        ImagesManager::instance()->removeImage(m_imageTexture->imageRef());
+    if (m_imageCRC)
+        ImagesManager::instance()->releaseImage(m_imageCRC);
+
     SkSafeUnref(m_recordingPicture);
     m_animations.clear();
 #ifdef DEBUG_COUNT
@@ -326,6 +324,17 @@
     return hasRunningAnimations || m_hasRunningAnimations;
 }
 
+void LayerAndroid::initAnimations() {
+    // tell auto-initializing animations to start now
+    for (int i = 0; i < countChildren(); i++)
+        getChild(i)->initAnimations();
+
+    KeyframesMap::const_iterator localBegin = m_animations.begin();
+    KeyframesMap::const_iterator localEnd = m_animations.end();
+    for (KeyframesMap::const_iterator localIt = localBegin; localIt != localEnd; ++localIt)
+        (localIt->second)->suggestBeginTime(WTF::currentTime());
+}
+
 void LayerAndroid::addDirtyArea()
 {
     IntSize layerSize(getSize().width(), getSize().height());
@@ -370,7 +379,7 @@
     }
 
     for (unsigned int i = 0; i < toDelete.size(); i++)
-            m_animations.remove(toDelete[i]);
+        m_animations.remove(toDelete[i]);
 }
 
 // We only use the bounding rect of the layer as mask...
@@ -761,16 +770,14 @@
 
 void LayerAndroid::setContentsImage(SkBitmapRef* img)
 {
-    m_imageRef = img;
-    if (!img)
-        return;
-
-    ImagesManager::instance()->addImage(img);
+    ImageTexture* image = ImagesManager::instance()->setImage(img);
+    ImagesManager::instance()->releaseImage(m_imageCRC);
+    m_imageCRC = image ? image->imageCRC() : 0;
 }
 
 bool LayerAndroid::needsTexture()
 {
-    return m_imageRef || (m_recordingPicture
+    return m_imageCRC || (m_recordingPicture
         && m_recordingPicture->width() && m_recordingPicture->height());
 }
 
@@ -841,10 +848,11 @@
     IntRect visible = visibleArea();
     IntRect clip(m_clippingRect.x(), m_clippingRect.y(),
                  m_clippingRect.width(), m_clippingRect.height());
-    XLOGC("%s [%d:0x%x] - %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) "
+    XLOGC("%s [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) "
           "clip (%d, %d, %d, %d) %s %s prepareContext(%x), pic w: %d h: %d",
           spaces, uniqueId(), m_owningLayer,
           needsTexture() ? "needs a texture" : "no texture",
+          m_imageCRC ? "has an image" : "no image",
           tr.x(), tr.y(), tr.width(), tr.height(),
           visible.x(), visible.y(), visible.width(), visible.height(),
           clip.x(), clip.y(), clip.width(), clip.height(),
@@ -889,7 +897,12 @@
     for (int i = 0; i < count; i++)
         this->getChild(i)->setIsPainting(drawingTree);
 
-    obtainTextureForPainting(static_cast<LayerAndroid*>(drawingTree));
+
+    LayerAndroid* drawingLayer = 0;
+    if (drawingTree)
+        drawingLayer = static_cast<LayerAndroid*>(drawingTree)->findById(uniqueId());
+
+    obtainTextureForPainting(drawingLayer);
 }
 
 void LayerAndroid::mergeInvalsInto(Layer* replacementTree)
@@ -950,38 +963,31 @@
     m_opacity = layer->m_opacity;
     m_transform = layer->m_transform;
 
-    if (m_imageRef != layer->m_imageRef)
+    if (m_imageCRC != layer->m_imageCRC)
         m_visible = false;
 
     if ((m_recordingPicture != layer->m_recordingPicture)
-        || (m_imageRef != layer->m_imageRef))
+        || (m_imageCRC != layer->m_imageCRC))
         return true;
 
     return false;
 }
 
-void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingTree)
+void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer)
 {
     if (!needsTexture())
         return;
 
-    if (m_imageRef) {
-        if (!m_imageTexture) {
-            m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef);
-            m_dirtyRegion.setEmpty();
-        }
+    if (m_imageCRC) {
         if (m_texture) {
             m_texture->setDrawingLayer(0);
             m_texture->clearPaintingLayer();
             m_texture = 0;
         }
     } else {
-        if (drawingTree) {
-            LayerAndroid* drawingLayer = drawingTree->findById(uniqueId());
-            if (drawingLayer) {
-                // if a previous tree had the same layer, paint with that painted surface
-                m_texture = drawingLayer->m_texture;
-            }
+        if (drawingLayer) {
+            // if a previous tree had the same layer, paint with that painted surface
+            m_texture = drawingLayer->m_texture;
         }
 
         if (!m_texture)
@@ -989,8 +995,8 @@
 
         // pass the invalidated regions to the PaintedSurface
         m_texture->setPaintingLayer(this, m_dirtyRegion);
-        m_dirtyRegion.setEmpty();
     }
+    m_dirtyRegion.setEmpty();
 }
 
 
@@ -1032,9 +1038,6 @@
 
     if (m_texture)
         m_texture->prepare(m_state);
-
-    if (m_imageTexture)
-        m_imageTexture->prepareGL();
 }
 
 IntRect LayerAndroid::unclippedArea()
@@ -1115,11 +1118,16 @@
 
     bool askScreenUpdate = false;
 
-    if (m_texture)
-        askScreenUpdate |= m_texture->draw();
-
-    if (m_imageTexture)
-        m_imageTexture->drawGL(this);
+    if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers) {
+        if (m_texture)
+            askScreenUpdate |= m_texture->draw();
+        if (m_imageCRC) {
+            ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC);
+            if (imageTexture)
+                imageTexture->drawGL(this);
+            ImagesManager::instance()->releaseImage(m_imageCRC);
+        }
+    }
 
     // When the layer is dirty, the UI thread should be notified to redraw.
     askScreenUpdate |= drawChildrenGL();
@@ -1216,16 +1224,15 @@
     if (canvasOpacity < 255)
         canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity));
 
-    if (m_imageRef) {
-        if (!m_imageTexture) {
-            m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef);
-            m_dirtyRegion.setEmpty();
-        }
-        if (m_imageTexture) {
+    if (m_imageCRC) {
+        ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC);
+        m_dirtyRegion.setEmpty();
+        if (imageTexture) {
             SkRect dest;
             dest.set(0, 0, getSize().width(), getSize().height());
-            m_imageTexture->drawCanvas(canvas, dest);
+            imageTexture->drawCanvas(canvas, dest);
         }
+        ImagesManager::instance()->releaseImage(m_imageCRC);
     }
     contentDraw(canvas);
 }
diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h
index ae9dc88..c1f1bc9 100644
--- a/Source/WebCore/platform/graphics/android/LayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h
@@ -214,6 +214,7 @@
     void removeAnimationsForKeyframes(const String& name);
     bool evaluateAnimations();
     bool evaluateAnimations(double time);
+    void initAnimations();
     bool hasAnimations() const;
     void addDirtyArea();
 
@@ -260,7 +261,7 @@
     /** This sets a content image -- calling it means we will use
         the image directly when drawing the layer instead of using
         the content painted by WebKit.
-        Images are handled in TilesManager, as they can be shared
+        Images are handled in ImagesManager, as they can be shared
         between layers.
     */
     void setContentsImage(SkBitmapRef* img);
@@ -290,7 +291,7 @@
     friend void android::cleanupImageRefs(LayerAndroid* layer);
 
     PaintedSurface* texture() { return m_texture; }
-    void obtainTextureForPainting(LayerAndroid* drawingTree);
+    void obtainTextureForPainting(LayerAndroid* drawingLayer);
 
     // Update layers using another tree. Only works for basic properties
     // such as the position, the transform. Return true if anything more
@@ -298,13 +299,13 @@
     bool updateWithTree(LayerAndroid*);
     virtual bool updateWithLayer(LayerAndroid*);
 
-    SkBitmapRef* imageRef() { return m_imageRef; }
-    ImageTexture* imageTexture() { return m_imageTexture; }
     int type() { return m_type; }
 
     bool hasText() { return m_hasText; }
     void checkTextPresence();
 
+    void copyAnimationStartTimesRecursive(LayerAndroid* oldTree);
+
 // rendering asset management
     void swapTiles();
     void setIsDrawing(bool isDrawing);
@@ -323,6 +324,7 @@
     friend class CachedLayer::Debug; // debugging access only
 #endif
 
+    void copyAnimationStartTimes(LayerAndroid* oldLayer);
     void findInner(FindState&) const;
     bool prepareContext(bool force = false);
     void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const;
@@ -386,8 +388,7 @@
     int m_uniqueId;
 
     PaintedSurface* m_texture;
-    SkBitmapRef* m_imageRef;
-    ImageTexture* m_imageTexture;
+    unsigned m_imageCRC;
 
     unsigned int m_pictureUsed;
 
diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
index 5d06ea3..2d69706 100644
--- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
+++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
@@ -25,12 +25,14 @@
 
 #include "config.h"
 #include "PaintTileOperation.h"
+#include "ImageTexture.h"
+#include "ImagesManager.h"
 #include "LayerAndroid.h"
 #include "PaintedSurface.h"
 
 namespace WebCore {
 
-PaintTileOperation::PaintTileOperation(BaseTile* tile, PaintedSurface* surface)
+PaintTileOperation::PaintTileOperation(BaseTile* tile, SurfacePainter* surface)
     : QueuedOperation(QueuedOperation::PaintTile, tile->page())
     , m_tile(tile)
     , m_surface(surface)
@@ -46,7 +48,13 @@
         m_tile->setRepaintPending(false);
         m_tile = 0;
     }
-    SkSafeUnref(m_surface);
+
+    if (m_surface && m_surface->type() == SurfacePainter::ImageSurface) {
+        ImageTexture* image = static_cast<ImageTexture*>(m_surface);
+        ImagesManager::instance()->releaseImage(image->imageCRC());
+    } else {
+        SkSafeUnref(m_surface);
+    }
 }
 
 bool PaintTileOperation::operator==(const QueuedOperation* operation)
diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/PaintTileOperation.h
index fabc2f7..bc74d03 100644
--- a/Source/WebCore/platform/graphics/android/PaintTileOperation.h
+++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.h
@@ -28,15 +28,17 @@
 
 #include "BaseTile.h"
 #include "QueuedOperation.h"
+#include "SkRefCnt.h"
 
 namespace WebCore {
 
 class LayerAndroid;
-class PaintedSurface;
+class SurfacePainter;
+class ImageTexture;
 
 class PaintTileOperation : public QueuedOperation {
 public:
-    PaintTileOperation(BaseTile* tile, PaintedSurface* surface = 0);
+    PaintTileOperation(BaseTile* tile, SurfacePainter* surface = 0);
     virtual ~PaintTileOperation();
     virtual bool operator==(const QueuedOperation* operation);
     virtual void run();
@@ -47,7 +49,7 @@
 
 private:
     BaseTile* m_tile;
-    PaintedSurface* m_surface;
+    SurfacePainter* m_surface;
 };
 
 class ScaleFilter : public OperationFilter {
diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp
index d3c1e15..45c7579 100644
--- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp
+++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp
@@ -52,9 +52,8 @@
 
 #endif // DEBUG
 
-// Allows layers using less than MAX_UNCLIPPED_AREA tiles to
-// schedule all of them instead of clipping the area with the visible rect.
-#define MAX_UNCLIPPED_AREA 16
+// Layers with an area larger than 2048*2048 should never be unclipped
+#define MAX_UNCLIPPED_AREA 4194304
 
 namespace WebCore {
 
@@ -203,10 +202,14 @@
         return area;
 
     if (!layer->contentIsScrollable()
-        && layer->state()->layersRenderingMode() == GLWebViewState::kAllTextures)
+        && layer->state()->layersRenderingMode() == GLWebViewState::kAllTextures) {
         area = layer->unclippedArea();
-    else
+        double total = ((double) area.width()) * ((double) area.height());
+        if (total > MAX_UNCLIPPED_AREA)
+            area = layer->visibleArea();
+    } else {
         area = layer->visibleArea();
+    }
 
     return area;
 }
diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h
index b438111..b8ab7b8 100644
--- a/Source/WebCore/platform/graphics/android/PaintedSurface.h
+++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h
@@ -43,7 +43,7 @@
 
 class DualTiledTexture;
 
-class PaintedSurface : public SkRefCnt {
+class PaintedSurface : public SurfacePainter {
 public:
     PaintedSurface();
     virtual ~PaintedSurface();
@@ -71,10 +71,10 @@
 
     // TilePainter methods for TiledTexture
     virtual const TransformationMatrix* transform();
+    virtual float opacity();
 
     // used by TiledTexture
     float scale() { return m_scale; }
-    float opacity();
     unsigned int pictureUsed() { return m_pictureUsed; }
 
 private:
diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp
index 2643d2c..3c2ced5 100644
--- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp
@@ -22,9 +22,6 @@
 
     setPosition(m_scrollLimits.fLeft - newX, m_scrollLimits.fTop - newY);
 
-    if (state())
-        state()->scrolledLayer(this);
-
     return true;
 }
 
diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
index cc9c810..2a6a488 100644
--- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
+++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
@@ -195,6 +195,8 @@
 ShaderProgram::ShaderProgram()
     : m_blendingEnabled(false)
     , m_contrast(1)
+    , m_alphaLayer(false)
+    , m_currentScale(1.0f)
 {
     init();
 }
@@ -286,13 +288,14 @@
 // Drawing
 /////////////////////////////////////////////////////////////////////////////////////////
 
-void ShaderProgram::setViewport(SkRect& viewport)
+void ShaderProgram::setViewport(SkRect& viewport, float scale)
 {
     TransformationMatrix ortho;
     GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop,
                                    viewport.fRight, viewport.fBottom, -1000, 1000);
     m_projectionMatrix = ortho;
     m_viewport = viewport;
+    m_currentScale = scale;
 }
 
 void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle)
@@ -302,7 +305,12 @@
     TransformationMatrix scale;
     scale.scale3d(geometry.width(), geometry.height(), 1.0);
 
-    TransformationMatrix total = m_projectionMatrix * translate * scale;
+    TransformationMatrix total;
+    if (!m_alphaLayer)
+        total = m_projectionMatrix * m_repositionMatrix * m_webViewMatrix
+                * translate * scale;
+    else
+        total = m_projectionMatrix * translate * scale;
 
     GLfloat projectionMatrix[16];
     GLUtils::toGLMatrix(projectionMatrix, total);
@@ -560,7 +568,13 @@
     // move the drawing depending on where the texture is on the layer
     modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
     modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
-    TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
+
+    TransformationMatrix renderMatrix;
+    if (!m_alphaLayer)
+        renderMatrix = m_projectionMatrix * m_repositionMatrix
+                       * m_webViewMatrix * modifiedDrawMatrix;
+    else
+        renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
 
     GLfloat projectionMatrix[16];
     GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
@@ -627,6 +641,44 @@
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 }
 
+void ShaderProgram::setWebViewMatrix(const float* matrix, bool alphaLayer)
+{
+    GLUtils::convertToTransformationMatrix(matrix, m_webViewMatrix);
+    m_alphaLayer = alphaLayer;
+}
+
+void ShaderProgram::calculateAnimationDelta()
+{
+    // The matrix contains the scrolling info, so this rect is starting from
+    // the m_viewport.
+    // So we just need to map the webview's visible rect using the matrix,
+    // calculate the difference b/t transformed rect and the webViewRect,
+    // then we can get the delta x , y caused by the animation.
+    // Note that the Y is for reporting back to GL viewport, so it is inverted.
+    // When it is alpha animation, then we rely on the framework implementation
+    // such that there is no matrix applied in native webkit.
+    if (!m_alphaLayer) {
+        FloatRect rect(m_viewport.fLeft * m_currentScale,
+                       m_viewport.fTop * m_currentScale,
+                       m_webViewRect.width(),
+                       m_webViewRect.height());
+        rect = m_webViewMatrix.mapRect(rect);
+        m_animationDelta.setX(rect.x() - m_webViewRect.x() );
+        m_animationDelta.setY(rect.y() + rect.height() - m_webViewRect.y()
+                              - m_webViewRect.height() - m_titleBarHeight);
+
+        m_repositionMatrix.makeIdentity();
+        m_repositionMatrix.translate3d(-m_webViewRect.x(), -m_webViewRect.y() - m_titleBarHeight, 0);
+        m_repositionMatrix.translate3d(m_viewport.fLeft * m_currentScale, m_viewport.fTop * m_currentScale, 0);
+        m_repositionMatrix.translate3d(-m_animationDelta.x(), -m_animationDelta.y(), 0);
+    } else {
+        m_animationDelta.setX(0);
+        m_animationDelta.setY(0);
+        m_repositionMatrix.makeIdentity();
+    }
+
+}
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h
index b309872..9ab7a46 100644
--- a/Source/WebCore/platform/graphics/android/ShaderProgram.h
+++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h
@@ -36,7 +36,7 @@
     int program() { return m_program; }
 
     // Drawing
-    void setViewport(SkRect& viewport);
+    void setViewport(SkRect& viewport, float scale);
     float zValue(const TransformationMatrix& drawMatrix, float w, float h);
 
     // For drawQuad and drawLayerQuad, they can handle 3 cases for now:
@@ -88,6 +88,18 @@
             contrast = MAX_CONTRAST;
         m_contrast = contrast;
     }
+    void setWebViewMatrix(const float* matrix, bool alphaLayer);
+
+    // This delta is the delta from the layout pos and the current animation pos.
+    // Basically, in terms of layout, the webview is still in the original layout
+    // pos, as without animation. Such that the viewport and visible rect etc are
+    // still in that pos, too, except the clipping info.
+    // Our rendering approach is after applying all the matrix, webView is
+    // rendered as if it was at the original layout pos, but then offset the
+    // glViewport to match the animation.
+    void calculateAnimationDelta();
+    int getAnimationDeltaX() { return m_animationDelta.x(); }
+    int getAnimationDeltaY() { return m_animationDelta.y(); }
 
 private:
     GLuint loadShader(GLenum shaderType, const char* pSource);
@@ -158,6 +170,22 @@
     GLint m_hPosition;
     GLint m_hPositionInverted;
     GLint m_hVideoPosition;
+
+    bool  m_alphaLayer;
+    TransformationMatrix m_webViewMatrix;
+    float m_currentScale;
+
+    // After the webViewTranform, we need to reposition the rect to match our viewport.
+    // Basically, the webViewTransformMatrix should apply on the screen resolution.
+    // So we start by doing the scale and translate to get each tile into screen coordinates.
+    // After applying the webViewTransformMatrix, b/c the way it currently set up
+    // for scroll and titlebar, we need to offset both of them.
+    // Finally, map everything back to (-1, 1) by using the m_projectionMatrix.
+    // TODO: Given that m_webViewMatrix contains most of the tranformation
+    // information, we should be able to get rid of some parameter we got from
+    // Java side and simplify our code.
+    TransformationMatrix  m_repositionMatrix;
+    IntPoint m_animationDelta;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp
index 0820688..bccb99b 100644
--- a/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp
+++ b/Source/WebCore/platform/graphics/android/TexturesGenerator.cpp
@@ -184,11 +184,10 @@
             m_currentOperation->run();
         }
 
+        QueuedOperation* oldOperation = m_currentOperation;
         mRequestedOperationsLock.lock();
-        if (m_currentOperation) {
-            delete m_currentOperation;
+        if (m_currentOperation)
             m_currentOperation = 0;
-        }
         if (!mRequestedOperations.size())
             stop = true;
         if (m_waitForCompletion) {
@@ -197,7 +196,8 @@
             mRequestedOperationsCond.signal();
         }
         mRequestedOperationsLock.unlock();
-
+        if (oldOperation)
+            delete oldOperation; // delete outside lock
     }
     XLOG("threadLoop empty");
 
diff --git a/Source/WebCore/platform/graphics/android/TilePainter.h b/Source/WebCore/platform/graphics/android/TilePainter.h
index 91030cb..4d0f5dc 100644
--- a/Source/WebCore/platform/graphics/android/TilePainter.h
+++ b/Source/WebCore/platform/graphics/android/TilePainter.h
@@ -27,6 +27,7 @@
 #define TilePainter_h
 
 #include "TransformationMatrix.h"
+#include "SkRefCnt.h"
 
 class SkCanvas;
 
@@ -41,6 +42,15 @@
    virtual const TransformationMatrix* transform() { return 0; }
 };
 
+class SurfacePainter : public SkRefCnt {
+public:
+   virtual ~SurfacePainter() { }
+   virtual const TransformationMatrix* transform() { return 0; }
+   virtual float opacity() { return 1.0; }
+   enum SurfaceType { PaintedSurface, ImageSurface };
+   virtual SurfaceType type() { return PaintedSurface; }
+};
+
 }
 
 #endif // TilePainter_h
diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp
index e33d39a..31a0593 100644
--- a/Source/WebCore/platform/graphics/android/TiledPage.cpp
+++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp
@@ -242,9 +242,6 @@
     int nbTilesWidth = tileBounds.width();
     int nbTilesHeight = tileBounds.height();
 
-    int lastTileX = tileBounds.fRight - 1;
-    int lastTileY = tileBounds.fBottom - 1;
-
     // Expand number of tiles to allow tiles outside of viewport to be prepared for
     // smoother scrolling.
     int nTilesToPrepare = nbTilesWidth * nbTilesHeight;
@@ -256,21 +253,31 @@
         int expandY = m_glWebViewState->expandedTileBoundsY();
 
         firstTileX -= expandX;
-        lastTileX += expandX;
         nbTilesWidth += expandX * 2;
 
         firstTileY -= expandY;
-        lastTileY += expandY;
         nbTilesHeight += expandY * 2;
     }
 
-    // crop the prepared region to the contents of the base layer
-    float maxWidthTiles = m_glWebViewState->baseContentWidth() * m_scale / TilesManager::tileWidth();
-    float maxHeightTiles = m_glWebViewState->baseContentHeight() * m_scale / TilesManager::tileHeight();
-    firstTileX = std::max(0, firstTileX);
-    firstTileY = std::max(0, firstTileY);
-    lastTileX = std::min(lastTileX, static_cast<int>(ceilf(maxWidthTiles)) - 1);
-    lastTileY = std::min(lastTileY, static_cast<int>(ceilf(maxHeightTiles)) - 1);
+    // crop the tile bounds in each dimension to the larger of the base layer or viewport
+    float maxBaseX = m_glWebViewState->baseContentWidth() * m_scale / TilesManager::tileWidth();
+    float maxBaseY = m_glWebViewState->baseContentHeight() * m_scale / TilesManager::tileHeight();
+    int maxX = std::max(static_cast<int>(ceilf(maxBaseX)),
+                        m_glWebViewState->viewportTileBounds().width());
+    int maxY = std::max(static_cast<int>(ceilf(maxBaseY)),
+                        m_glWebViewState->viewportTileBounds().height());
+
+    // adjust perimeter to not go outside cropped region
+    if (firstTileX < 0) {
+        nbTilesWidth += firstTileX;
+        firstTileX = 0;
+    }
+    if (firstTileY < 0) {
+        nbTilesHeight += firstTileY;
+        firstTileY = 0;
+    }
+    nbTilesWidth = std::min(nbTilesWidth, maxX - firstTileX);
+    nbTilesHeight = std::min(nbTilesHeight, maxY - firstTileY);
 
     // check against corrupted scale values giving bad height/width (use float to avoid overflow)
     float numTiles = static_cast<float>(nbTilesHeight) * static_cast<float>(nbTilesWidth);
diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp
index 5538e1b..d538416 100644
--- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp
+++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp
@@ -204,6 +204,7 @@
 
     if (tile->isDirty() || !tile->frontTexture())
         tile->reserveTexture();
+
     bool hasPicture = m_paintingPicture != 0; // safely read on UI thread, since only UI thread writes
     if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && hasPicture) {
         PaintTileOperation *operation = new PaintTileOperation(tile, m_surface);
@@ -223,12 +224,26 @@
 
 int TiledTexture::nbTextures(IntRect& area, float scale)
 {
-    IntRect computedTilesArea = computeTilesArea(area, scale);
-    return computedTilesArea.width() * computedTilesArea.height();
+    IntRect tileBounds = computeTilesArea(area, scale);
+    int numberTextures = tileBounds.width() * tileBounds.height();
+
+    // add the number of dirty tiles in the bounds, as they take up double
+    // textures for double buffering
+    for (unsigned int i = 0; i <m_tiles.size(); i++) {
+        BaseTile* tile = m_tiles[i];
+        if (tile->isDirty()
+                && tile->x() >= tileBounds.x() && tile->x() <= tileBounds.maxX()
+                && tile->y() >= tileBounds.y() && tile->y() <= tileBounds.maxY())
+            numberTextures++;
+    }
+    return numberTextures;
 }
 
 bool TiledTexture::draw()
 {
+    if (!m_surface)
+        return true;
+
     XLOG("TT %p draw", this);
 
 #ifdef DEBUG
@@ -257,8 +272,8 @@
             rect.fTop = tile->y() * tileHeight;
             rect.fRight = rect.fLeft + tileWidth;
             rect.fBottom = rect.fTop + tileHeight;
-            XLOG("- [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
-                 i, this, tile->painter(), tile, tile->x(), tile->y(),
+            XLOG("- [%d], { painter %x vs %x }, tile %x (layer tile: %d) %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
+                 i, this, tile->painter(), tile, tile->isLayerTile(), tile->x(), tile->y(),
                  tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());
             tile->draw(m_surface->opacity(), rect, m_scale);
 #ifdef DEBUG
@@ -283,7 +298,7 @@
         return false;
     }
 
-    XLOG("TT %p painting with picture %p", this, picture);
+    XLOG("TT %p painting tile %d, %d with picture %p", this, tile->x(), tile->y(), picture);
 
     canvas->drawPicture(*picture);
 
@@ -294,6 +309,8 @@
 
 const TransformationMatrix* TiledTexture::transform()
 {
+    if (!m_surface)
+        return 0;
     return m_surface->transform();
 }
 
@@ -323,7 +340,7 @@
     return false;
 }
 
-DualTiledTexture::DualTiledTexture(PaintedSurface* surface)
+DualTiledTexture::DualTiledTexture(SurfacePainter* surface)
 {
     m_textureA = new TiledTexture(surface);
     m_textureB = new TiledTexture(surface);
@@ -364,6 +381,7 @@
     if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) {
         m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea);
         if (m_backTexture->ready()) {
+            m_backTexture->swapTiles();
             swap();
             m_zooming = false;
         }
diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h
index b761880..444ab14 100644
--- a/Source/WebCore/platform/graphics/android/TiledTexture.h
+++ b/Source/WebCore/platform/graphics/android/TiledTexture.h
@@ -39,11 +39,9 @@
 
 namespace WebCore {
 
-class PaintedSurface;
-
 class TiledTexture : public TilePainter {
 public:
-    TiledTexture(PaintedSurface* surface)
+    TiledTexture(SurfacePainter* surface)
         : m_paintingPicture(0)
         , m_surface(surface)
         , m_prevTileX(0)
@@ -82,8 +80,6 @@
     float scale() { return m_scale; }
     bool ready();
 
-    PaintedSurface* surface() { return m_surface; }
-
     int nbTextures(IntRect& area, float scale);
 
 private:
@@ -95,7 +91,7 @@
     android::Mutex m_paintingPictureSync;
     SkPicture* m_paintingPicture;
 
-    PaintedSurface* m_surface;
+    SurfacePainter* m_surface;
     Vector<BaseTile*> m_tiles;
 
     // tile coordinates in viewport, set in prepare()
@@ -112,7 +108,7 @@
 
 class DualTiledTexture {
 public:
-    DualTiledTexture(PaintedSurface* surface);
+    DualTiledTexture(SurfacePainter* surface);
     ~DualTiledTexture();
     void prepare(GLWebViewState* state, float scale, bool repaint,
                  bool startFastSwap, IntRect& area);
diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp
index 219435d..30bd8d0 100644
--- a/Source/WebCore/platform/graphics/android/TilesManager.cpp
+++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp
@@ -189,6 +189,23 @@
          dealloc, max, maxLayer);
 }
 
+void TilesManager::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures,
+                                        int* nbLayerTextures, int* nbAllocatedLayerTextures)
+{
+    *nbTextures = m_textures.size();
+    for (unsigned int i = 0; i < m_textures.size(); i++) {
+        BaseTileTexture* texture = m_textures[i];
+        if (texture->m_ownTextureId)
+            *nbAllocatedTextures += 1;
+    }
+    *nbLayerTextures = m_tilesTextures.size();
+    for (unsigned int i = 0; i < m_tilesTextures.size(); i++) {
+        BaseTileTexture* texture = m_tilesTextures[i];
+        if (texture->m_ownTextureId)
+            *nbAllocatedLayerTextures += 1;
+    }
+}
+
 void TilesManager::printTextures()
 {
 #ifdef DEBUG
diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h
index 0c3e900..9782fbb 100644
--- a/Source/WebCore/platform/graphics/android/TilesManager.h
+++ b/Source/WebCore/platform/graphics/android/TilesManager.h
@@ -88,6 +88,8 @@
     void gatherLayerTextures();
     void gatherTextures();
     bool layerTexturesRemain() { return m_layerTexturesRemain; }
+    void gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures,
+                               int* nbLayerTextures, int* nbAllocatedLayerTextures);
 
     BaseTileTexture* getAvailableTexture(BaseTile* owner);
 
diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp
index b92edaf..b20ec7a 100644
--- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp
+++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp
@@ -50,7 +50,7 @@
 
 #endif // DEBUG
 
-#define ST_BUFFER_NUMBER 4
+#define ST_BUFFER_NUMBER 6
 
 // Set this to 1 if we would like to take the new GpuUpload approach which
 // relied on the glCopyTexSubImage2D instead of a glDraw call
diff --git a/Source/WebCore/platform/graphics/android/TreeManager.cpp b/Source/WebCore/platform/graphics/android/TreeManager.cpp
index 5fd3b7c..b7eaacf 100644
--- a/Source/WebCore/platform/graphics/android/TreeManager.cpp
+++ b/Source/WebCore/platform/graphics/android/TreeManager.cpp
@@ -28,6 +28,7 @@
 
 #include "Layer.h"
 #include "BaseLayerAndroid.h"
+#include "ScrollableLayerAndroid.h"
 #include "TilesManager.h"
 
 #include <cutils/log.h>
@@ -87,6 +88,8 @@
     // painting tree becomes the drawing tree
     XLOG("drawing tree %p", m_paintingTree);
     m_paintingTree->setIsDrawing(true);
+    if (m_paintingTree->countChildren())
+        static_cast<LayerAndroid*>(m_paintingTree->getChild(0))->initAnimations();
 
     if (m_queuedTree) {
         // start painting with the queued tree
@@ -132,6 +135,10 @@
 // or start painting it if we aren't
 void TreeManager::updateWithTree(Layer* newTree, bool brandNew)
 {
+    XLOG("updateWithTree - %p, has children %d, has animations %d",
+         newTree, newTree && newTree->countChildren(),
+         newTree && newTree->countChildren()
+             ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0);
 
     // can't have a queued tree unless have a painting tree too
     ASSERT(m_paintingTree || !m_queuedTree);
@@ -143,10 +150,6 @@
     if (!newTree || brandNew) {
         clearTrees();
         if (brandNew) {
-            m_animationOffset = 0;
-            m_isAnimating = false;
-            m_lastFrameTime = WTF::currentTime();
-
             m_paintingTree = newTree;
             m_paintingTree->setIsPainting(m_drawingTree);
         }
@@ -159,6 +162,11 @@
             // have a queued tree, copy over invals so the regions are
             // eventually repainted
             m_queuedTree->mergeInvalsInto(newTree);
+
+            XLOG("DISCARDING tree - %p, has children %d, has animations %d",
+                 newTree, newTree && newTree->countChildren(),
+                 newTree && newTree->countChildren()
+                     ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0);
         }
         SkSafeUnref(m_queuedTree);
         m_queuedTree = newTree;
@@ -170,9 +178,26 @@
     m_paintingTree->setIsPainting(m_drawingTree);
 }
 
+void TreeManager::updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y)
+{
+    LayerAndroid* layer;
+    if (tree && tree->countChildren()) {
+        layer = static_cast<LayerAndroid*>(tree->getChild(0))->findById(layerId);
+        if (layer && layer->contentIsScrollable())
+            static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
+    }
+}
+
+void TreeManager::updateScrollableLayer(int layerId, int x, int y)
+{
+    updateScrollableLayerInTree(m_queuedTree, layerId, x, y);
+    updateScrollableLayerInTree(m_paintingTree, layerId, x, y);
+    updateScrollableLayerInTree(m_drawingTree, layerId, x, y);
+}
+
 bool TreeManager::drawGL(double currentTime, IntRect& viewRect,
                          SkRect& visibleRect, float scale,
-                         bool enterFastSwapMode, bool* buffersSwappedPtr,
+                         bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr,
                          TexturesResult* texturesResultPtr)
 {
     m_fastSwapMode |= enterFastSwapMode;
@@ -183,19 +208,28 @@
     bool ret = false;
     bool didTreeSwap = false;
     if (m_paintingTree) {
+        XLOG("preparing painting tree %p", m_paintingTree);
+
+        LayerAndroid* laTree = 0;
+        if (m_paintingTree->countChildren()) {
+            laTree = static_cast<LayerAndroid*>(m_paintingTree->getChild(0));
+            ret |= laTree->evaluateAnimations(currentTime);
+        }
+
         ret |= m_paintingTree->prepare(currentTime, viewRect,
                                        visibleRect, scale);
 
-        if (m_paintingTree->countChildren()) {
-            LayerAndroid* laTree = static_cast<LayerAndroid*>(m_paintingTree->getChild(0));
+        if (laTree)
             laTree->computeTexturesAmount(texturesResultPtr);
-        }
+
         if (/*!m_fastSwapMode && */ m_paintingTree->isReady()) {
             XLOG("have painting tree %p ready, swapping!", m_paintingTree);
             didTreeSwap = true;
             swap();
-            if (buffersSwappedPtr)
-                *buffersSwappedPtr = true;
+            if (treesSwappedPtr)
+                *treesSwappedPtr = true;
+            if (laTree && newTreeHasAnimPtr)
+                *newTreeHasAnimPtr = laTree->hasAnimations();
         }
     } else if (m_drawingTree) {
         XLOG("preparing drawing tree %p", m_drawingTree);
@@ -207,17 +241,11 @@
         }
     }
 
-    if (!m_isAnimating) {
-        m_animationOffset += currentTime - m_lastFrameTime;
-#ifdef ANIM_DEBUG
-        XLOGC("adding to %f", m_animationOffset);
-#endif
-    }
 
     if (m_drawingTree) {
         bool drawingReady = didTreeSwap || m_drawingTree->isReady();
 
-        if (drawingReady || m_fastSwapMode)
+        if (didTreeSwap || m_fastSwapMode || (drawingReady && !m_paintingTree))
             m_drawingTree->swapTiles();
 
         if (drawingReady) {
@@ -229,18 +257,8 @@
         }
 
         if (m_drawingTree->countChildren()) {
-#ifdef ANIM_DEBUG
-            XLOGC("drawing tree %p with animation time offset of %f, locked %d",
-                  m_drawingTree, m_animationOffset, m_isAnimating);
-#endif
             LayerAndroid* laTree = static_cast<LayerAndroid*>(m_drawingTree->getChild(0));
-            m_isAnimating = laTree->evaluateAnimations(currentTime - m_animationOffset);
-            if (!m_isAnimating)
-                m_animationOffset = 0;
-            ret |= m_isAnimating;
-        } else if (!m_paintingTree) {
-            m_animationOffset = 0;
-            m_isAnimating = false;
+            ret |= laTree->evaluateAnimations(currentTime);
         }
         XLOG("drawing tree %p", m_drawingTree);
         ret |= m_drawingTree->drawGL(viewRect, visibleRect, scale);
@@ -250,8 +268,6 @@
         m_paintingTree->state()->drawBackground(defaultBackground);
     }
 
-    m_lastFrameTime = currentTime;
-
     if (m_paintingTree) {
         XLOG("still have painting tree %p", m_paintingTree);
         return true;
diff --git a/Source/WebCore/platform/graphics/android/TreeManager.h b/Source/WebCore/platform/graphics/android/TreeManager.h
index 09b1bd9..83d5300 100644
--- a/Source/WebCore/platform/graphics/android/TreeManager.h
+++ b/Source/WebCore/platform/graphics/android/TreeManager.h
@@ -28,6 +28,7 @@
 
 #include "TestExport.h"
 #include <utils/threads.h>
+#include "PerformanceMonitor.h"
 
 class Layer;
 class SkRect;
@@ -46,9 +47,11 @@
 
     void updateWithTree(Layer* tree, bool brandNew);
 
+    void updateScrollableLayer(int layerId, int x, int y);
+
     bool drawGL(double currentTime, IntRect& viewRect,
                 SkRect& visibleRect, float scale,
-                bool enterFastSwapMode, bool* buffersSwappedPtr,
+                bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr,
                 TexturesResult* texturesResultPtr);
 
     void drawCanvas(SkCanvas* canvas, bool drawLayers);
@@ -60,6 +63,8 @@
     int baseContentHeight();
 
 private:
+    static void updateScrollableLayerInTree(Layer* tree, int layerId, int x, int y);
+
     void swap();
     void clearTrees();
 
@@ -70,10 +75,7 @@
     Layer* m_queuedTree;
 
     bool m_fastSwapMode;
-
-    double m_animationOffset;
-    double m_lastFrameTime;
-    bool m_isAnimating;
+    PerformanceMonitor m_perf;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
index d4e2aa3..df20063 100644
--- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -812,7 +812,7 @@
                 else {
 #ifdef ANDROID_LAYOUT
                     // ignore text wrap for textField or menuList
-                    if (doTextWrap && (o->isTextField() || o->isMenuList() || o->isFloating()))
+                    if (doTextWrap && (o->isTextField() || o->isMenuList()))
                         doTextWrap = false;
 #endif
                     if (o->isFloating())
diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp
index 80d5699..fb1dd2c 100644
--- a/Source/WebCore/rendering/RenderBox.cpp
+++ b/Source/WebCore/rendering/RenderBox.cpp
@@ -1562,6 +1562,13 @@
     // https://bugs.webkit.org/show_bug.cgi?id=46418
     if (hasOverrideSize() &&  parent()->style()->boxOrient() == HORIZONTAL
             && parent()->isFlexibleBox() && parent()->isFlexingChildren()) {
+#if PLATFORM(ANDROID)
+        // Strangely, the slider is get overrided as width 0 on youtube.com
+        // The wrong width will cause the touch hit test for the slider failed.
+        // This WAR should be safe since it is only targeted to slider.
+        // TODO: root cause this and see if any webkit update fix this.
+        if (!(isSlider() &&  overrideSize() == 0))
+#endif
         setLogicalWidth(overrideSize());
         return;
     }
diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp
index 904b1b2..cdc4c05 100644
--- a/Source/WebCore/rendering/RenderLayer.cpp
+++ b/Source/WebCore/rendering/RenderLayer.cpp
@@ -1419,8 +1419,15 @@
     }
 
     // Just schedule a full repaint of our object.
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+    // On android, scrollable areas are put on composited layers, so we
+    // do not need to repaint simply because we are scrolling
+    if (view && !hasOverflowScroll())
+        renderer()->repaintUsingContainer(repaintContainer, rectForRepaint);
+#else
     if (view)
         renderer()->repaintUsingContainer(repaintContainer, rectForRepaint);
+#endif
 
     // Schedule the scroll DOM event.
     renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget);
diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp
index 5827636..1ef3b77 100644
--- a/Source/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp
@@ -1576,7 +1576,12 @@
         return false;
 
     if (AnimationController* animController = renderer->animation()) {
+#if PLATFORM(ANDROID)
+        // android renders an opacity animation much faster if it's composited
+        return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity))
+#else
         return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode())
+#endif
             || animController->isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform);
     }
     return false;
diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
index a6e58c8..43037ab 100644
--- a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
+++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp
@@ -324,16 +324,6 @@
     this->Release();
 }
 
-void WebUrlLoaderClient::sslClientCert(EVP_PKEY* pkey, net::X509Certificate* chain)
-{
-    base::Thread* thread = ioThread();
-    scoped_refptr<net::X509Certificate> scopedChain(chain);
-    if (isActive() && thread)
-        thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::sslClientCert, pkey, scopedChain));
-    this->Release();
-}
-
-
 void WebUrlLoaderClient::finish()
 {
     m_finished = true;
@@ -492,12 +482,22 @@
     m_webFrame->reportSslCertError(this, cert_error, chain_bytes[0], m_request->getUrl());
 }
 
+void WebUrlLoaderClient::sslClientCert(EVP_PKEY* pkey, net::X509Certificate* chain)
+{
+    base::Thread* thread = ioThread();
+    scoped_refptr<net::X509Certificate> scopedChain(chain);
+    if (isActive() && thread)
+        thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::sslClientCert, pkey, scopedChain));
+    this->Release();
+}
+
 void WebUrlLoaderClient::requestClientCert(net::SSLCertRequestInfo* cert_request_info)
 {
     if (!isActive())
         return;
 
     std::string host_and_port = cert_request_info->host_and_port;
+    this->AddRef();
     m_webFrame->requestClientCert(this, host_and_port);
 }
 
diff --git a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
index 5f03339..4463dfb 100644
--- a/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
+++ b/Source/WebKit/android/WebCoreSupport/WebUrlLoaderClient.h
@@ -74,7 +74,6 @@
     void cancelAuth();
     void proceedSslCertError();
     void cancelSslCertError(int cert_error);
-    void sslClientCert(EVP_PKEY* pkey, net::X509Certificate* chain);
 
     typedef void CallbackFunction(void*);
 
@@ -92,6 +91,8 @@
     void willSendRequest(PassOwnPtr<WebResponse>);
     void authRequired(scoped_refptr<net::AuthChallengeInfo>, bool firstTime, bool suppressDialog);
     void reportSslCertError(int cert_error, net::X509Certificate* cert);
+
+    void sslClientCert(EVP_PKEY* pkey, net::X509Certificate* chain);
     void requestClientCert(net::SSLCertRequestInfo* cert);
 
     // Handle to the chrome IO thread
diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp
index 93f4375..6b473f5 100644
--- a/Source/WebKit/android/jni/ViewStateSerializer.cpp
+++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp
@@ -111,11 +111,6 @@
         if (childLayer)
             layer->addChild(childLayer);
     }
-    // Now double back and delete any imageRefs
-    for (int i = 0; i < layer->countChildren(); i++) {
-        LayerAndroid* childLayer = static_cast<LayerAndroid*>(layer->getChild(i));
-        cleanupImageRefs(childLayer);
-    }
     delete stream;
     return layer;
 }
@@ -297,15 +292,16 @@
     stream->writeBool(layer->m_preserves3D);
     stream->writeScalar(layer->m_anchorPointZ);
     stream->writeScalar(layer->m_drawOpacity);
-    bool hasContentsImage = layer->m_imageRef != 0;
+    bool hasContentsImage = layer->m_imageCRC != 0;
     stream->writeBool(hasContentsImage);
     if (hasContentsImage) {
         SkFlattenableWriteBuffer buffer(1024);
         buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
         ImageTexture* imagetexture =
-                ImagesManager::instance()->getTextureForImage(layer->m_imageRef, false);
+                ImagesManager::instance()->retainImage(layer->m_imageCRC);
         if (imagetexture && imagetexture->bitmap())
             imagetexture->bitmap()->flatten(buffer);
+        ImagesManager::instance()->releaseImage(layer->m_imageCRC);
         stream->write32(buffer.size());
         buffer.writeToStream(stream);
     }
@@ -388,8 +384,7 @@
         contentsImage.unflatten(buffer);
         SkBitmapRef* imageRef = new SkBitmapRef(contentsImage);
         layer->setContentsImage(imageRef);
-        // We delay deleting the imageRef until after deserialization to make
-        // sure we have unique keys
+        delete imageRef;
     }
     bool hasRecordingPicture = stream->readBool();
     if (hasRecordingPicture) {
@@ -418,17 +413,6 @@
     return layer;
 }
 
-void cleanupImageRefs(LayerAndroid* layer)
-{
-    if (!layer)
-        return;
-    int count = layer->countChildren();
-    for (int i = 0; i < count; i++)
-        cleanupImageRefs(layer->getChild(i));
-    if (layer->m_imageRef)
-        delete layer->m_imageRef;
-}
-
 /*
  * JNI registration
  */
diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp
index 7ec73a3..aa74b81 100644
--- a/Source/WebKit/android/jni/WebHistory.cpp
+++ b/Source/WebKit/android/jni/WebHistory.cpp
@@ -490,7 +490,7 @@
 
     // Read the original url
     // Read the expected length of the string.
-    int l;
+    unsigned l;
     memcpy(&l, data, sizeofUnsigned);
     // Increment data pointer by the size of an unsigned int.
     data += sizeofUnsigned;
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 7692de1..839c352 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -885,29 +885,37 @@
     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
     if (root) {
-        root->notifyClientAnimationStarted();
         LayerAndroid* updatedLayer = root->contentLayer();
         return layers->updateWithTree(updatedLayer);
     }
     return true;
 }
 
+void WebViewCore::notifyAnimationStarted()
+{
+    // We notify webkit that the animations have begun
+    // TODO: handle case where not all have begun
+    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
+    GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
+    if (root)
+        root->notifyClientAnimationStarted();
+
+}
+
 BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
 {
     BaseLayerAndroid* base = new BaseLayerAndroid();
     base->setContent(m_content);
 
-    if (!region->isEmpty()) {
-        m_skipContentDraw = true;
-        bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
-        m_skipContentDraw = false;
-        // Layout only fails if called during a layout.
-        LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
-    }
+    m_skipContentDraw = true;
+    bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
+    m_skipContentDraw = false;
+    // Layout only fails if called during a layout.
+    LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
 
 #if USE(ACCELERATED_COMPOSITING)
     // We set the background color
-    if (!region->isEmpty() && m_mainFrame && m_mainFrame->document()
+    if (m_mainFrame && m_mainFrame->document()
         && m_mainFrame->document()->body()) {
         Document* document = m_mainFrame->document();
         RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
@@ -922,7 +930,6 @@
     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
     if (root) {
-        root->notifyClientAnimationStarted();
         LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
         base->addChild(copyLayer);
         copyLayer->unref();
@@ -4106,9 +4113,9 @@
         m_groupForVisitedLinks->addVisitedLink(string, length);
 }
 
-static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer)
+static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer)
 {
-    WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
     BaseLayerAndroid* baseLayer = (BaseLayerAndroid*)  jbaseLayer;
     if (baseLayer) {
         LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
@@ -4118,6 +4125,12 @@
     return true;
 }
 
+static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass)
+{
+    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
+    viewImpl->notifyAnimationStarted();
+}
+
 static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
 {
 #ifdef ANDROID_INSTRUMENT
@@ -4697,8 +4710,10 @@
         (void*) UpdateFrameCache },
     { "nativeGetContentMinPrefWidth", "()I",
         (void*) GetContentMinPrefWidth },
-    { "nativeUpdateLayers", "(I)Z",
+    { "nativeUpdateLayers", "(II)Z",
         (void*) UpdateLayers },
+    { "nativeNotifyAnimationStarted", "(I)V",
+        (void*) NotifyAnimationStarted },
     { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
         (void*) RecordContent },
     { "setViewportSettingsFromNative", "()V",
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index acde590..a05c3ea 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -529,6 +529,7 @@
         // as we are calling layersSync().
         BaseLayerAndroid* createBaseLayer(SkRegion*);
         bool updateLayers(LayerAndroid*);
+        void notifyAnimationStarted();
 
         int textWrapWidth() const { return m_textWrapWidth; }
         float scale() const { return m_scale; }
diff --git a/Source/WebKit/android/nav/CacheBuilder.cpp b/Source/WebKit/android/nav/CacheBuilder.cpp
index 0c9e85c..940991f 100644
--- a/Source/WebKit/android/nav/CacheBuilder.cpp
+++ b/Source/WebKit/android/nav/CacheBuilder.cpp
@@ -1161,8 +1161,6 @@
         absBounds.move(globalOffsetX, globalOffsetY);
         hasClip = nodeRenderer->hasOverflowClip();
 
-        if (node->hasTagName(HTMLNames::canvasTag))
-            mPictureSetDisabled = true;
         if (checkForPluginViewThatWantsFocus(nodeRenderer)) {
             bounds = absBounds;
             isUnclipped = true;
@@ -1269,6 +1267,7 @@
             type = TEXT_INPUT_CACHEDNODETYPE;
             cachedInput.setFormPointer(area->form());
             cachedInput.setIsTextArea(true);
+            cachedInput.setSpellcheck(area->spellcheck());
             exported = area->value().threadsafeCopy();
         } else if (node->hasTagName(HTMLNames::aTag)) {
             const HTMLAnchorElement* anchorNode = 
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 13346b3..76f0fb8 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -172,7 +172,7 @@
     m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
     m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
         "viewInvalidateDelayed", "(JIIII)V");
-    m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "()V");
+    m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V");
     m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
     m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F");
     env->DeleteLocalRef(clazz);
@@ -505,17 +505,18 @@
     // once the correct scale is set
     if (!m_visibleRect.hasValidCoordinates())
         return false;
-    bool pagesSwapped = false;
+    bool treesSwapped = false;
+    bool newTreeHasAnim = false;
     bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect,
                                         webViewRect, titleBarHeight, clip, scale,
-                                        &pagesSwapped);
-    if (m_pageSwapCallbackRegistered && pagesSwapped) {
+                                        &treesSwapped, &newTreeHasAnim);
+    if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) {
         m_pageSwapCallbackRegistered = false;
         LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
         JNIEnv* env = JSC::Bindings::getJNIEnv();
         AutoJObject javaObject = m_javaGlue.object(env);
         if (javaObject.get()) {
-            env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback);
+            env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim);
             checkException(env);
         }
     }
@@ -1092,6 +1093,12 @@
     return 0;
 }
 
+void scrollLayer(int layerId, int x, int y)
+{
+    if (m_glWebViewState)
+        m_glWebViewState->scrollLayer(layerId, x, y);
+}
+
 int getBlockLeftEdge(int x, int y, float scale)
 {
     CachedRoot* root = getFrameCache(AllowNewer);
@@ -1458,6 +1465,7 @@
 
 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
     if (layer) {
+        // TODO: the below tree copies are only necessary in software rendering
         LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
         copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
     }
@@ -1584,6 +1592,7 @@
         WebCore::IntRect clip(info->clipLeft, info->clipTop,
                               info->clipRight - info->clipLeft,
                               info->clipBottom - info->clipTop);
+        TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer);
 
         bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect,
                 titlebarHeight, clip, scale, extras);
@@ -1904,10 +1913,13 @@
 
 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView)
 {
+    // only call in software rendering, initialize and evaluate animations
 #if USE(ACCELERATED_COMPOSITING)
     LayerAndroid* root = ((WebView*)nativeView)->compositeRoot();
-    if (root)
+    if (root) {
+        root->initAnimations();
         return root->evaluateAnimations();
+    }
 #endif
     return false;
 }
@@ -2094,6 +2106,18 @@
     return input->getType();
 }
 
+static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj)
+{
+    const CachedFrame* frame = 0;
+    const CachedNode* node = getFocusNode(env, obj, &frame);
+    if (!node || !frame)
+        return -1;
+    const CachedLayer* layer = frame->layer(node);
+    if (!layer)
+        return -1;
+    return layer->uniqueId();
+}
+
 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
 {
     const CachedNode* node = getFocusNode(env, obj);
@@ -2657,6 +2681,9 @@
 {
 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
     WebView* view = GET_NATIVE_VIEW(env, obj);
+    view->scrollLayer(layerId, x, y);
+
+    //TODO: the below only needed for the SW rendering path
     LayerAndroid* root = view->compositeRoot();
     if (!root)
         return false;
@@ -2789,6 +2816,8 @@
         (void*) nativeFocusCandidateTextSize },
     { "nativeFocusCandidateType", "()I",
         (void*) nativeFocusCandidateType },
+    { "nativeFocusCandidateLayerId", "()I",
+        (void*) nativeFocusCandidateLayerId },
     { "nativeFocusIsPlugin", "()Z",
         (void*) nativeFocusIsPlugin },
     { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",