resolved conflicts for merge of 870689c8
diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h
index dbe2f8e..18e2b5c 100644
--- a/JavaScriptCore/wtf/Platform.h
+++ b/JavaScriptCore/wtf/Platform.h
@@ -919,6 +919,10 @@
 #endif
 #endif
 
+#if PLATFORM(ANDROID)
+#define WTF_USE_ACCELERATED_COMPOSITING 0
+#endif
+
 #if PLATFORM(IPHONE)
 #define WTF_USE_ACCELERATED_COMPOSITING 1
 #endif
diff --git a/WebCore/Android.derived.v8bindings.mk b/WebCore/Android.derived.v8bindings.mk
index 33b7050..ada160b 100644
--- a/WebCore/Android.derived.v8bindings.mk
+++ b/WebCore/Android.derived.v8bindings.mk
@@ -30,7 +30,8 @@
 	$(LOCAL_PATH)/bindings/scripts/IDLStructure.pm \
 	$(LOCAL_PATH)/bindings/scripts/generate-bindings.pl
 
-FEATURE_DEFINES := ENABLE_ORIENTATION_EVENTS=1 ENABLE_TOUCH_EVENTS=1 V8_BINDING ENABLE_DATABASE=1 ENABLE_OFFLINE_WEB_APPLICATIONS=1 ENABLE_DOM_STORAGE=1 ENABLE_VIDEO=1 ENABLE_WORKERS=1 ENABLE_GEOLOCATION=1
+# Add ACCELERATED_COMPOSITING=1 and ENABLE_3D_RENDERING=1 for layers support
+FEATURE_DEFINES := ANDROID_ORIENTATION_SUPPORT ENABLE_TOUCH_EVENTS=1 V8_BINDING ENABLE_DATABASE=1 ENABLE_OFFLINE_WEB_APPLICATIONS=1 ENABLE_DOM_STORAGE=1 ENABLE_WORKERS=1 ENABLE_VIDEO=1 ENABLE_GEOLOCATION=1
 
 # CSS
 GEN := \
diff --git a/WebCore/Android.mk b/WebCore/Android.mk
index 1fdbcbb..d5bc740 100644
--- a/WebCore/Android.mk
+++ b/WebCore/Android.mk
@@ -449,6 +449,7 @@
 	platform/graphics/StringTruncator.cpp \
 	platform/graphics/WidthIterator.cpp \
 	\
+	platform/graphics/android/AndroidAnimation.cpp \
 	platform/graphics/android/BitmapAllocatorAndroid.cpp \
 	platform/graphics/android/FontAndroid.cpp \
 	platform/graphics/android/FontCacheAndroid.cpp \
@@ -458,9 +459,11 @@
 	platform/graphics/android/GlyphMapAndroid.cpp \
 	platform/graphics/android/GradientAndroid.cpp \
 	platform/graphics/android/GraphicsContextAndroid.cpp \
+	platform/graphics/android/GraphicsLayerAndroid.cpp \
 	platform/graphics/android/ImageAndroid.cpp \
 	platform/graphics/android/ImageBufferAndroid.cpp \
 	platform/graphics/android/ImageSourceAndroid.cpp \
+	platform/graphics/android/LayerAndroid.cpp \
 	platform/graphics/android/PathAndroid.cpp \
 	platform/graphics/android/PatternAndroid.cpp \
 	platform/graphics/android/PlatformGraphicsContext.cpp \
diff --git a/WebCore/config.h b/WebCore/config.h
index 907b0d5..8fbed4f 100644
--- a/WebCore/config.h
+++ b/WebCore/config.h
@@ -91,6 +91,7 @@
 #ifndef ENABLE_SVG
 #define ENABLE_SVG 0
 #endif
+#define ENABLE_3D_RENDERING 0
 #define ENABLE_VIDEO 1
 #define ENABLE_WORKERS 1
 
diff --git a/WebCore/platform/android/PlatformBridge.h b/WebCore/platform/android/PlatformBridge.h
index fcdfac7..a1ed50a 100644
--- a/WebCore/platform/android/PlatformBridge.h
+++ b/WebCore/platform/android/PlatformBridge.h
@@ -33,6 +33,8 @@
 
 namespace WebCore {
 
+class FrameView;
+
 // An interface to the embedding layer, which has the ability to answer
 // questions about the system and so on...
 // This is very similar to ChromiumBridge and the two are likely to converge
@@ -62,6 +64,13 @@
         SubmitLabel
     };
     static String* globalLocalizedName(rawResId resId);
+
+#if USE(ACCELERATED_COMPOSITING)
+    // Those methods are used by the layers system
+    static void setRootLayer(const FrameView* view, int layer);
+    static void immediateRepaint(const FrameView* view);
+#endif // USE(ACCELERATED_COMPOSITING)
+
 };
 
 }
diff --git a/WebCore/platform/graphics/android/AndroidAnimation.cpp b/WebCore/platform/graphics/android/AndroidAnimation.cpp
new file mode 100644
index 0000000..9cdb0c7
--- /dev/null
+++ b/WebCore/platform/graphics/android/AndroidAnimation.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "AndroidAnimation.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Animation.h"
+#include "GraphicsLayerAndroid.h"
+
+#include "Timer.h"
+#include "TimingFunction.h"
+#include "UnitBezier.h"
+
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+void AndroidTransformAnimationValue::apply()
+{
+    if (m_doTranslation)
+        m_layer->setTranslation(m_translation);
+
+    if (m_doScaling)
+        m_layer->setScale(m_scale);
+
+    if (m_doRotation)
+        m_layer->setRotation(m_rotation);
+}
+
+void AndroidAnimationTimer::fired()
+{
+    if (!m_notificationSent) {
+        m_notificationSent = true;
+        if (m_layer && m_layer->client())
+            m_layer->client()->notifyAnimationStarted(m_layer, WTF::currentTime());
+    }
+}
+
+static long gDebugAndroidAnimationInstances;
+
+long AndroidAnimation::instancesCount()
+{
+    return gDebugAndroidAnimationInstances;
+}
+
+AndroidAnimation::AndroidAnimation(LayerAndroid* contentLayer,
+                 const Animation* animation,
+                 double beginTime) :
+    m_contentLayer(contentLayer),
+    m_beginTime(beginTime),
+    m_duration(animation->duration()),
+    m_iterationCount(animation->iterationCount()),
+    m_currentIteration(0),
+    m_direction(animation->direction()),
+    m_timingFunction(animation->timingFunction())
+{
+    if (!static_cast<int>(beginTime)) // time not set
+        m_beginTime = WTF::currentTime();
+
+    gDebugAndroidAnimationInstances++;
+}
+
+AndroidAnimation::AndroidAnimation(AndroidAnimation* anim) :
+    m_contentLayer(anim->m_contentLayer),
+    m_beginTime(anim->m_beginTime),
+    m_duration(anim->m_duration),
+    m_iterationCount(anim->m_iterationCount),
+    m_currentIteration(0),
+    m_direction(anim->m_direction),
+    m_timingFunction(anim->m_timingFunction)
+{
+    gDebugAndroidAnimationInstances++;
+}
+
+AndroidAnimation::~AndroidAnimation()
+{
+    gDebugAndroidAnimationInstances--;
+}
+
+float AndroidAnimation::currentProgress(double time)
+{
+    if (m_beginTime <= 0.000001) // overflow or not correctly set
+        m_beginTime = time;
+
+    m_elapsedTime = time - m_beginTime;
+
+    if (m_duration <= 0)
+      m_duration = 0.000001;
+
+    if (m_elapsedTime < 0) // animation not yet started.
+        return 0;
+
+    return m_elapsedTime / m_duration;
+}
+
+bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
+{
+    float progress = currentProgress(time);
+
+    int currentIteration = static_cast<int>(progress);
+    if (currentIteration != m_currentIteration)
+        if (m_direction == Animation::AnimationDirectionAlternate)
+            swapDirection();
+
+    m_currentIteration = currentIteration;
+    progress -= m_currentIteration;
+
+    if ((m_currentIteration >= m_iterationCount)
+          && (m_iterationCount != Animation::IterationCountInfinite))
+        return false;
+
+    if (m_timingFunction.type() != LinearTimingFunction) {
+        UnitBezier bezier(m_timingFunction.x1(),
+                          m_timingFunction.y1(),
+                          m_timingFunction.x2(),
+                          m_timingFunction.y2());
+        if (m_duration > 0)
+            progress = bezier.solve(progress, 1.0f / (200.0f * m_duration));
+    }
+
+    *finalProgress = progress;
+    return true;
+}
+
+PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(LayerAndroid* contentLayer,
+    float fromValue, float toValue,
+    const Animation* animation, double beginTime)
+{
+    return adoptRef(new AndroidOpacityAnimation(contentLayer,
+                    fromValue, toValue, animation, beginTime));
+}
+
+AndroidOpacityAnimation::AndroidOpacityAnimation(LayerAndroid* contentLayer,
+                           float fromValue, float toValue,
+                           const Animation* animation,
+                           double beginTime)
+    : AndroidAnimation(contentLayer, animation, beginTime),
+      m_fromValue(fromValue), m_toValue(toValue)
+{
+}
+
+AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim)
+    : AndroidAnimation(anim),
+    m_fromValue(anim->m_fromValue),
+    m_toValue(anim->m_toValue)
+{
+}
+
+AndroidAnimation* AndroidOpacityAnimation::copy()
+{
+    return new AndroidOpacityAnimation(this);
+}
+
+void AndroidOpacityAnimation::swapDirection()
+{
+    float v = m_toValue;
+    m_toValue = m_fromValue;
+    m_fromValue = m_toValue;
+}
+
+bool AndroidOpacityAnimation::evaluate(double time)
+{
+    float progress;
+    if (!checkIterationsAndProgress(time, &progress))
+        return false;
+
+    if (progress < 0) // we still want to be evaluated until we get progress > 0
+        return true;
+
+    float value = m_fromValue + ((m_toValue - m_fromValue) * progress);
+    m_result = AndroidOpacityAnimationValue::create(m_contentLayer.get(), value);
+    return true;
+}
+
+PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(LayerAndroid* contentLayer,
+    const Animation* animation, double beginTime)
+{
+    return adoptRef(new AndroidTransformAnimation(contentLayer, animation, beginTime));
+}
+
+AndroidTransformAnimation::AndroidTransformAnimation(LayerAndroid* contentLayer,
+                           const Animation* animation,
+                           double beginTime)
+    : AndroidAnimation(contentLayer, animation, beginTime),
+    m_doTranslation(false),
+    m_doScaling(false),
+    m_doRotation(false)
+{
+}
+
+AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim)
+    : AndroidAnimation(anim),
+    m_doTranslation(anim->m_doTranslation),
+    m_doScaling(anim->m_doScaling),
+    m_doRotation(anim->m_doRotation),
+    m_position(anim->m_position),
+    m_fromX(anim->m_fromX), m_fromY(anim->m_fromY), m_fromZ(anim->m_fromZ),
+    m_toX(anim->m_toX), m_toY(anim->m_toY), m_toZ(anim->m_toZ),
+    m_fromAngle(anim->m_fromAngle), m_toAngle(anim->m_toAngle),
+    m_fromScaleX(anim->m_fromScaleX), m_fromScaleY(anim->m_fromScaleY), m_fromScaleZ(anim->m_fromScaleZ),
+    m_toScaleX(anim->m_toScaleX), m_toScaleY(anim->m_toScaleY), m_toScaleZ(anim->m_toScaleZ)
+{
+}
+
+AndroidAnimation* AndroidTransformAnimation::copy()
+{
+    return new AndroidTransformAnimation(this);
+}
+
+void AndroidTransformAnimation::setRotation(float fA, float tA)
+{
+    m_fromAngle = fA;
+    m_toAngle = tA;
+    m_doRotation = true;
+}
+
+void AndroidTransformAnimation::setTranslation(float fX, float fY, float fZ,
+    float tX, float tY, float tZ)
+{
+    m_fromX = fX;
+    m_fromY = fY;
+    m_fromZ = fZ;
+    m_toX = tX;
+    m_toY = tY;
+    m_toZ = tZ;
+    m_doTranslation = true;
+}
+
+void AndroidTransformAnimation::setScale(float fX, float fY, float fZ,
+                                         float tX, float tY, float tZ)
+{
+    m_fromScaleX = fX;
+    m_fromScaleY = fY;
+    m_fromScaleZ = fZ;
+    m_toScaleX   = tX;
+    m_toScaleY   = tY;
+    m_toScaleZ   = tZ;
+    m_doScaling = true;
+}
+
+void AndroidTransformAnimation::swapDirection()
+{
+    if (m_doTranslation) {
+        float tx = m_toX;
+        m_toX = m_fromX;
+        m_fromX = tx;
+        float ty = m_toY;
+        m_toY = m_fromY;
+        m_fromY = ty;
+        float tz = m_toZ;
+        m_toZ = m_fromZ;
+        m_fromZ = tz;
+    }
+    if (m_doScaling) {
+        float sx = m_toScaleX;
+        m_toScaleX = m_fromScaleX;
+        m_fromScaleX = sx;
+        float sy = m_toScaleY;
+        m_toScaleY = m_fromScaleY;
+        m_fromScaleY = sy;
+    }
+    if (m_doRotation) {
+        float a = m_toAngle;
+        m_toAngle = m_fromAngle;
+        m_fromAngle = a;
+    }
+}
+
+bool AndroidTransformAnimation::evaluate(double time)
+{
+    float progress;
+    if (!checkIterationsAndProgress(time, &progress))
+        return false;
+
+    if (progress < 0) // we still want to be evaluated until we get progress > 0
+        return true;
+
+    float x = m_fromX + (m_toX - m_fromX) * progress;
+    float y = m_fromY + (m_toY - m_fromY) * progress;
+    float z = m_fromZ + (m_toZ - m_fromZ) * progress;
+    float sx = m_fromScaleX + (m_toScaleX - m_fromScaleX) * progress;
+    float sy = m_fromScaleY + (m_toScaleY - m_fromScaleY) * progress;
+    float sz = m_fromScaleZ + (m_toScaleZ - m_fromScaleZ) * progress;
+    float a = m_fromAngle + (m_toAngle - m_fromAngle) * progress;
+
+    FloatPoint translation(x, y);
+    FloatPoint3D scale(sx, sy, sz);
+    m_result = AndroidTransformAnimationValue::create(m_contentLayer.get(),
+                                                      translation, scale, a);
+    m_result->setDoTranslation(m_doTranslation);
+    m_result->setDoScaling(m_doScaling);
+    m_result->setDoRotation(m_doRotation);
+    return true;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/android/AndroidAnimation.h b/WebCore/platform/graphics/android/AndroidAnimation.h
new file mode 100644
index 0000000..05d6a76
--- /dev/null
+++ b/WebCore/platform/graphics/android/AndroidAnimation.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AndroidAnimation_h
+#define AndroidAnimation_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "FloatPoint.h"
+#include "FloatPoint3D.h"
+#include "HashMap.h"
+#include "LayerAndroid.h"
+#include "RefPtr.h"
+#include "Timer.h"
+#include "Vector.h"
+
+namespace WebCore {
+
+class AndroidAnimation;
+class GraphicsLayerAndroid;
+class TimingFunction;
+
+typedef Vector<RefPtr<AndroidAnimation> > AnimsVector;
+typedef HashMap<RefPtr<LayerAndroid>, AnimsVector* > LayersAnimsMap;
+
+class AndroidAnimationValue : public RefCounted<AndroidAnimationValue> {
+  public:
+    AndroidAnimationValue(LayerAndroid* layer) : m_layer(layer) { }
+    virtual ~AndroidAnimationValue() { }
+    virtual void apply() = 0;
+  protected:
+    RefPtr<LayerAndroid> m_layer;
+};
+
+class AndroidOpacityAnimationValue : public AndroidAnimationValue {
+  public:
+    static PassRefPtr<AndroidOpacityAnimationValue> create(
+                                   LayerAndroid* layer, float value) {
+        return adoptRef(new AndroidOpacityAnimationValue(layer, value));
+    }
+    AndroidOpacityAnimationValue(LayerAndroid* layer, float value) :
+      AndroidAnimationValue(layer), m_value(value) { }
+    virtual void apply() { m_layer->setOpacity(m_value); }
+  private:
+    float m_value;
+};
+
+class AndroidTransformAnimationValue : public AndroidAnimationValue {
+  public:
+    static PassRefPtr<AndroidTransformAnimationValue> create(
+                                   LayerAndroid* layer,
+                                   FloatPoint translation,
+                                   FloatPoint3D scale,
+                                   float rotation) {
+        return adoptRef(new AndroidTransformAnimationValue(layer, translation, scale, rotation));
+    }
+
+    AndroidTransformAnimationValue(LayerAndroid* layer,
+                                   FloatPoint translation,
+                                   FloatPoint3D scale,
+                                   float rotation) :
+      AndroidAnimationValue(layer),
+       m_doTranslation(false), m_doScaling(false), m_doRotation(false),
+       m_translation(translation), m_scale(scale), m_rotation(rotation) { }
+    void setDoTranslation(bool doTranslation) { m_doTranslation = doTranslation; }
+    void setDoScaling(bool doScaling) { m_doScaling = doScaling; }
+    void setDoRotation(bool doRotation) { m_doRotation = doRotation; }
+
+    virtual void apply();
+
+  private:
+    bool m_doTranslation;
+    bool m_doScaling;
+    bool m_doRotation;
+    FloatPoint m_translation;
+    FloatPoint3D m_scale;
+    float m_rotation;
+};
+
+class AndroidAnimation : public RefCounted<AndroidAnimation> {
+  public:
+    AndroidAnimation(LayerAndroid* contentLayer,
+                     const Animation* animation,
+                     double beginTime);
+    AndroidAnimation(AndroidAnimation* anim);
+
+    virtual ~AndroidAnimation();
+    virtual AndroidAnimation* copy() = 0;
+    float currentProgress(double time);
+    bool checkIterationsAndProgress(double time, float* finalProgress);
+    virtual void swapDirection() = 0;
+    virtual bool evaluate(double time) = 0;
+    LayerAndroid* contentLayer() { return m_contentLayer.get(); }
+    static long instancesCount();
+    void setLayer(LayerAndroid* layer) { m_contentLayer = layer; }
+    void setName(const String& name) { m_name = name; }
+    String name() { return m_name; }
+    virtual PassRefPtr<AndroidAnimationValue> result() = 0;
+
+  protected:
+    RefPtr<LayerAndroid> m_contentLayer;
+    double m_beginTime;
+    double m_elapsedTime;
+    double m_duration;
+    int m_iterationCount;
+    int m_currentIteration;
+    int m_direction;
+    TimingFunction m_timingFunction;
+    String m_name;
+};
+
+class AndroidOpacityAnimation : public AndroidAnimation {
+  public:
+    static PassRefPtr<AndroidOpacityAnimation> create(LayerAndroid* contentLayer,
+                                        float fromValue, float toValue,
+                                        const Animation* animation,
+                                        double beginTime);
+    AndroidOpacityAnimation(LayerAndroid* contentLayer,
+                            float fromValue, float toValue,
+                            const Animation* animation,
+                            double beginTime);
+    AndroidOpacityAnimation(AndroidOpacityAnimation* anim);
+    virtual AndroidAnimation* copy();
+    virtual PassRefPtr<AndroidAnimationValue> result() { return m_result.release(); }
+
+    virtual void swapDirection();
+    virtual bool evaluate(double time);
+
+  private:
+    RefPtr<AndroidOpacityAnimationValue> m_result;
+    float m_fromValue;
+    float m_toValue;
+};
+
+class AndroidTransformAnimation : public AndroidAnimation {
+  public:
+    static PassRefPtr<AndroidTransformAnimation> create(LayerAndroid* contentLayer,
+                                        const Animation* animation,
+                                        double beginTime);
+    AndroidTransformAnimation(LayerAndroid* contentLayer,
+                             const Animation* animation,
+                             double beginTime);
+
+    AndroidTransformAnimation(AndroidTransformAnimation* anim);
+    virtual AndroidAnimation* copy();
+
+    void setOriginalPosition(FloatPoint position) { m_position = position; }
+    void setRotation(float fA, float tA);
+    void setTranslation(float fX, float fY, float fZ,
+                        float tX, float tY, float tZ);
+    void setScale(float fX, float fY, float fZ,
+                  float tX, float tY, float tZ);
+    virtual void swapDirection();
+    virtual bool evaluate(double time);
+    virtual PassRefPtr<AndroidAnimationValue> result() { return m_result.release(); }
+
+  private:
+    RefPtr<AndroidTransformAnimationValue> m_result;
+    bool m_doTranslation;
+    bool m_doScaling;
+    bool m_doRotation;
+    FloatPoint m_position;
+    float m_fromX, m_fromY, m_fromZ;
+    float m_toX, m_toY, m_toZ;
+    float m_fromAngle, m_toAngle;
+    float m_fromScaleX, m_fromScaleY, m_fromScaleZ;
+    float m_toScaleX, m_toScaleY, m_toScaleZ;
+};
+
+class AndroidAnimationTimer : public TimerBase {
+  public:
+
+    AndroidAnimationTimer(GraphicsLayerAndroid* layer, double beginTime)
+    {
+        m_layer = layer;
+        m_notificationSent = false;
+        m_beginTime = beginTime;
+    }
+
+  private:
+    void fired();
+    GraphicsLayerAndroid* m_layer;
+    double m_beginTime;
+    bool m_notificationSent;
+};
+
+} // namespace WebCore
+
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // AndroidAnimation_h
diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
new file mode 100644
index 0000000..7637be9
--- /dev/null
+++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
@@ -0,0 +1,852 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "GraphicsLayerAndroid.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidAnimation.h"
+#include "Animation.h"
+#include "CString.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "PlatformBridge.h"
+#include "PlatformGraphicsContext.h"
+#include "RenderLayerBacking.h"
+#include "RenderView.h"
+#include "RotateTransformOperation.h"
+#include "ScaleTransformOperation.h"
+#include "SkCanvas.h"
+#include "TransformationMatrix.h"
+#include "TranslateTransformOperation.h"
+
+#include <cutils/log.h>
+#include <wtf/CurrentTime.h>
+
+#undef LOG
+#define LOG(...) android_printLog(ANDROID_LOG_DEBUG, "GraphicsLayer", __VA_ARGS__)
+#define MLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GraphicsLayer", __VA_ARGS__)
+#define TLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GraphicsLayer", __VA_ARGS__)
+
+#undef LOG
+#define LOG(...)
+#undef MLOG
+#define MLOG(...)
+#undef TLOG
+#define TLOG(...)
+#undef LAYER_DEBUG
+
+using namespace std;
+
+static bool gPaused;
+static double gPausedDelay;
+
+namespace WebCore {
+
+static int gDebugGraphicsLayerAndroidInstances = 0;
+inline int GraphicsLayerAndroid::instancesCount()
+{
+    return gDebugGraphicsLayerAndroidInstances;
+}
+
+static String propertyIdToString(AnimatedPropertyID property)
+{
+    switch (property) {
+    case AnimatedPropertyWebkitTransform:
+        return "transform";
+    case AnimatedPropertyOpacity:
+        return "opacity";
+    case AnimatedPropertyBackgroundColor:
+        return "backgroundColor";
+    case AnimatedPropertyInvalid:
+        ASSERT_NOT_REACHED();
+    }
+    ASSERT_NOT_REACHED();
+    return "";
+}
+
+GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation()
+{
+    return CompositingCoordinatesBottomUp;
+}
+
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+    return new GraphicsLayerAndroid(client);
+}
+
+GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) :
+    GraphicsLayer(client),
+    m_needsSyncChildren(false),
+    m_needsSyncMask(false),
+    m_needsRepaint(false),
+    m_needsDisplay(false),
+    m_haveContents(false),
+    m_haveImage(false),
+    m_translateX(0),
+    m_translateY(0),
+    m_currentTranslateX(0),
+    m_currentTranslateY(0),
+    m_currentPosition(0, 0)
+{
+    m_contentLayer = new LayerAndroid(true);
+    if (client) {
+      RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(client);
+      RenderLayer* renderLayer = backing->owningLayer();
+      m_contentLayer->setIsRootLayer(renderLayer->isRootLayer());
+      RenderView* view = static_cast<RenderView*>(renderLayer->renderer());
+      if (view->isPositioned() && view->style()->position() == FixedPosition) {
+          FloatPoint position(view->style()->left().value(),
+                              view->style()->right().value());
+          m_contentLayer->setFixedPosition(position);
+      }
+    }
+    gDebugGraphicsLayerAndroidInstances++;
+}
+
+GraphicsLayerAndroid::~GraphicsLayerAndroid()
+{
+    if (!parent() && m_frame && m_frame->view())
+        PlatformBridge::setRootLayer(m_frame->view(), 0);
+
+    gDebugGraphicsLayerAndroidInstances--;
+}
+
+void GraphicsLayerAndroid::setName(const String& name)
+{
+    GraphicsLayer::setName(name);
+}
+
+NativeLayer GraphicsLayerAndroid::nativeLayer() const
+{
+    LOG("(%x) nativeLayer", this);
+    return 0;
+}
+
+bool GraphicsLayerAndroid::setChildren(const Vector<GraphicsLayer*>& children)
+{
+    bool childrenChanged = GraphicsLayer::setChildren(children);
+    if (childrenChanged) {
+        m_needsSyncChildren = true;
+        askForSync();
+    }
+
+    return childrenChanged;
+}
+
+void GraphicsLayerAndroid::addChild(GraphicsLayer* childLayer)
+{
+#ifndef NDEBUG
+    const char* n = (static_cast<GraphicsLayerAndroid*>(childLayer))->m_name.latin1().data();
+    LOG("(%x) addChild: %x (%s)", this, childLayer, n);
+#endif
+    GraphicsLayer::addChild(childLayer);
+    m_needsSyncChildren = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+    LOG("(%x) addChild %x AtIndex %d", this, childLayer, index);
+    GraphicsLayer::addChildAtIndex(childLayer, index);
+    m_needsSyncChildren = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+    LOG("(%x) addChild %x Below %x", this, childLayer, sibling);
+    GraphicsLayer::addChildBelow(childLayer, sibling);
+    m_needsSyncChildren = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+    LOG("(%x) addChild %x Above %x", this, childLayer, sibling);
+    GraphicsLayer::addChildAbove(childLayer, sibling);
+    m_needsSyncChildren = true;
+    askForSync();
+}
+
+bool GraphicsLayerAndroid::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+    LOG("(%x) replaceChild %x by %x", this, oldChild, newChild);
+    bool ret = GraphicsLayer::replaceChild(oldChild, newChild);
+    m_needsSyncChildren = true;
+    askForSync();
+    return ret;
+}
+
+void GraphicsLayerAndroid::removeFromParent()
+{
+    LOG("(%x) removeFromParent()", this);
+    if (m_parent)
+        static_cast<GraphicsLayerAndroid*>(m_parent)->needsSyncChildren();
+    GraphicsLayer::removeFromParent();
+    m_needsSyncChildren = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::needsSyncChildren()
+{
+    m_needsSyncChildren = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setPosition(const FloatPoint& point)
+{
+    m_currentPosition = point;
+    m_needsDisplay = true;
+#ifdef LAYER_DEBUG_2
+    LOG("(%x) setPosition(%.2f,%.2f) pos(%.2f, %.2f) anchor(%.2f,%.2f) size(%.2f, %.2f)",
+        this, point.x(), point.y(), m_currentPosition.x(), m_currentPosition.y(),
+        m_anchorPoint.x(), m_anchorPoint.y(), m_size.width(), m_size.height());
+#endif
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setAnchorPoint(const FloatPoint3D& point)
+{
+    GraphicsLayer::setAnchorPoint(point);
+    m_contentLayer->setAnchorPoint(point);
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setSize(const FloatSize& size)
+{
+    if ((size.width() != m_size.width())
+          || (size.height() != m_size.height())) {
+        MLOG("(%x) setSize (%.2f,%.2f)", this, size.width(), size.height());
+        GraphicsLayer::setSize(size);
+        m_contentLayer->setSize(size);
+        askForSync();
+    }
+}
+
+void GraphicsLayerAndroid::setTransform(const TransformationMatrix& t)
+{
+    TransformationMatrix::DecomposedType tDecomp;
+    t.decompose(tDecomp);
+    LOG("(%x) setTransform, translate (%.2f, %.2f), mpos(%.2f,%.2f)",
+        this, tDecomp.translateX, tDecomp.translateY,
+        m_position.x(), m_position.y());
+
+    if ((m_currentTranslateX != tDecomp.translateX)
+          || (m_currentTranslateY != tDecomp.translateY)) {
+        m_currentTranslateX = tDecomp.translateX;
+        m_currentTranslateY = tDecomp.translateY;
+        m_needsDisplay = true;
+        askForSync();
+    }
+}
+
+void GraphicsLayerAndroid::setChildrenTransform(const TransformationMatrix& t)
+{
+    if (t == m_childrenTransform)
+       return;
+    LOG("(%x) setChildrenTransform", this);
+
+    GraphicsLayer::setChildrenTransform(t);
+    for (unsigned int i = 0; i < m_children.size(); i++) {
+        GraphicsLayer* layer = m_children[i];
+        layer->setTransform(t);
+        if (layer->children().size())
+            layer->setChildrenTransform(t);
+    }
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setMaskLayer(GraphicsLayer* layer)
+{
+    if (layer == m_maskLayer)
+      return;
+
+    GraphicsLayer::setMaskLayer(layer);
+    m_needsSyncMask = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setMasksToBounds(bool masksToBounds)
+{
+    GraphicsLayer::setMasksToBounds(masksToBounds);
+    m_needsSyncMask = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setDrawsContent(bool drawsContent)
+{
+    GraphicsLayer::setDrawsContent(drawsContent);
+    m_contentLayer->setDrawsContent(m_drawsContent);
+
+    if (m_drawsContent) {
+        m_haveContents = true;
+        m_contentLayer->setHaveContents(true);
+        setNeedsDisplay();
+    }
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setBackgroundColor(const Color& color)
+{
+    LOG("(%x) setBackgroundColor", this);
+    GraphicsLayer::setBackgroundColor(color);
+    m_contentLayer->setBackgroundColor(color);
+    m_haveContents = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::clearBackgroundColor()
+{
+    LOG("(%x) clearBackgroundColor", this);
+    GraphicsLayer::clearBackgroundColor();
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setContentsOpaque(bool opaque)
+{
+    LOG("(%x) setContentsOpaque (%d)", this, opaque);
+    GraphicsLayer::setContentsOpaque(opaque);
+    m_haveContents = true;
+    m_contentLayer->setHaveContents(true);
+    m_contentLayer->setDrawsContent(true);
+    askForSync();
+}
+
+void GraphicsLayerAndroid::setOpacity(float opacity)
+{
+    LOG("(%x) setOpacity: %.2f", this, opacity);
+    float clampedOpacity = max(0.0f, min(opacity, 1.0f));
+
+    if (clampedOpacity == m_opacity)
+        return;
+
+    MLOG("(%x) setFinalOpacity: %.2f=>%.2f (%.2f)", this,
+        opacity, clampedOpacity, m_opacity);
+    GraphicsLayer::setOpacity(clampedOpacity);
+    askForSync();
+}
+
+bool GraphicsLayerAndroid::repaintAll()
+{
+     LOG("(%x) repaintAll", this);
+     bool ret = false;
+     for (unsigned int i = 0; i < m_children.size(); i++) {
+         GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]);
+         if (layer && layer->repaintAll())
+             ret = true;
+     }
+     int nbRects = m_invalidatedRects.size();
+
+     for (int i = 0; !gPaused && i < nbRects; i++) {
+         FloatRect rect = m_invalidatedRects[i];
+         if (repaint(rect))
+             ret = true;
+     }
+     if (!gPaused) {
+         m_needsRepaint = false;
+         m_invalidatedRects.clear();
+     }
+     return ret;
+}
+
+void GraphicsLayerAndroid::setNeedsDisplay()
+{
+    LOG("(%x) setNeedsDisplay()", this);
+    FloatRect rect(0, 0, m_size.width(), m_size.height());
+    setNeedsDisplayInRect(rect);
+}
+
+void GraphicsLayerAndroid::setFrame(Frame* f)
+{
+    m_frame = f;
+}
+
+void GraphicsLayerAndroid::sendImmediateRepaint()
+{
+    LOG("(%x) sendImmediateRepaint()", this);
+    GraphicsLayerAndroid* rootGraphicsLayer = this;
+
+    while (rootGraphicsLayer->parent())
+        rootGraphicsLayer = static_cast<GraphicsLayerAndroid*>(rootGraphicsLayer->parent());
+
+    if (rootGraphicsLayer->m_frame
+        && rootGraphicsLayer->m_frame->view()) {
+        LayerAndroid* copyLayer = new LayerAndroid(m_contentLayer.get());
+        TLOG("(%x) sendImmediateRepaint, copy the layer, (%.2f,%.2f => %.2f,%.2f)",
+            this, m_contentLayer->size().width(), m_contentLayer->size().height(),
+            copyLayer->size().width(), copyLayer->size().height());
+        PlatformBridge::setRootLayer(m_frame->view(), (int)copyLayer);
+        PlatformBridge::immediateRepaint(m_frame->view());
+    }
+}
+
+bool GraphicsLayerAndroid::repaint(const FloatRect& rect)
+{
+    LOG("(%x) repaint(%.2f,%.2f,%.2f,%.2f), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ",
+        this, rect.x(), rect.y(), rect.width(), rect.height(),
+        gPaused, m_needsRepaint, m_haveContents);
+
+    m_contentLayer->setDrawsContent(true);
+
+    if (!gPaused && m_haveContents && m_needsRepaint) {
+        SkAutoPictureRecord arp(m_contentLayer->recordContext(), m_size.width(), m_size.height());
+        SkCanvas* recordingCanvas = arp.getRecordingCanvas();
+
+        if (!recordingCanvas)
+            return false;
+
+        if ((rect.width() > 0.5) && (rect.height() > 0.5)) {
+            IntRect r((int)rect.x(), (int)rect.y(),
+                  (int)rect.width(), (int)rect.height());
+
+            PlatformGraphicsContext pgc(recordingCanvas, 0);
+            GraphicsContext gc(&pgc);
+
+            // with SkPicture, we request the entire layer's content.
+            r.setX(0);
+            r.setY(0);
+            r.setWidth(m_contentLayer->size().width());
+            r.setHeight(m_contentLayer->size().height());
+            paintGraphicsLayerContents(gc, r);
+
+            TLOG("(%x) repaint(%.2f,%.2f,%.2f,%.2f) on (%.2f,%.2f) contentlayer(%.2f,%.2f,%.2f,%.2f)paintGraphicsLayer called!",
+                this, rect.x(), rect.y(), rect.width(),
+                rect.height(), m_size.width(), m_size.height(),
+                m_contentLayer->position().x(),
+                m_contentLayer->position().y(),
+                m_contentLayer->size().width(),
+                m_contentLayer->size().height());
+        }
+        return true;
+    }
+    return false;
+}
+
+void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect)
+{
+    for (unsigned int i = 0; i < m_children.size(); i++) {
+        GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]);
+        if (layer) {
+            FloatRect childrenRect(m_position.x() + m_translateX + rect.x(),
+                                   m_position.y() + m_translateY + rect.y(),
+                                   rect.width(), rect.height());
+            layer->setNeedsDisplayInRect(childrenRect);
+        }
+    }
+    if (!m_haveImage && !drawsContent()) {
+        LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...",
+            this, rect.x(), rect.y(), rect.width(), rect.height());
+        return;
+    }
+
+    const size_t maxDirtyRects = 8;
+    for (size_t i = 0; i < m_invalidatedRects.size(); ++i) {
+        if (m_invalidatedRects[i].contains(rect))
+            return;
+    }
+
+#ifdef LAYER_DEBUG
+    LOG("(%x) setNeedsDisplayInRect(%d) - (%.2f, %.2f, %.2f, %.2f)", this,
+        m_needsRepaint, rect.x(), rect.y(), rect.width(), rect.height());
+#endif
+
+    if (m_invalidatedRects.size() < maxDirtyRects)
+        m_invalidatedRects.append(rect);
+    else
+        m_invalidatedRects[0].unite(rect);
+
+    m_needsRepaint = true;
+    askForSync();
+}
+
+void GraphicsLayerAndroid::pauseDisplay(bool state)
+{
+    gPaused = state;
+    if (gPaused)
+        gPausedDelay = WTF::currentTime() + 1;
+}
+
+bool GraphicsLayerAndroid::addAnimation(const KeyframeValueList& valueList,
+                                        const IntSize& boxSize,
+                                        const Animation* anim,
+                                        const String& keyframesName,
+                                        double beginTime)
+{
+    if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
+    return false;
+
+    bool createdAnimations = false;
+    if (valueList.property() == AnimatedPropertyWebkitTransform) {
+        createdAnimations = createTransformAnimationsFromKeyframes(valueList,
+                                                                   anim,
+                                                                   keyframesName,
+                                                                   beginTime,
+                                                                   boxSize);
+    } else {
+        createdAnimations = createAnimationFromKeyframes(valueList,
+                                                         anim,
+                                                         keyframesName,
+                                                         beginTime);
+    }
+    askForSync();
+    return createdAnimations;
+}
+
+bool GraphicsLayerAndroid::createAnimationFromKeyframes(const KeyframeValueList& valueList,
+     const Animation* animation, const String& keyframesName, double beginTime)
+{
+    bool isKeyframe = valueList.size() > 2;
+    TLOG("createAnimationFromKeyframes(%d), name(%s) beginTime(%.2f)",
+        isKeyframe, keyframesName.latin1().data(), beginTime);
+    // TODO: handles keyframe animations correctly
+
+    switch (valueList.property()) {
+    case AnimatedPropertyInvalid: break;
+    case AnimatedPropertyWebkitTransform: break;
+    case AnimatedPropertyBackgroundColor: break;
+    case AnimatedPropertyOpacity: {
+        MLOG("ANIMATEDPROPERTYOPACITY");
+        const FloatAnimationValue* startVal =
+            static_cast<const FloatAnimationValue*>(valueList.at(0));
+        const FloatAnimationValue* endVal =
+            static_cast<const FloatAnimationValue*>(valueList.at(1));
+        RefPtr<AndroidOpacityAnimation> anim = AndroidOpacityAnimation::create(m_contentLayer.get(),
+                                                                               startVal->value(),
+                                                                               endVal->value(),
+                                                                               animation,
+                                                                               beginTime);
+        if (keyframesName.isEmpty())
+            anim->setName(propertyIdToString(valueList.property()));
+        else
+            anim->setName(keyframesName);
+
+        m_contentLayer->addAnimation(anim.release());
+        AndroidAnimationTimer* timer = new AndroidAnimationTimer(this, WTF::currentTime());
+        timer->startOneShot(0);
+        return true;
+    } break;
+    }
+    return false;
+}
+
+bool GraphicsLayerAndroid::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList,
+                                                                  const Animation* animation,
+                                                                  const String& keyframesName,
+                                                                  double beginTime,
+                                                                  const IntSize& boxSize)
+{
+    ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
+    TLOG("createTransformAnimationFromKeyframes, name(%s) beginTime(%.2f)",
+        keyframesName.latin1().data(), beginTime);
+
+    TransformOperationList functionList;
+    bool listsMatch, hasBigRotation;
+    fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation);
+
+    // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation.
+    // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation
+    // if that's not true as well.
+
+    bool isMatrixAnimation = !listsMatch;
+    size_t numAnimations = isMatrixAnimation ? 1 : functionList.size();
+    bool isKeyframe = valueList.size() > 2;
+
+    float fromTranslateX = 0;
+    float fromTranslateY = 0;
+    float fromTranslateZ = 0;
+    float toTranslateX   = 0;
+    float toTranslateY   = 0;
+    float toTranslateZ   = 0;
+    float fromAngle      = 0;
+    float toAngle        = 0;
+    float fromScaleX     = 1;
+    float fromScaleY     = 1;
+    float fromScaleZ     = 1;
+    float toScaleX       = 1;
+    float toScaleY       = 1;
+    float toScaleZ       = 1;
+
+    bool doTranslation = false;
+    bool doRotation = false;
+    bool doScaling = false;
+
+    TLOG("(%x) animateTransform, valueList(%d) functionList(%d) duration(%.2f)", this,
+        valueList.size(), functionList.size(), animation->duration());
+
+    for (unsigned int i = 0; i < valueList.size(); i++) {
+        const TransformOperations* operation = ((TransformAnimationValue*)valueList.at(i))->value();
+        Vector<RefPtr<TransformOperation> > ops = operation->operations();
+        TLOG("(%x) animateTransform, dealing with the %d operation, with %d ops", this, i, ops.size());
+        for (unsigned int j = 0; j < ops.size(); j++) {
+            TransformOperation* op = ops[j].get();
+            TLOG("(%x) animateTransform, dealing with the %d:%d operation, current op: %d (translate is %d, rotate %d, scale %d)",
+                this, i, j, op->getOperationType(), TransformOperation::TRANSLATE, TransformOperation::ROTATE, TransformOperation::SCALE);
+            if (op->getOperationType() == TransformOperation::TRANSLATE) {
+                TranslateTransformOperation* translateOperation = (TranslateTransformOperation*) op;
+                IntSize bounds(m_size.width(), m_size.height());
+                float x = translateOperation->x(bounds);
+                float y = translateOperation->y(bounds);
+                float z = translateOperation->z(bounds);
+                if (!i) {
+                    fromTranslateX = x;
+                    fromTranslateY = y;
+                    fromTranslateZ = z;
+                } else {
+                    toTranslateX = x;
+                    toTranslateY = y;
+                    toTranslateZ = z;
+                }
+                TLOG("(%x) animateTransform, the %d operation is a translation(%.2f,%.2f,%.2f)",
+                    this, j, x, y, z);
+                doTranslation = true;
+            } else if (op->getOperationType() == TransformOperation::TRANSLATE_X) {
+                TranslateTransformOperation* translateOperation = (TranslateTransformOperation*) op;
+                IntSize bounds(m_size.width(), m_size.height());
+                float x = translateOperation->x(bounds);
+                if (!i)
+                    fromTranslateX = x;
+                else
+                    toTranslateX = x;
+                TLOG("(%x) animateTransform, the %d operation is a translation_x(%.2f)",
+                    this, j, x);
+                doTranslation = true;
+            } else if (op->getOperationType() == TransformOperation::TRANSLATE_Y) {
+                TranslateTransformOperation* translateOperation = (TranslateTransformOperation*) op;
+                IntSize bounds(m_size.width(), m_size.height());
+                float y = translateOperation->y(bounds);
+                if (!i)
+                    fromTranslateY = y;
+                else
+                    toTranslateY = y;
+                TLOG("(%x) animateTransform, the %d operation is a translation_y(%.2f)",
+                    this, j, y);
+                doTranslation = true;
+            } else if ((op->getOperationType() == TransformOperation::ROTATE)
+                          || (op->getOperationType() == TransformOperation::ROTATE_X)
+                          || (op->getOperationType() == TransformOperation::ROTATE_Y)) {
+                LOG("(%x) animateTransform, the %d operation is a rotation", this, j);
+                RotateTransformOperation* rotateOperation = (RotateTransformOperation*) op;
+                float angle = rotateOperation->angle();
+                TLOG("(%x) animateTransform, the %d operation is a rotation (%d), of angle %.2f",
+                    this, j, op->getOperationType(), angle);
+
+                if (!i)
+                    fromAngle = angle;
+                else
+                    toAngle = angle;
+                doRotation = true;
+            } else if (op->getOperationType() == TransformOperation::SCALE_X) {
+                ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op;
+                if (!i)
+                    fromScaleX = scaleOperation->x();
+                else
+                    toScaleX = scaleOperation->x();
+                doScaling = true;
+            } else if (op->getOperationType() == TransformOperation::SCALE_Y) {
+                ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op;
+                if (!i)
+                    fromScaleY = scaleOperation->y();
+                else
+                    toScaleY = scaleOperation->y();
+                doScaling = true;
+            } else if (op->getOperationType() == TransformOperation::SCALE_Z) {
+                ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op;
+                if (!i)
+                    fromScaleZ = scaleOperation->z();
+                else
+                    toScaleZ = scaleOperation->z();
+                doScaling = true;
+            } else if (op->getOperationType() == TransformOperation::SCALE) {
+                ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op;
+                if (!i) {
+                    fromScaleX = scaleOperation->x();
+                    fromScaleY = scaleOperation->y();
+                    fromScaleZ = scaleOperation->z();
+                } else {
+                    toScaleX = scaleOperation->x();
+                    toScaleY = scaleOperation->y();
+                    toScaleZ = scaleOperation->z();
+                }
+                doScaling = true;
+            } else {
+                TLOG("(%x) animateTransform, the %d operation is not a rotation (%d)",
+                    this, j, op->getOperationType());
+            }
+        }
+    }
+
+    RefPtr<AndroidTransformAnimation> anim = AndroidTransformAnimation::create(m_contentLayer.get(),
+                                                                               animation, beginTime);
+
+    if (keyframesName.isEmpty())
+        anim->setName(propertyIdToString(valueList.property()));
+    else
+        anim->setName(keyframesName);
+
+    anim->setOriginalPosition(m_position);
+
+    if (doTranslation)
+        anim->setTranslation(fromTranslateX, fromTranslateY, fromTranslateZ,
+                         toTranslateX, toTranslateY, toTranslateZ);
+    if (doRotation)
+        anim->setRotation(fromAngle, toAngle);
+    if (doScaling)
+        anim->setScale(fromScaleX, fromScaleY, fromScaleZ,
+                       toScaleX, toScaleY, toScaleZ);
+    m_contentLayer->addAnimation(anim.release());
+
+    AndroidAnimationTimer* timer = new AndroidAnimationTimer(this, WTF::currentTime());
+    timer->startOneShot(0);
+    return true;
+}
+
+void GraphicsLayerAndroid::removeAnimationsForProperty(AnimatedPropertyID anID)
+{
+    TLOG("NRO removeAnimationsForProperty(%d)", anID);
+    m_contentLayer->removeAnimation(propertyIdToString(anID));
+    askForSync();
+}
+
+void GraphicsLayerAndroid::removeAnimationsForKeyframes(const String& keyframesName)
+{
+    TLOG("NRO removeAnimationsForKeyframes(%s)", keyframesName.latin1().data());
+    m_contentLayer->removeAnimation(keyframesName);
+    askForSync();
+}
+
+void GraphicsLayerAndroid::pauseAnimation(const String& keyframesName)
+{
+    TLOG("NRO pauseAnimation(%s)", keyframesName.latin1().data());
+}
+
+void GraphicsLayerAndroid::suspendAnimations(double time)
+{
+    TLOG("NRO suspendAnimations(%.2f)", time);
+}
+
+void GraphicsLayerAndroid::resumeAnimations()
+{
+    TLOG("NRO resumeAnimations()");
+}
+
+void GraphicsLayerAndroid::setContentsToImage(Image* image)
+{
+    TLOG("(%x) setContentsToImage", this, image);
+    if (image) {
+        m_haveContents = true;
+        m_contentLayer->setHaveContents(true);
+        m_contentLayer->setDrawsContent(true);
+        m_contentLayer->setHaveImage(true);
+        if (!m_haveImage) {
+            m_haveImage = true;
+            setNeedsDisplay();
+            askForSync();
+        }
+    } else
+        m_contentLayer->setHaveImage(false);
+}
+
+PlatformLayer* GraphicsLayerAndroid::platformLayer() const
+{
+    LOG("platformLayer");
+    return (PlatformLayer*) m_contentLayer.get();
+}
+
+#ifndef NDEBUG
+void GraphicsLayerAndroid::setDebugBackgroundColor(const Color& color)
+{
+}
+
+void GraphicsLayerAndroid::setDebugBorder(const Color& color, float borderWidth)
+{
+}
+#endif
+
+void GraphicsLayerAndroid::setZPosition(float position)
+{
+    LOG("(%x) setZPosition: %.2f", this, position);
+    GraphicsLayer::setZPosition(position);
+    askForSync();
+}
+
+void GraphicsLayerAndroid::askForSync()
+{
+    if (m_client)
+        m_client->notifySyncRequired(this);
+}
+
+void GraphicsLayerAndroid::syncChildren()
+{
+    if (m_needsSyncChildren) {
+        m_contentLayer->removeAllChildren();
+        for (unsigned int i = 0; i < m_children.size(); i++) {
+            m_contentLayer->addChildren(
+                (static_cast<GraphicsLayerAndroid*>(m_children[i]))->contentLayer());
+        }
+        m_needsSyncChildren = false;
+    }
+}
+
+void GraphicsLayerAndroid::syncMask()
+{
+    if (m_needsSyncMask) {
+        if (m_maskLayer) {
+            GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_maskLayer);
+            LayerAndroid* mask = reinterpret_cast<LayerAndroid*>(layer->platformLayer());
+            m_contentLayer->setMaskLayer(mask);
+        } else
+            m_contentLayer->setMaskLayer(0);
+
+        m_contentLayer->setMasksToBounds(m_masksToBounds);
+        m_needsSyncMask = false;
+    }
+}
+
+void GraphicsLayerAndroid::syncPositionState()
+{
+     if (m_needsDisplay) {
+         m_translateX = m_currentTranslateX;
+         m_translateY = m_currentTranslateY;
+         m_position = m_currentPosition;
+         FloatPoint translation(m_currentTranslateX, m_currentTranslateY);
+         m_contentLayer->setTranslation(translation);
+         m_contentLayer->setPosition(m_currentPosition);
+         m_needsDisplay = false;
+     }
+}
+
+void GraphicsLayerAndroid::syncCompositingState()
+{
+    for (unsigned int i = 0; i < m_children.size(); i++) {
+        GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]);
+        layer->syncCompositingState();
+    }
+
+    syncChildren();
+    syncMask();
+    syncPositionState();
+
+    if (!gPaused || WTF::currentTime() >= gPausedDelay)
+        repaintAll();
+}
+
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
new file mode 100644
index 0000000..fc88fbf
--- /dev/null
+++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GraphicsLayerAndroid_h
+#define GraphicsLayerAndroid_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "FloatRect.h"
+#include "Frame.h"
+#include "GraphicsLayer.h"
+#include "GraphicsLayerClient.h"
+#include "LayerAndroid.h"
+#include "RefPtr.h"
+#include "Vector.h"
+
+class FloatPoint3D;
+class Image;
+
+namespace WebCore {
+
+class GraphicsLayerAndroid : public GraphicsLayer {
+public:
+
+    GraphicsLayerAndroid(GraphicsLayerClient*);
+    virtual ~GraphicsLayerAndroid();
+
+    virtual void setName(const String&);
+
+    // for hosting this GraphicsLayer in a native layer hierarchy
+    virtual NativeLayer nativeLayer() const;
+
+    virtual bool setChildren(const Vector<GraphicsLayer*>&);
+    virtual void addChild(GraphicsLayer*);
+    virtual void addChildAtIndex(GraphicsLayer*, int index);
+    virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+    virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+    virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+
+    virtual void removeFromParent();
+
+    virtual void setPosition(const FloatPoint&);
+    virtual void setAnchorPoint(const FloatPoint3D&);
+    virtual void setSize(const FloatSize&);
+
+    virtual void setTransform(const TransformationMatrix&);
+
+    virtual void setChildrenTransform(const TransformationMatrix&);
+
+    virtual void setMaskLayer(GraphicsLayer*);
+    virtual void setMasksToBounds(bool);
+    virtual void setDrawsContent(bool);
+
+    virtual void setBackgroundColor(const Color&);
+    virtual void clearBackgroundColor();
+
+    virtual void setContentsOpaque(bool);
+
+    virtual void setOpacity(float);
+
+    virtual void setNeedsDisplay();
+    virtual void setNeedsDisplayInRect(const FloatRect&);
+
+    virtual bool addAnimation(const KeyframeValueList& valueList,
+                              const IntSize& boxSize,
+                              const Animation* anim,
+                              const String& keyframesName,
+                              double beginTime);
+    bool createTransformAnimationsFromKeyframes(const KeyframeValueList&,
+                                                const Animation*,
+                                                const String& keyframesName,
+                                                double beginTime,
+                                                const IntSize& boxSize);
+    bool createAnimationFromKeyframes(const KeyframeValueList&,
+                                      const Animation*,
+                                      const String& keyframesName,
+                                      double beginTime);
+
+    virtual void removeAnimationsForProperty(AnimatedPropertyID);
+    virtual void removeAnimationsForKeyframes(const String& keyframesName);
+    virtual void pauseAnimation(const String& keyframesName);
+
+    virtual void suspendAnimations(double time);
+    virtual void resumeAnimations();
+
+    virtual void setContentsToImage(Image*);
+    bool repaintAll();
+    virtual PlatformLayer* platformLayer() const;
+
+    void pauseDisplay(bool state);
+
+#ifndef NDEBUG
+    virtual void setDebugBackgroundColor(const Color&);
+    virtual void setDebugBorder(const Color&, float borderWidth);
+#endif
+
+    virtual void setZPosition(float);
+
+    void askForSync();
+    void syncPositionState();
+    void needsSyncChildren();
+    void syncChildren();
+    void syncMask();
+    virtual void syncCompositingState();
+    void setFrame(Frame*);
+
+    void sendImmediateRepaint();
+    LayerAndroid* contentLayer() { return m_contentLayer.get(); }
+
+    static int instancesCount();
+
+private:
+
+    bool repaint(const FloatRect& rect);
+
+    bool m_needsSyncChildren;
+    bool m_needsSyncMask;
+    bool m_needsRepaint;
+    bool m_needsDisplay;
+
+    bool m_haveContents;
+    bool m_haveImage;
+
+    float m_translateX;
+    float m_translateY;
+    float m_currentTranslateX;
+    float m_currentTranslateY;
+
+    FloatPoint m_currentPosition;
+
+    RefPtr<Frame> m_frame;
+
+    Vector<FloatRect> m_invalidatedRects;
+
+    RefPtr<LayerAndroid> m_contentLayer;
+};
+
+} // namespace WebCore
+
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerAndroid_h
diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp
new file mode 100644
index 0000000..347021a
--- /dev/null
+++ b/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -0,0 +1,353 @@
+#include "config.h"
+#include "LayerAndroid.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidAnimation.h"
+#include "CString.h"
+#include "GraphicsLayerAndroid.h"
+#include "PlatformGraphicsContext.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include "RenderView.h"
+#include "SkDevice.h"
+#include "SkDrawFilter.h"
+#include <wtf/CurrentTime.h>
+
+#define LAYER_DEBUG // Add diagonals for debugging
+#undef LAYER_DEBUG
+
+namespace WebCore {
+
+static int gDebugLayerAndroidInstances;
+inline int LayerAndroid::instancesCount()
+{
+    return gDebugLayerAndroidInstances;
+}
+
+class OpacityDrawFilter : public SkDrawFilter {
+ public:
+    OpacityDrawFilter(int opacity) : m_opacity(opacity) { }
+    virtual bool filter(SkCanvas* canvas, SkPaint* paint, Type)
+    {
+        m_previousOpacity = paint->getAlpha();
+        paint->setAlpha(m_opacity);
+        return true;
+    }
+    virtual void restore(SkCanvas* canvas, SkPaint* paint, Type)
+    {
+        paint->setAlpha(m_previousOpacity);
+    }
+ private:
+    int m_opacity;
+    int m_previousOpacity;
+};
+
+PassRefPtr<LayerAndroid> LayerAndroid::create(bool isRootLayer)
+{
+    return adoptRef(new LayerAndroid(isRootLayer));
+}
+
+LayerAndroid::LayerAndroid(bool isRootLayer) :
+    m_doRotation(false),
+    m_isRootLayer(isRootLayer),
+    m_isFixed(false),
+    m_haveContents(false),
+    m_drawsContent(true),
+    m_haveImage(false),
+    m_haveClip(false),
+    m_backgroundColorSet(false),
+    m_angleTransform(0),
+    m_opacity(1),
+    m_size(0, 0),
+    m_position(0, 0),
+    m_translation(0, 0),
+    m_fixedPosition(0, 0),
+    m_anchorPoint(0, 0, 0),
+    m_scale(1, 1, 1),
+    m_recordingPicture(0)
+{
+    gDebugLayerAndroidInstances++;
+}
+
+LayerAndroid::LayerAndroid(LayerAndroid* layer) :
+    m_doRotation(layer->m_doRotation),
+    m_isRootLayer(layer->m_isRootLayer),
+    m_isFixed(layer->m_isFixed),
+    m_haveContents(layer->m_haveContents),
+    m_drawsContent(layer->m_drawsContent),
+    m_haveImage(layer->m_haveImage),
+    m_haveClip(layer->m_haveClip),
+    m_backgroundColorSet(layer->m_backgroundColorSet),
+    m_angleTransform(layer->m_angleTransform),
+    m_opacity(layer->m_opacity),
+    m_size(layer->m_size),
+    m_position(layer->m_position),
+    m_translation(layer->m_translation),
+    m_fixedPosition(layer->m_fixedPosition),
+    m_anchorPoint(layer->m_anchorPoint),
+    m_scale(layer->m_scale)
+{
+    if (layer->m_recordingPicture) {
+        layer->m_recordingPicture->ref();
+        m_recordingPicture = layer->m_recordingPicture;
+    } else
+        m_recordingPicture = 0;
+
+    for (unsigned int i = 0; i < layer->m_children.size(); i++)
+        m_children.append(adoptRef(new LayerAndroid(layer->m_children[i].get())));
+
+    KeyframesMap::const_iterator end = layer->m_animations.end();
+    for (KeyframesMap::const_iterator it = layer->m_animations.begin(); it != end; ++it)
+        m_animations.add((it->second)->name(), adoptRef((it->second)->copy()));
+
+    end = m_animations.end();
+    for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it)
+        (it->second)->setLayer(this);
+
+    gDebugLayerAndroidInstances++;
+}
+
+LayerAndroid::~LayerAndroid()
+{
+    m_recordingPicture->safeUnref();
+    m_children.clear();
+    m_animations.clear();
+    gDebugLayerAndroidInstances--;
+}
+
+static int gDebugNbAnims = 0;
+
+Vector<RefPtr<AndroidAnimationValue> >* LayerAndroid::evaluateAnimations() const
+{
+    double time = WTF::currentTime();
+    Vector<RefPtr<AndroidAnimationValue> >* result = new Vector<RefPtr<AndroidAnimationValue> >();
+    gDebugNbAnims = 0;
+    if (evaluateAnimations(time, result))
+      return result;
+    return 0;
+}
+
+bool LayerAndroid::hasAnimations() const
+{
+    for (unsigned int i = 0; i < m_children.size(); i++) {
+        if (m_children[i]->hasAnimations())
+            return true;
+    }
+    return !!m_animations.size();
+}
+
+bool LayerAndroid::evaluateAnimations(double time,
+                                      Vector<RefPtr<AndroidAnimationValue> >* result) const
+{
+    bool hasRunningAnimations = false;
+    for (unsigned int i = 0; i < m_children.size(); i++) {
+        if (m_children[i]->evaluateAnimations(time, result))
+            hasRunningAnimations = true;
+    }
+    KeyframesMap::const_iterator end = m_animations.end();
+    for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
+        gDebugNbAnims++;
+        if ((it->second)->evaluate(time)) {
+            result->append((it->second)->result());
+            hasRunningAnimations = true;
+        }
+    }
+    
+    return hasRunningAnimations;
+}
+
+void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> anim)
+{
+    m_animations.add(anim->name(), anim);
+}
+
+void LayerAndroid::removeAnimation(const String& name)
+{
+    m_animations.remove(name);
+}
+
+void LayerAndroid::setFixedPosition(FloatPoint position)
+{
+    m_fixedPosition = position;
+    m_isFixed = true;
+}
+
+void LayerAndroid::setDrawsContent(bool drawsContent)
+{
+    m_drawsContent = drawsContent;
+    for (unsigned int i = 0; i < m_children.size(); i++) {
+        LayerAndroid* layer = m_children[i].get();
+        layer->setDrawsContent(drawsContent);
+    }
+}
+
+// We only use the bounding rect of the layer as mask...
+// TODO: use a real mask?
+void LayerAndroid::setMaskLayer(LayerAndroid* layer)
+{
+    if (layer)
+        m_haveClip = true;
+}
+
+void LayerAndroid::setMasksToBounds(bool masksToBounds)
+{
+    m_haveClip = masksToBounds;
+}
+
+void LayerAndroid::setBackgroundColor(const Color& color)
+{
+    m_backgroundColor = color;
+    m_backgroundColorSet = true;
+    setHaveContents(true);
+    setDrawsContent(true);
+}
+
+static int gDebugChildLevel;
+
+void LayerAndroid::paintOn(float scrollX, float scrollY, float scale, SkCanvas* canvas)
+{
+    gDebugChildLevel = 0;
+    paintChildren(scrollX, scrollY, scale, canvas, 1);
+}
+
+void LayerAndroid::setClip(SkCanvas* canvas)
+{
+    SkRect clip;
+    clip.fLeft = m_position.x() + m_translation.x();
+    clip.fTop = m_position.y() + m_translation.y();
+    clip.fRight = clip.fLeft + m_size.width();
+    clip.fBottom = clip.fTop + m_size.height();
+    canvas->clipRect(clip);
+}
+
+void LayerAndroid::paintChildren(float scrollX, float scrollY,
+                                 float scale, SkCanvas* canvas,
+                                 float opacity)
+{
+    canvas->save();
+
+    if (m_haveClip)
+        setClip(canvas);
+
+    paintMe(scrollX, scrollY, scale, canvas, opacity);
+    canvas->translate(m_position.x() + m_translation.x(),
+                      m_position.y() + m_translation.y());
+
+    for (unsigned int i = 0; i < m_children.size(); i++) {
+        LayerAndroid* layer = m_children[i].get();
+        if (layer) {
+            gDebugChildLevel++;
+            layer->paintChildren(scrollX, scrollY, scale, canvas, opacity * m_opacity);
+            gDebugChildLevel--;
+        }
+    }
+
+    canvas->restore();
+}
+
+void LayerAndroid::paintMe(float scrollX,
+                           float scrollY,
+                           float scale,
+                           SkCanvas* canvas,
+                           float opacity)
+{
+    if (!prepareContext())
+        return;
+
+    if (!m_haveImage && !m_drawsContent && !m_isRootLayer)
+        return;
+
+    SkAutoCanvasRestore restore(canvas, true);
+
+    int canvasOpacity = opacity * m_opacity * 255;
+    if (canvasOpacity != 255)
+        canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity));
+
+    SkPaint paintMode;
+    if (m_backgroundColorSet) {
+        paintMode.setARGB(m_backgroundColor.alpha(),
+            m_backgroundColor.red(),
+            m_backgroundColor.green(),
+            m_backgroundColor.blue());
+    } else
+        paintMode.setARGB(0, 0, 0, 0);
+
+    paintMode.setXfermodeMode(SkXfermode::kSrc_Mode);
+
+    float x, y;
+    if (m_isFixed) {
+        x = m_fixedPosition.x() + (scrollX / scale);
+        y = m_fixedPosition.y() + (scrollY / scale);
+    } else {
+        x = m_translation.x() + m_position.x();
+        y = m_translation.y() + m_position.y();
+    }
+
+    canvas->translate(x, y);
+
+    if (m_doRotation) {
+        float anchorX = m_anchorPoint.x() * m_size.width();
+        float anchorY = m_anchorPoint.y() * m_size.height();
+        canvas->translate(anchorX, anchorY);
+        canvas->rotate(m_angleTransform);
+        canvas->translate(-anchorX, -anchorY);
+    }
+
+    float sx = m_scale.x();
+    float sy = m_scale.y();
+    if (sx > 1.0f || sy > 1.0f) {
+        float dx = (sx * m_size.width()) - m_size.width();
+        float dy = (sy * m_size.height()) - m_size.height();
+        canvas->translate(-dx / 2.0f, -dy / 2.0f);
+        canvas->scale(sx, sy);
+    }
+
+    m_recordingPicture->draw(canvas);
+
+#ifdef LAYER_DEBUG
+    float w = m_size.width();
+    float h = m_size.height();
+    SkPaint paint;
+    paint.setARGB(128, 255, 0, 0);
+    canvas->drawLine(0, 0, w, h, paint);
+    canvas->drawLine(0, h, w, 0, paint);
+    paint.setARGB(128, 0, 255, 0);
+    canvas->drawLine(0, 0, 0, h, paint);
+    canvas->drawLine(0, h, w, h, paint);
+    canvas->drawLine(w, h, w, 0, paint);
+    canvas->drawLine(w, 0, 0, 0, paint);
+#endif
+}
+
+SkPicture* LayerAndroid::recordContext()
+{
+    if (prepareContext(true))
+        return m_recordingPicture;
+    return 0;
+}
+
+bool LayerAndroid::prepareContext(bool force)
+{
+    if (!m_haveContents)
+        return false;
+
+    if (!m_isRootLayer) {
+        if (force || !m_recordingPicture
+            || (m_recordingPicture
+                && ((m_recordingPicture->width() != (int) m_size.width())
+                   || (m_recordingPicture->height() != (int) m_size.height())))) {
+            m_recordingPicture->safeUnref();
+            m_recordingPicture = new SkPicture();
+        }
+    } else if (m_recordingPicture) {
+        m_recordingPicture->safeUnref();
+        m_recordingPicture = 0;
+    }
+
+    return m_recordingPicture;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h
new file mode 100644
index 0000000..284185d
--- /dev/null
+++ b/WebCore/platform/graphics/android/LayerAndroid.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LayerAndroid_h
+#define LayerAndroid_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Color.h"
+#include "FloatPoint.h"
+#include "FloatPoint3D.h"
+#include "FloatSize.h"
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+#include "RefPtr.h"
+#include "StringHash.h"
+#include "Vector.h"
+#include <wtf/HashSet.h>
+
+class SkCanvas;
+class SkPicture;
+class SkRect;
+
+namespace WebCore {
+
+class AndroidAnimation;
+class AndroidAnimationValue;
+
+class LayerAndroid : public RefCounted<LayerAndroid> {
+
+public:
+    static PassRefPtr<LayerAndroid> create(bool isRootLayer);
+    LayerAndroid(bool isRootLayer);
+    LayerAndroid(LayerAndroid* layer);
+    ~LayerAndroid();
+
+    static int instancesCount();
+
+    void setSize(FloatSize size) { m_size = size; }
+    void setOpacity(float opacity) { m_opacity = opacity; }
+    void setTranslation(FloatPoint translation) { m_translation = translation; }
+    void setRotation(float a) { m_angleTransform = a; m_doRotation = true; }
+    void setScale(FloatPoint3D scale) { m_scale = scale; }
+    void setPosition(FloatPoint position) { m_position = position; }
+    void setAnchorPoint(FloatPoint3D point) { m_anchorPoint = point; }
+    void setHaveContents(bool haveContents) { m_haveContents = haveContents; }
+    void setHaveImage(bool haveImage) { m_haveImage = haveImage; }
+    void setDrawsContent(bool drawsContent);
+    void setMaskLayer(LayerAndroid*);
+    void setMasksToBounds(bool);
+    void setBackgroundColor(const Color& color);
+    void setIsRootLayer(bool isRootLayer) { m_isRootLayer = isRootLayer; }
+
+    void paintOn(float scrollX, float scrollY, float scale, SkCanvas*);
+    GraphicsContext* paintContext();
+    void removeAllChildren() { m_children.clear(); }
+    void addChildren(LayerAndroid* layer) { m_children.append(layer); }
+    bool prepareContext(bool force = false);
+    void startRecording();
+    void stopRecording();
+    SkPicture* recordContext();
+    void setClip(SkCanvas* clip);
+    FloatPoint position() { return m_position; }
+    FloatPoint translation() { return m_translation; }
+    FloatSize size() { return m_size; }
+
+    void setFixedPosition(FloatPoint position);
+    void addAnimation(PassRefPtr<AndroidAnimation> anim);
+    void removeAnimation(const String& name);
+    Vector<RefPtr<AndroidAnimationValue> >* evaluateAnimations() const;
+    bool evaluateAnimations(double time,
+             Vector<RefPtr<AndroidAnimationValue> >* result) const;
+    bool hasAnimations() const;
+
+private:
+
+    void paintChildren(float scrollX, float scrollY,
+                       float scale, SkCanvas* canvas,
+                       float opacity);
+
+    void paintMe(float scrollX, float scrollY,
+                 float scale, SkCanvas* canvas,
+                 float opacity);
+
+    bool m_doRotation;
+    bool m_isRootLayer;
+    bool m_isFixed;
+    bool m_haveContents;
+    bool m_drawsContent;
+    bool m_haveImage;
+    bool m_haveClip;
+    bool m_backgroundColorSet;
+
+    float m_angleTransform;
+    float m_opacity;
+
+    FloatSize m_size;
+    FloatPoint m_position;
+    FloatPoint m_translation;
+    FloatPoint m_fixedPosition;
+    FloatPoint3D m_anchorPoint;
+    FloatPoint3D m_scale;
+
+    SkPicture* m_recordingPicture;
+    Color m_backgroundColor;
+
+    Vector<RefPtr<LayerAndroid> > m_children;
+    typedef HashMap<String, RefPtr<AndroidAnimation> > KeyframesMap;
+    KeyframesMap m_animations;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif  // LayerAndroid_h
diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
index a62c1be..35aa7e1 100644
--- a/WebCore/rendering/RenderLayerBacking.cpp
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -1007,6 +1007,7 @@
     ASSERT(!m_owningLayer->m_usedTransparency);
 }
 
+#if ENABLE(INSPECTOR)
 static InspectorTimelineAgent* inspectorTimelineAgent(RenderObject* renderer)
 {
     Frame* frame = renderer->document()->frame();
@@ -1017,6 +1018,7 @@
         return 0;
     return page->inspectorTimelineAgent();
 }
+#endif
 
 // Up-call from compositing layer drawing callback.
 void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip)
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
index 2f5e267..8ce59cb 100644
--- a/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
@@ -891,6 +891,10 @@
              requiresCompositingForVideo(layer->renderer()) ||
              requiresCompositingForCanvas(layer->renderer()) ||
              layer->renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden ||
+#if PLATFORM(ANDROID)
+             (layer->renderer()->isPositioned() &&
+              layer->renderer()->style()->position() == FixedPosition) ||
+#endif
              clipsCompositingDescendants(layer) ||
              requiresCompositingForAnimation(layer->renderer());
 }
@@ -1064,4 +1068,3 @@
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
-
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
index 8390cbc..f14c2c1 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp
@@ -38,6 +38,7 @@
 #include "FrameLoader.h"
 #include "FrameView.h"
 #include "Geolocation.h"
+#include "GraphicsLayerAndroid.h"
 #include "Page.h"
 #include "Screen.h"
 #include "ScriptController.h"
@@ -49,6 +50,68 @@
 
 namespace android {
 
+#if USE(ACCELERATED_COMPOSITING)
+
+void ChromeClientAndroid::syncTimerFired(Timer<ChromeClientAndroid>* client)
+{
+    m_syncTimer.stop();
+    compositingLayerSync();
+}
+
+void ChromeClientAndroid::compositingLayerSync()
+{
+    if (!m_rootGraphicsLayer) {
+        scheduleCompositingLayerSync();
+        return;
+    }
+
+    if (m_webFrame) {
+        FrameView* frameView = m_webFrame->page()->mainFrame()->view();
+        if (frameView && !frameView->layoutPending() && !frameView->needsLayout()) {
+            frameView->syncCompositingStateRecursive();
+            GraphicsLayerAndroid* androidGraphicsLayer =
+                    static_cast<GraphicsLayerAndroid*>(m_rootGraphicsLayer);
+            if (androidGraphicsLayer)
+                androidGraphicsLayer->sendImmediateRepaint();
+            return;
+        }
+    }
+    if (m_askToDrawAgain) {
+        m_askToDrawAgain = false;
+        scheduleCompositingLayerSync();
+    }
+}
+
+void ChromeClientAndroid::scheduleCompositingLayerSync()
+{
+    if (!m_syncTimer.isActive())
+        m_syncTimer.startOneShot(0.001); // 1ms
+    else
+        m_askToDrawAgain = true;
+}
+
+void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization()
+{
+    // This should not be needed
+}
+
+void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame* frame, WebCore::GraphicsLayer* layer)
+{
+    m_rootGraphicsLayer = layer;
+    if (!layer) {
+        WebViewCore::getWebViewCore(frame->view())->setRootLayer(0);
+        return;
+    }
+    WebCore::GraphicsLayerAndroid* androidGraphicsLayer = static_cast<GraphicsLayerAndroid*>(layer);
+    if (frame && frame->view() && androidGraphicsLayer) {
+        androidGraphicsLayer->setFrame(frame);
+        WebCore::LayerAndroid* androidLayer = new LayerAndroid(androidGraphicsLayer->contentLayer());
+        WebViewCore::getWebViewCore(frame->view())->setRootLayer((int)androidLayer);
+    }
+}
+
+#endif
+
 void ChromeClientAndroid::setWebFrame(android::WebFrame* webframe)
 {
     Release(m_webFrame);
diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
index 7396997..45dd078 100644
--- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
+++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h
@@ -43,7 +43,13 @@
 
     class ChromeClientAndroid : public ChromeClient {
     public:
-        ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0) { }
+        ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0)
+#if USE(ACCELERATED_COMPOSITING)
+                                , m_rootGraphicsLayer(0)
+                                , m_askToDrawAgain(false)
+                                , m_syncTimer(this, &ChromeClientAndroid::syncTimerFired)
+#endif
+                                { }
         virtual void chromeDestroyed();
         
         virtual void setWindowRect(const FloatRect&);
@@ -149,13 +155,27 @@
         // Android-specific
         void setWebFrame(android::WebFrame* webframe);
         void wakeUpMainThreadWithNewQuota(long newQuota);
+
+#if USE(ACCELERATED_COMPOSITING)
+        virtual void attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* g);
+        virtual void setNeedsOneShotDrawingSynchronization();
+        virtual void scheduleCompositingLayerSync();
+        void compositingLayerSync();
+        void syncTimerFired(Timer<ChromeClientAndroid>*);
+#endif
+
     private:
         android::WebFrame* m_webFrame;
+        // The Geolocation permissions manager.
+        OwnPtr<GeolocationPermissions> m_geolocationPermissions;
+#if USE(ACCELERATED_COMPOSITING)
+        WebCore::GraphicsLayer* m_rootGraphicsLayer;
+        bool m_askToDrawAgain;
+        Timer<ChromeClientAndroid> m_syncTimer;
+#endif
         WTF::ThreadCondition m_quotaThreadCondition;
         WTF::Mutex m_quotaThreadLock;
         long m_newQuota;
-        // The Geolocation permissions manager.
-        OwnPtr<GeolocationPermissions> m_geolocationPermissions;
     };
 
 }
diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp
index 10ca246..cd5e2e6 100644
--- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp
+++ b/WebKit/android/WebCoreSupport/PlatformBridge.cpp
@@ -29,6 +29,7 @@
 #include "CookieClient.h"
 #include "JavaSharedClient.h"
 #include "KeyGeneratorClient.h"
+#include "WebViewCore.h"
 #include <wtf/android/AndroidThreading.h>
 #include <wtf/MainThread.h>
 
@@ -36,6 +37,22 @@
 
 namespace WebCore {
 
+#if USE(ACCELERATED_COMPOSITING)
+
+void PlatformBridge::setRootLayer(const WebCore::FrameView* view, int layer)
+{
+    android::WebViewCore* core = android::WebViewCore::getWebViewCore(view);
+    core->setRootLayer(layer);
+}
+
+void PlatformBridge::immediateRepaint(const WebCore::FrameView* view)
+{
+    android::WebViewCore* core = android::WebViewCore::getWebViewCore(view);
+    core->immediateRepaint();
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
 WTF::Vector<String> PlatformBridge::getSupportedKeyStrengthList()
 {
     KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient();
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp
index d546067..7d58b5f 100644
--- a/WebKit/android/jni/WebViewCore.cpp
+++ b/WebKit/android/jni/WebViewCore.cpp
@@ -130,6 +130,11 @@
 #include "TimeCounter.h"
 #endif
 
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerAndroid.h"
+#include "RenderLayerCompositor.h"
+#endif
+
 /*  We pass this flag when recording the actual content, so that we don't spend
     time actually regionizing complex path clips, when all we really want to do
     is record them.
@@ -195,6 +200,8 @@
     jmethodID   m_updateViewport;
     jmethodID   m_sendNotifyProgressFinished;
     jmethodID   m_sendViewInvalidate;
+    jmethodID   m_sendImmediateRepaint;
+    jmethodID   m_setRootLayer;
     jmethodID   m_updateTextfield;
     jmethodID   m_updateTextSelection;
     jmethodID   m_clearTextEntry;
@@ -277,6 +284,8 @@
     m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
     m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
     m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
+    m_javaGlue->m_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V");
+    m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)V");
     m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
     m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
     m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
@@ -859,6 +868,28 @@
     checkException(env);
 }
 
+#if USE(ACCELERATED_COMPOSITING)
+
+void WebViewCore::immediateRepaint()
+{
+    LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
+    JNIEnv* env = JSC::Bindings::getJNIEnv();
+    env->CallVoidMethod(m_javaGlue->object(env).get(),
+                        m_javaGlue->m_sendImmediateRepaint);
+    checkException(env);
+}
+
+void WebViewCore::setRootLayer(int layer)
+{
+    JNIEnv* env = JSC::Bindings::getJNIEnv();
+    env->CallVoidMethod(m_javaGlue->object(env).get(),
+                        m_javaGlue->m_setRootLayer,
+                        layer);
+    checkException(env);
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
 void WebViewCore::contentDraw()
 {
     JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -1214,6 +1245,12 @@
 
 void WebViewCore::updateFrameCache()
 {
+#if USE(ACCELERATED_COMPOSITING)
+    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(
+                                       mainFrame()->page()->chrome()->client());
+    chromeC->scheduleCompositingLayerSync();
+#endif
+
     if (!m_frameCacheOutOfDate) {
         DBG_NAV_LOG("!m_frameCacheOutOfDate");
         return;
@@ -2044,6 +2081,16 @@
 {
     int preventDefault = 0;
 
+#if USE(ACCELERATED_COMPOSITING)
+    RenderView* contentRenderer = m_mainFrame->contentRenderer();
+    GraphicsLayerAndroid* rootLayer = 0;
+    if (contentRenderer)
+      rootLayer = static_cast<GraphicsLayerAndroid*>(
+          contentRenderer->compositor()->rootPlatformLayer());
+    if (rootLayer)
+      rootLayer->pauseDisplay(true);
+#endif
+
 #if ENABLE(TOUCH_EVENTS) // Android
     WebCore::TouchEventType type = WebCore::TouchEventCancel;
     switch (action) {
@@ -2071,6 +2118,10 @@
     preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
 #endif
 
+#if USE(ACCELERATED_COMPOSITING)
+    if (rootLayer)
+      rootLayer->pauseDisplay(false);
+#endif
     return preventDefault;
 }
 
diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h
index 4c8de78..75df0b5 100644
--- a/WebKit/android/jni/WebViewCore.h
+++ b/WebKit/android/jni/WebViewCore.h
@@ -126,6 +126,11 @@
          */
         void contentDraw();
 
+#if USE(ACCELERATED_COMPOSITING)
+        void immediateRepaint();
+        void setRootLayer(int layer);
+#endif
+
         /** Invalidate the view/screen, NOT the content/DOM, but expressed in
          *  content/DOM coordinates (i.e. they need to eventually be scaled,
          *  by webview into view.java coordinates
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index 173d1d2..361b957 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -28,6 +28,7 @@
 #include <config.h>
 
 #include "android_graphics.h"
+#include "AndroidAnimation.h"
 #include "AndroidLog.h"
 #include "AtomicString.h"
 #include "CachedFrame.h"
@@ -39,6 +40,7 @@
 #include "HTMLInputElement.h"
 #include "IntPoint.h"
 #include "IntRect.h"
+#include "LayerAndroid.h"
 #include "Node.h"
 #include "PlatformGraphicsContext.h"
 #include "PlatformString.h"
@@ -1530,6 +1532,86 @@
     view->drawMatches(canvas);
 }
 
+static void nativeDrawLayers(JNIEnv *env, jobject obj,
+    jint layer, jfloat scrollX, jfloat scrollY,
+    jfloat scale, jobject canv)
+{
+    if (!env)
+        return;
+    if (!layer)
+        return;
+    if (!canv)
+        return;
+
+#if USE(ACCELERATED_COMPOSITING)
+    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
+    SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
+    if (canvas)
+        layerImpl->paintOn(scrollX, scrollY, scale, canvas);
+#endif
+}
+
+static void nativeUpdateLayers(JNIEnv *env, jobject obj,
+                               jint layer, jint updates)
+{
+    if (!env)
+        return;
+    if (!layer)
+        return;
+    if (!updates)
+        return;
+
+#if USE(ACCELERATED_COMPOSITING)
+    Vector<RefPtr<AndroidAnimationValue> >* updatesImpl =
+        reinterpret_cast<Vector<RefPtr<AndroidAnimationValue> >* >(updates);
+    if (updatesImpl) {
+        for (unsigned int i = 0; i < updatesImpl->size(); i++)
+            (updatesImpl->at(i))->apply();
+        delete updatesImpl;
+    }
+#endif
+}
+
+static bool nativeLayersHaveAnimations(JNIEnv *env, jobject obj, jint layer)
+{
+    if (!env)
+        return false;
+    if (!layer)
+        return false;
+#if USE(ACCELERATED_COMPOSITING)
+    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
+    return layerImpl->hasAnimations();
+#else
+    return false;
+#endif
+}
+
+static int nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint layer)
+{
+    if (!env)
+        return 0;
+    if (!layer)
+        return 0;
+#if USE(ACCELERATED_COMPOSITING)
+    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
+    return reinterpret_cast<int>(layerImpl->evaluateAnimations());
+#else
+    return 0;
+#endif
+}
+
+static void nativeDestroyLayer(JNIEnv *env, jobject obj, jint layer)
+{
+    if (!env)
+        return;
+    if (!layer)
+        return;
+#if USE(ACCELERATED_COMPOSITING)
+    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
+    delete layerImpl;
+#endif
+}
+
 static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv)
 {
     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
@@ -2071,6 +2153,16 @@
         (void*) nativeDestroy },
     { "nativeDrawCursorRing", "(Landroid/graphics/Canvas;)V",
         (void*) nativeDrawCursorRing },
+    { "nativeDestroyLayer", "(I)V",
+        (void*) nativeDestroyLayer },
+    { "nativeLayersHaveAnimations", "(I)Z",
+        (void*) nativeLayersHaveAnimations },
+    { "nativeEvaluateLayersAnimations", "(I)I",
+        (void*) nativeEvaluateLayersAnimations },
+    { "nativeDrawLayers", "(IFFFLandroid/graphics/Canvas;)V",
+        (void*) nativeDrawLayers },
+    { "nativeUpdateLayers", "(II)V",
+        (void*) nativeUpdateLayers },
     { "nativeDrawMatches", "(Landroid/graphics/Canvas;)V",
         (void*) nativeDrawMatches },
     { "nativeDrawSelectionPointer", "(Landroid/graphics/Canvas;FIIZ)V",