diff options
author | Nicolas Roard <nicolas@android.com> | 2010-01-04 19:33:17 +0000 |
---|---|---|
committer | Nicolas Roard <nicolas@android.com> | 2010-01-04 19:33:17 +0000 |
commit | 9acd586e4a0aa54e4f630665aa0d3c8c95b78e72 (patch) | |
tree | 97f62cc64e391bde4a9436791e844dda7ed3f76a /WebCore | |
parent | 5bd553b63661fa0f711bb9c02566d5df80a9432f (diff) | |
download | external_webkit-9acd586e4a0aa54e4f630665aa0d3c8c95b78e72.zip external_webkit-9acd586e4a0aa54e4f630665aa0d3c8c95b78e72.tar.gz external_webkit-9acd586e4a0aa54e4f630665aa0d3c8c95b78e72.tar.bz2 |
webkit layers support
Diffstat (limited to 'WebCore')
-rw-r--r-- | WebCore/Android.derived.v8bindings.mk | 3 | ||||
-rw-r--r-- | WebCore/Android.mk | 3 | ||||
-rw-r--r-- | WebCore/config.h | 1 | ||||
-rw-r--r-- | WebCore/platform/android/PlatformBridge.h | 9 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/AndroidAnimation.cpp | 313 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/AndroidAnimation.h | 205 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp | 852 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/GraphicsLayerAndroid.h | 156 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/LayerAndroid.cpp | 353 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/LayerAndroid.h | 129 | ||||
-rw-r--r-- | WebCore/rendering/RenderLayerBacking.cpp | 2 | ||||
-rw-r--r-- | WebCore/rendering/RenderLayerCompositor.cpp | 5 |
12 files changed, 2029 insertions, 2 deletions
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 @@ 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 46d9caa..0ab375b 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 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 e3f3b98..9adb314 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 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 @@ 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 2f5e267..8ce59cb 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) - |