blob: 69905039c12061a185025bde1a5df6cc6143618a [file] [log] [blame]
/*
* 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 "FloatRect.h"
#include "GraphicsContext.h"
#include "Image.h"
#include "ImagesManager.h"
#include "Layer.h"
#include "Length.h"
#include "MediaLayer.h"
#include "PlatformBridge.h"
#include "PlatformGraphicsContext.h"
#include "RenderLayerBacking.h"
#include "RenderView.h"
#include "RotateTransformOperation.h"
#include "ScaleTransformOperation.h"
#include "ScrollableLayerAndroid.h"
#include "SkCanvas.h"
#include "SkRegion.h"
#include "TransformationMatrix.h"
#include "TranslateTransformOperation.h"
#include <cutils/log.h>
#include <wtf/CurrentTime.h>
#include <wtf/text/CString.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 "";
}
PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
{
return new GraphicsLayerAndroid(client);
}
SkLength convertLength(Length len)
{
SkLength length;
length.type = SkLength::Undefined;
length.value = 0;
if (len.type() == WebCore::Percent) {
length.type = SkLength::Percent;
length.value = len.percent();
}
if (len.type() == WebCore::Fixed) {
length.type = SkLength::Fixed;
length.value = len.value();
}
return length;
}
static RenderLayer* renderLayerFromClient(GraphicsLayerClient* client)
{
return client ? client->owningLayer() : 0;
}
GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) :
GraphicsLayer(client),
m_needsSyncChildren(false),
m_needsSyncMask(false),
m_needsRepaint(false),
m_needsNotifyClient(false),
m_haveContents(false),
m_newImage(false),
m_image(0),
m_foregroundLayer(0),
m_foregroundClipLayer(0)
{
RenderLayer* renderLayer = renderLayerFromClient(m_client);
m_contentLayer = new LayerAndroid(renderLayer);
m_dirtyRegion.setEmpty();
gDebugGraphicsLayerAndroidInstances++;
}
GraphicsLayerAndroid::~GraphicsLayerAndroid()
{
if (m_image)
m_image->deref();
m_contentLayer->unref();
SkSafeUnref(m_foregroundLayer);
SkSafeUnref(m_foregroundClipLayer);
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 String& name = childLayer->name();
LOG("(%x) addChild: %x (%s)", this, childLayer, name.latin1().data());
#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);
if (ret) {
m_needsSyncChildren = true;
askForSync();
}
return ret;
}
void GraphicsLayerAndroid::removeFromParent()
{
LOG("(%x) removeFromParent()", this);
GraphicsLayerAndroid* parent = static_cast<GraphicsLayerAndroid*>(m_parent);
GraphicsLayer::removeFromParent();
// Update the parent's children.
if (parent) {
parent->m_needsSyncChildren = true;
askForSync();
}
}
void GraphicsLayerAndroid::updateFixedPosition()
{
RenderLayer* renderLayer = renderLayerFromClient(m_client);
if (!renderLayer)
return;
RenderView* view = static_cast<RenderView*>(renderLayer->renderer());
if (!view)
return;
// We will need the Iframe flag in the LayerAndroid tree for fixed position
if (view->isRenderIFrame())
m_contentLayer->setIsIframe(true);
// If we are a fixed position layer, just set it
if (view->isPositioned() && view->style()->position() == FixedPosition) {
// We need to get the passed CSS properties for the element
SkLength left, top, right, bottom;
left = convertLength(view->style()->left());
top = convertLength(view->style()->top());
right = convertLength(view->style()->right());
bottom = convertLength(view->style()->bottom());
// We also need to get the margin...
SkLength marginLeft, marginTop, marginRight, marginBottom;
marginLeft = convertLength(view->style()->marginLeft());
marginTop = convertLength(view->style()->marginTop());
marginRight = convertLength(view->style()->marginRight());
marginBottom = convertLength(view->style()->marginBottom());
// In order to compute the fixed element's position, we need the width
// and height of the element when bottom or right is defined.
// And here we should use the non-overflowed value, that means, the
// overflowed content (e.g. outset shadow) will not be counted into the
// width and height.
int w = view->width();
int h = view->height();
int paintingOffsetX = - offsetFromRenderer().width();
int paintingOffsetY = - offsetFromRenderer().height();
SkRect viewRect;
viewRect.set(paintingOffsetX, paintingOffsetY, paintingOffsetX + w, paintingOffsetY + h);
IntPoint renderLayerPos(renderLayer->x(), renderLayer->y());
m_contentLayer->setFixedPosition(left, top, right, bottom,
marginLeft, marginTop,
marginRight, marginBottom,
renderLayerPos,
viewRect);
}
}
void GraphicsLayerAndroid::setPosition(const FloatPoint& point)
{
if (point == m_position)
return;
GraphicsLayer::setPosition(point);
#ifdef LAYER_DEBUG_2
LOG("(%x) setPosition(%.2f,%.2f) pos(%.2f, %.2f) anchor(%.2f,%.2f) size(%.2f, %.2f)",
this, point.x(), point.y(), m_position.x(), m_position.y(),
m_anchorPoint.x(), m_anchorPoint.y(), m_size.width(), m_size.height());
#endif
m_contentLayer->setPosition(point.x(), point.y());
askForSync();
}
void GraphicsLayerAndroid::setPreserves3D(bool preserves3D)
{
if (preserves3D == m_preserves3D)
return;
GraphicsLayer::setPreserves3D(preserves3D);
m_contentLayer->setPreserves3D(preserves3D);
askForSync();
}
void GraphicsLayerAndroid::setAnchorPoint(const FloatPoint3D& point)
{
if (point == m_anchorPoint)
return;
GraphicsLayer::setAnchorPoint(point);
m_contentLayer->setAnchorPoint(point.x(), point.y());
m_contentLayer->setAnchorPointZ(point.z());
askForSync();
}
void GraphicsLayerAndroid::setSize(const FloatSize& size)
{
if (size == m_size)
return;
MLOG("(%x) setSize (%.2f,%.2f)", this, size.width(), size.height());
GraphicsLayer::setSize(size);
// If it is a media layer the size may have changed as a result of the media
// element (e.g. plugin) gaining focus. Therefore, we must sync the size of
// the focus' outline so that our UI thread can draw accordingly.
RenderLayer* layer = renderLayerFromClient(m_client);
if (layer && m_contentLayer->isMedia()) {
RenderBox* box = layer->renderBox();
int outline = box->view()->maximalOutlineSize();
static_cast<MediaLayer*>(m_contentLayer)->setOutlineSize(outline);
LOG("Media Outline: %d %p %p %p", outline, m_client, layer, box);
LOG("Media Size: %g,%g", size.width(), size.height());
}
m_contentLayer->setSize(size.width(), size.height());
setNeedsDisplay();
askForSync();
}
void GraphicsLayerAndroid::setBackfaceVisibility(bool b)
{
if (b == m_backfaceVisibility)
return;
GraphicsLayer::setBackfaceVisibility(b);
m_contentLayer->setBackfaceVisibility(b);
askForSync();
}
void GraphicsLayerAndroid::setTransform(const TransformationMatrix& t)
{
if (t == m_transform)
return;
GraphicsLayer::setTransform(t);
m_contentLayer->setTransform(t);
askForSync();
}
void GraphicsLayerAndroid::setChildrenTransform(const TransformationMatrix& t)
{
if (t == m_childrenTransform)
return;
LOG("(%x) setChildrenTransform", this);
GraphicsLayer::setChildrenTransform(t);
m_contentLayer->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)
{
if (masksToBounds == m_masksToBounds)
return;
GraphicsLayer::setMasksToBounds(masksToBounds);
m_needsSyncMask = true;
askForSync();
}
void GraphicsLayerAndroid::setDrawsContent(bool drawsContent)
{
if (drawsContent == m_drawsContent)
return;
GraphicsLayer::setDrawsContent(drawsContent);
m_contentLayer->setVisible(drawsContent);
if (m_drawsContent) {
m_haveContents = true;
setNeedsDisplay();
}
askForSync();
}
void GraphicsLayerAndroid::setBackgroundColor(const Color& color)
{
if (color == m_backgroundColor && m_backgroundColorSet)
return;
LOG("(%x) setBackgroundColor", this);
GraphicsLayer::setBackgroundColor(color);
SkColor c = SkColorSetARGB(color.alpha(), color.red(), color.green(), color.blue());
m_contentLayer->setBackgroundColor(c);
m_haveContents = true;
askForSync();
}
void GraphicsLayerAndroid::clearBackgroundColor()
{
if (!m_backgroundColorSet)
return;
LOG("(%x) clearBackgroundColor", this);
GraphicsLayer::clearBackgroundColor();
askForSync();
}
void GraphicsLayerAndroid::setContentsOpaque(bool opaque)
{
if (opaque == m_contentsOpaque)
return;
LOG("(%x) setContentsOpaque (%d)", this, opaque);
GraphicsLayer::setContentsOpaque(opaque);
m_haveContents = 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);
m_contentLayer->setOpacity(clampedOpacity);
askForSync();
}
void GraphicsLayerAndroid::setNeedsDisplay()
{
LOG("(%x) setNeedsDisplay()", this);
FloatRect rect(0, 0, m_size.width(), m_size.height());
setNeedsDisplayInRect(rect);
}
// Helper to set and clear the painting phase as well as auto restore the
// original phase.
class PaintingPhase {
public:
PaintingPhase(GraphicsLayer* layer)
: m_layer(layer)
, m_originalPhase(layer->paintingPhase()) {}
~PaintingPhase()
{
m_layer->setPaintingPhase(m_originalPhase);
}
void set(GraphicsLayerPaintingPhase phase)
{
m_layer->setPaintingPhase(phase);
}
void clear(GraphicsLayerPaintingPhase phase)
{
m_layer->setPaintingPhase(
(GraphicsLayerPaintingPhase) (m_originalPhase & ~phase));
}
private:
GraphicsLayer* m_layer;
GraphicsLayerPaintingPhase m_originalPhase;
};
void GraphicsLayerAndroid::updateScrollingLayers()
{
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
RenderLayer* layer = renderLayerFromClient(m_client);
if (!layer || !m_haveContents)
return;
bool hasOverflowScroll = m_foregroundLayer || m_contentLayer->contentIsScrollable();
bool layerNeedsOverflow = layer->hasOverflowScroll();
bool iframeNeedsOverflow = layer->isRootLayer() &&
layer->renderer()->frame()->ownerRenderer() &&
layer->renderer()->frame()->view()->hasOverflowScroll();
if (hasOverflowScroll && (layerNeedsOverflow || iframeNeedsOverflow)) {
// Already has overflow layers.
return;
}
if (!hasOverflowScroll && !layerNeedsOverflow && !iframeNeedsOverflow) {
// Does not need overflow layers.
return;
}
if (layerNeedsOverflow || iframeNeedsOverflow) {
ASSERT(!hasOverflowScroll);
if (layerNeedsOverflow) {
ASSERT(!m_foregroundLayer && !m_foregroundClipLayer);
m_foregroundLayer = new ScrollableLayerAndroid(layer);
m_foregroundClipLayer = new LayerAndroid(layer);
m_foregroundClipLayer->setMasksToBounds(true);
m_foregroundClipLayer->addChild(m_foregroundLayer);
m_contentLayer->addChild(m_foregroundClipLayer);
m_contentLayer->setHasOverflowChildren(true);
} else {
ASSERT(iframeNeedsOverflow && !m_contentLayer->contentIsScrollable());
// No need to copy the children as they will be removed and synced.
m_contentLayer->removeChildren();
// Replace the content layer with a scrollable layer.
LayerAndroid* layer = new ScrollableLayerAndroid(*m_contentLayer);
m_contentLayer->unref();
m_contentLayer = layer;
if (m_parent) {
// The content layer has changed so the parent needs to sync
// children.
static_cast<GraphicsLayerAndroid*>(m_parent)->m_needsSyncChildren = true;
}
}
// Need to rebuild our children based on the new structure.
m_needsSyncChildren = true;
} else {
ASSERT(hasOverflowScroll && !layerNeedsOverflow && !iframeNeedsOverflow);
ASSERT(m_contentLayer);
// Remove the foreground layers.
if (m_foregroundLayer) {
m_foregroundLayer->unref();
m_foregroundLayer = 0;
m_foregroundClipLayer->unref();
m_foregroundClipLayer = 0;
}
// No need to copy over children.
m_contentLayer->removeChildren();
LayerAndroid* layer = new LayerAndroid(*m_contentLayer);
m_contentLayer->unref();
m_contentLayer = layer;
if (m_parent) {
// The content layer has changed so the parent needs to sync
// children.
static_cast<GraphicsLayerAndroid*>(m_parent)->m_needsSyncChildren = true;
}
// Children are all re-parented.
m_needsSyncChildren = true;
}
#endif
}
bool GraphicsLayerAndroid::repaint()
{
LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ",
this, gPaused, m_needsRepaint, m_haveContents);
if (!gPaused && m_haveContents && m_needsRepaint && !m_image) {
// with SkPicture, we request the entire layer's content.
IntRect layerBounds(0, 0, m_size.width(), m_size.height());
RenderLayer* layer = renderLayerFromClient(m_client);
if (!layer)
return false;
if (m_foregroundLayer) {
PaintingPhase phase(this);
// Paint the background into a separate context.
phase.set(GraphicsLayerPaintBackground);
if (!paintContext(m_contentLayer->recordContext(), layerBounds))
return false;
m_contentLayer->checkTextPresence();
// Construct the foreground layer and draw.
RenderBox* box = layer->renderBox();
int outline = box->view()->maximalOutlineSize();
IntRect contentsRect(0, 0,
box->borderLeft() + box->borderRight() + layer->scrollWidth(),
box->borderTop() + box->borderBottom() + layer->scrollHeight());
contentsRect.inflate(outline);
// Update the foreground layer size.
m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height());
// Paint everything else into the main recording canvas.
phase.clear(GraphicsLayerPaintBackground);
// Paint at 0,0.
IntSize scroll = layer->scrolledContentOffset();
layer->scrollToOffset(0, 0);
// At this point, it doesn't matter if painting failed.
(void) paintContext(m_foregroundLayer->recordContext(), contentsRect);
m_foregroundLayer->checkTextPresence();
layer->scrollToOffset(scroll.width(), scroll.height());
// Construct the clip layer for masking the contents.
IntRect clip = layer->renderer()->absoluteBoundingBoxRect();
// absoluteBoundingBoxRect does not include the outline so we need
// to offset the position.
int x = box->borderLeft() + outline;
int y = box->borderTop() + outline;
int width = clip.width() - box->borderLeft() - box->borderRight();
int height = clip.height() - box->borderTop() - box->borderBottom();
m_foregroundClipLayer->setPosition(x, y);
m_foregroundClipLayer->setSize(width, height);
// Need to offset the foreground layer by the clip layer in order
// for the contents to be in the correct position.
m_foregroundLayer->setPosition(-x, -y);
// Set the scrollable bounds of the layer.
m_foregroundLayer->setScrollLimits(-x, -y, m_size.width(), m_size.height());
// Invalidate the entire layer for now, as webkit will only send the
// setNeedsDisplayInRect() for the visible (clipped) scrollable area,
// offsetting the invals by the scroll position would not be enough.
// TODO: have webkit send us invals even for non visible area
SkRegion region;
region.setRect(0, 0, contentsRect.width(), contentsRect.height());
m_foregroundLayer->markAsDirty(region);
m_foregroundLayer->needsRepaint();
} else {
// If there is no contents clip, we can draw everything into one
// picture.
if (!paintContext(m_contentLayer->recordContext(), layerBounds))
return false;
m_contentLayer->checkTextPresence();
// Check for a scrollable iframe and report the scrolling
// limits based on the view size.
if (m_contentLayer->contentIsScrollable()) {
FrameView* view = layer->renderer()->frame()->view();
static_cast<ScrollableLayerAndroid*>(m_contentLayer)->setScrollLimits(
m_position.x(), m_position.y(), view->layoutWidth(), view->layoutHeight());
}
}
LOG("(%x) repaint() on (%.2f,%.2f) contentlayer(%.2f,%.2f,%.2f,%.2f)paintGraphicsLayer called!",
this, m_size.width(), m_size.height(),
m_contentLayer->getPosition().fX,
m_contentLayer->getPosition().fY,
m_contentLayer->getSize().width(),
m_contentLayer->getSize().height());
m_contentLayer->markAsDirty(m_dirtyRegion);
m_dirtyRegion.setEmpty();
m_contentLayer->needsRepaint();
m_needsRepaint = false;
return true;
}
if (m_needsRepaint && m_image && m_newImage) {
// We need to tell the GL thread that we will need to repaint the
// texture. Only do so if we effectively have a new image!
m_contentLayer->markAsDirty(m_dirtyRegion);
m_dirtyRegion.setEmpty();
m_contentLayer->needsRepaint();
m_newImage = false;
m_needsRepaint = false;
return true;
}
return false;
}
bool GraphicsLayerAndroid::paintContext(SkPicture* context,
const IntRect& rect)
{
SkAutoPictureRecord arp(context, rect.width(), rect.height());
SkCanvas* canvas = arp.getRecordingCanvas();
if (!canvas)
return false;
PlatformGraphicsContext platformContext(canvas);
GraphicsContext graphicsContext(&platformContext);
paintGraphicsLayerContents(graphicsContext, rect);
return true;
}
void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect)
{
// rect is in the render object coordinates
if (!m_image && !drawsContent()) {
LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...",
this, rect.x(), rect.y(), rect.width(), rect.height());
return;
}
SkRegion region;
region.setRect(rect.x(), rect.y(),
rect.x() + rect.width(),
rect.y() + rect.height());
m_dirtyRegion.op(region, SkRegion::kUnion_Op);
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);
}
if (createdAnimations)
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);
switch (valueList.property()) {
case AnimatedPropertyInvalid: break;
case AnimatedPropertyWebkitTransform: break;
case AnimatedPropertyBackgroundColor: break;
case AnimatedPropertyOpacity: {
MLOG("ANIMATEDPROPERTYOPACITY");
KeyframeValueList* operationsList = new KeyframeValueList(AnimatedPropertyOpacity);
for (unsigned int i = 0; i < valueList.size(); i++) {
FloatAnimationValue* originalValue = (FloatAnimationValue*)valueList.at(i);
PassRefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction()));
FloatAnimationValue* value = new FloatAnimationValue(originalValue->keyTime(),
originalValue->value(),
timingFunction);
operationsList->insert(value);
}
RefPtr<AndroidOpacityAnimation> anim = AndroidOpacityAnimation::create(animation,
operationsList,
beginTime);
if (keyframesName.isEmpty())
anim->setName(propertyIdToString(valueList.property()));
else
anim->setName(keyframesName);
m_contentLayer->addAnimation(anim.release());
needsNotifyClient();
return true;
} break;
}
return false;
}
void GraphicsLayerAndroid::needsNotifyClient()
{
m_needsNotifyClient = true;
askForSync();
}
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);
KeyframeValueList* operationsList = new KeyframeValueList(AnimatedPropertyWebkitTransform);
for (unsigned int i = 0; i < valueList.size(); i++) {
TransformAnimationValue* originalValue = (TransformAnimationValue*)valueList.at(i);
PassRefPtr<TimingFunction> timingFunction(const_cast<TimingFunction*>(originalValue->timingFunction()));
TransformAnimationValue* value = new TransformAnimationValue(originalValue->keyTime(),
originalValue->value(),
timingFunction);
operationsList->insert(value);
}
RefPtr<AndroidTransformAnimation> anim = AndroidTransformAnimation::create(animation,
operationsList,
beginTime);
if (keyframesName.isEmpty())
anim->setName(propertyIdToString(valueList.property()));
else
anim->setName(keyframesName);
m_contentLayer->addAnimation(anim.release());
needsNotifyClient();
return true;
}
void GraphicsLayerAndroid::removeAnimationsForProperty(AnimatedPropertyID anID)
{
TLOG("NRO removeAnimationsForProperty(%d)", anID);
m_contentLayer->removeAnimationsForProperty(anID);
askForSync();
}
void GraphicsLayerAndroid::removeAnimationsForKeyframes(const String& keyframesName)
{
TLOG("NRO removeAnimationsForKeyframes(%s)", keyframesName.latin1().data());
m_contentLayer->removeAnimationsForKeyframes(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 && image != m_image) {
image->ref();
if (m_image)
m_image->deref();
m_image = image;
SkBitmapRef* bitmap = image->nativeImageForCurrentFrame();
m_contentLayer->setContentsImage(bitmap);
m_haveContents = true;
m_newImage = true;
}
if (!image && m_image) {
m_contentLayer->setContentsImage(0);
m_image->deref();
m_image = 0;
}
setNeedsDisplay();
askForSync();
}
void GraphicsLayerAndroid::setContentsToMedia(PlatformLayer* mediaLayer)
{
// Only fullscreen video on Android, so media doesn't get it's own layer.
// We might still have other layers though.
if (m_contentLayer != mediaLayer && mediaLayer) {
// TODO add a copy method to LayerAndroid to sync everything
// copy data from the original content layer to the new one
mediaLayer->setPosition(m_contentLayer->getPosition().fX,
m_contentLayer->getPosition().fY);
mediaLayer->setSize(m_contentLayer->getWidth(), m_contentLayer->getHeight());
mediaLayer->setDrawTransform(*m_contentLayer->drawTransform());
mediaLayer->ref();
m_contentLayer->unref();
m_contentLayer = mediaLayer;
// If the parent exists then notify it to re-sync it's children
if (m_parent) {
GraphicsLayerAndroid* parent = static_cast<GraphicsLayerAndroid*>(m_parent);
parent->m_needsSyncChildren = true;
}
m_needsSyncChildren = true;
setNeedsDisplay();
askForSync();
}
}
PlatformLayer* GraphicsLayerAndroid::platformLayer() const
{
LOG("platformLayer");
return m_contentLayer;
}
#ifndef NDEBUG
void GraphicsLayerAndroid::setDebugBackgroundColor(const Color& color)
{
}
void GraphicsLayerAndroid::setDebugBorder(const Color& color, float borderWidth)
{
}
#endif
void GraphicsLayerAndroid::setZPosition(float position)
{
if (position == m_zPosition)
return;
LOG("(%x) setZPosition: %.2f", this, position);
GraphicsLayer::setZPosition(position);
askForSync();
}
void GraphicsLayerAndroid::askForSync()
{
if (!m_client)
return;
if (m_client)
m_client->notifySyncRequired(this);
}
void GraphicsLayerAndroid::syncChildren()
{
if (m_needsSyncChildren) {
m_contentLayer->removeChildren();
LayerAndroid* layer = m_contentLayer;
if (m_foregroundClipLayer) {
m_contentLayer->addChild(m_foregroundClipLayer);
// Use the scrollable content layer as the parent of the children so
// that they move with the content.
layer = m_foregroundLayer;
layer->removeChildren();
}
for (unsigned int i = 0; i < m_children.size(); i++)
layer->addChild(m_children[i]->platformLayer());
m_needsSyncChildren = false;
}
}
void GraphicsLayerAndroid::syncMask()
{
if (m_needsSyncMask) {
if (m_maskLayer) {
LayerAndroid* mask = m_maskLayer->platformLayer();
m_contentLayer->setMaskLayer(mask);
} else
m_contentLayer->setMaskLayer(0);
m_contentLayer->setMasksToBounds(m_masksToBounds);
m_needsSyncMask = false;
}
}
void GraphicsLayerAndroid::syncCompositingState()
{
for (unsigned int i = 0; i < m_children.size(); i++)
m_children[i]->syncCompositingState();
updateScrollingLayers();
updateFixedPosition();
syncChildren();
syncMask();
if (!gPaused || WTF::currentTime() >= gPausedDelay)
repaint();
}
void GraphicsLayerAndroid::notifyClientAnimationStarted()
{
for (unsigned int i = 0; i < m_children.size(); i++)
static_cast<GraphicsLayerAndroid*>(m_children[i])->notifyClientAnimationStarted();
if (m_needsNotifyClient) {
if (client())
client()->notifyAnimationStarted(this, WTF::currentTime());
m_needsNotifyClient = false;
}
}
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)