From: Nicolas Roard Date: Mon, 4 Jan 2010 19:33:17 +0000 (+0000) Subject: webkit layers support X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=9acd586e;p=android-x86%2Fexternal-webkit.git webkit layers support --- diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index dbe2f8ebf..18e2b5cdf 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -919,6 +919,10 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #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 33b705095..ada160b59 100644 --- a/WebCore/Android.derived.v8bindings.mk +++ b/WebCore/Android.derived.v8bindings.mk @@ -30,7 +30,8 @@ js_binding_scripts := \ $(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 46d9caaf0..0ab375b65 100644 --- a/WebCore/Android.mk +++ b/WebCore/Android.mk @@ -449,6 +449,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ 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 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ 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 907b0d58d..8fbed4f8b 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 e3f3b989c..9adb3145f 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 @@ -58,6 +60,13 @@ public: 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) + }; } #endif // PlatformBridge_h diff --git a/WebCore/platform/graphics/android/AndroidAnimation.cpp b/WebCore/platform/graphics/android/AndroidAnimation.cpp new file mode 100644 index 000000000..9cdb0c7b7 --- /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 + +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(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(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::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::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 000000000..05d6a765f --- /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 > AnimsVector; +typedef HashMap, AnimsVector* > LayersAnimsMap; + +class AndroidAnimationValue : public RefCounted { + public: + AndroidAnimationValue(LayerAndroid* layer) : m_layer(layer) { } + virtual ~AndroidAnimationValue() { } + virtual void apply() = 0; + protected: + RefPtr m_layer; +}; + +class AndroidOpacityAnimationValue : public AndroidAnimationValue { + public: + static PassRefPtr 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 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 { + 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 result() = 0; + + protected: + RefPtr 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 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 result() { return m_result.release(); } + + virtual void swapDirection(); + virtual bool evaluate(double time); + + private: + RefPtr m_result; + float m_fromValue; + float m_toValue; +}; + +class AndroidTransformAnimation : public AndroidAnimation { + public: + static PassRefPtr 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 result() { return m_result.release(); } + + private: + RefPtr 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 000000000..7637be921 --- /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 +#include + +#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::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(client); + RenderLayer* renderLayer = backing->owningLayer(); + m_contentLayer->setIsRootLayer(renderLayer->isRootLayer()); + RenderView* view = static_cast(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& 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(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(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(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(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(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(valueList.at(0)); + const FloatAnimationValue* endVal = + static_cast(valueList.at(1)); + RefPtr 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 > 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 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(m_children[i]))->contentLayer()); + } + m_needsSyncChildren = false; + } +} + +void GraphicsLayerAndroid::syncMask() +{ + if (m_needsSyncMask) { + if (m_maskLayer) { + GraphicsLayerAndroid* layer = static_cast(m_maskLayer); + LayerAndroid* mask = reinterpret_cast(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(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 000000000..fc88fbf08 --- /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&); + 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 m_frame; + + Vector m_invalidatedRects; + + RefPtr 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 000000000..347021a67 --- /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 + +#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::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 >* LayerAndroid::evaluateAnimations() const +{ + double time = WTF::currentTime(); + Vector >* result = new Vector >(); + 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 >* 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 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 000000000..284185d97 --- /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 + +class SkCanvas; +class SkPicture; +class SkRect; + +namespace WebCore { + +class AndroidAnimation; +class AndroidAnimationValue; + +class LayerAndroid : public RefCounted { + +public: + static PassRefPtr 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 anim); + void removeAnimation(const String& name); + Vector >* evaluateAnimations() const; + bool evaluateAnimations(double time, + Vector >* 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 > m_children; + typedef HashMap > KeyframesMap; + KeyframesMap m_animations; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // LayerAndroid_h diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index a62c1beec..35aa7e1a1 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -1007,6 +1007,7 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* ASSERT(!m_owningLayer->m_usedTransparency); } +#if ENABLE(INSPECTOR) static InspectorTimelineAgent* inspectorTimelineAgent(RenderObject* renderer) { Frame* frame = renderer->document()->frame(); @@ -1017,6 +1018,7 @@ static InspectorTimelineAgent* inspectorTimelineAgent(RenderObject* renderer) 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 2f5e2676d..8ce59cb48 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -891,6 +891,10 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c 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 @@ bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index 8390cbc1d..f14c2c138 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* 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(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(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 7396997b5..45dd078ae 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h @@ -43,7 +43,13 @@ namespace android { 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 @@ namespace android { // 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*); +#endif + private: android::WebFrame* m_webFrame; + // The Geolocation permissions manager. + OwnPtr m_geolocationPermissions; +#if USE(ACCELERATED_COMPOSITING) + WebCore::GraphicsLayer* m_rootGraphicsLayer; + bool m_askToDrawAgain; + Timer m_syncTimer; +#endif WTF::ThreadCondition m_quotaThreadCondition; WTF::Mutex m_quotaThreadLock; long m_newQuota; - // The Geolocation permissions manager. - OwnPtr m_geolocationPermissions; }; } diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp index e4fe4ce96..e93d3da58 100644 --- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp +++ b/WebKit/android/WebCoreSupport/PlatformBridge.cpp @@ -28,11 +28,28 @@ #include "JavaSharedClient.h" #include "KeyGeneratorClient.h" +#include "WebViewCore.h" using namespace android; 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 PlatformBridge::getSupportedKeyStrengthList() { KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient(); @@ -51,4 +68,4 @@ String PlatformBridge::getSignedPublicKeyAndChallengeString(unsigned index, cons return client->getSignedPublicKeyAndChallengeString(index, challenge, url); } -} \ No newline at end of file +} diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 1c1384a6f..5ebee310f 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -130,6 +130,11 @@ FILE* gRenderTreeFile = 0; #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 @@ struct WebViewCore::JavaGlue { 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 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m 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"); @@ -879,6 +888,28 @@ void WebViewCore::scrollBy(int dx, int dy, bool animate) 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(); @@ -1267,6 +1298,12 @@ void WebViewCore::updateCacheOnNodeChange() void WebViewCore::updateFrameCache() { +#if USE(ACCELERATED_COMPOSITING) + ChromeClientAndroid* chromeC = static_cast( + mainFrame()->page()->chrome()->client()); + chromeC->scheduleCompositingLayerSync(); +#endif + if (!m_frameCacheOutOfDate) { DBG_NAV_LOG("!m_frameCacheOutOfDate"); return; @@ -2098,6 +2135,16 @@ int WebViewCore::handleTouchEvent(int action, int x, int y) { int preventDefault = 0; +#if USE(ACCELERATED_COMPOSITING) + RenderView* contentRenderer = m_mainFrame->contentRenderer(); + GraphicsLayerAndroid* rootLayer = 0; + if (contentRenderer) + rootLayer = static_cast( + contentRenderer->compositor()->rootPlatformLayer()); + if (rootLayer) + rootLayer->pauseDisplay(true); +#endif + #if ENABLE(TOUCH_EVENTS) // Android WebCore::TouchEventType type = WebCore::TouchEventCancel; switch (action) { @@ -2125,6 +2172,10 @@ int WebViewCore::handleTouchEvent(int action, int x, int y) 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 4c8de7821..75df0b5a4 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -126,6 +126,11 @@ namespace android { */ 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 d1d5e8628..c8d89deb5 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -28,6 +28,7 @@ #include #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" @@ -1602,6 +1604,86 @@ static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv) 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(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 >* updatesImpl = + reinterpret_cast >* >(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(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(layer); + return reinterpret_cast(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(layer); + delete layerImpl; +#endif +} + static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); @@ -2143,6 +2225,16 @@ static JNINativeMethod gJavaWebViewMethods[] = { (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",