blob: c4a20a3443e54879fe2fbf191eb09dbaec17a26f [file] [log] [blame]
/*
Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "config.h"
#if USE(COORDINATED_GRAPHICS)
#include "CoordinatedGraphicsLayer.h"
#include "BackingStore.h"
#include "CoordinatedTile.h"
#include "FloatQuad.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "GraphicsLayer.h"
#include "LayerTreeCoordinatorProxyMessages.h"
#include "Page.h"
#include "TextureMapperPlatformLayer.h"
#include "WebPage.h"
#include <wtf/CurrentTime.h>
#include <wtf/HashMap.h>
#include <wtf/text/CString.h>
using namespace WebKit;
namespace WebCore {
static HashMap<WebLayerID, CoordinatedGraphicsLayer*>& layerByIDMap()
{
static HashMap<WebLayerID, CoordinatedGraphicsLayer*> globalMap;
return globalMap;
}
static WebLayerID toWebLayerID(GraphicsLayer* layer)
{
return layer ? toCoordinatedGraphicsLayer(layer)->id() : 0;
}
void CoordinatedGraphicsLayer::didChangeLayerState()
{
m_shouldSyncLayerState = true;
if (client())
client()->notifyFlushRequired(this);
}
void CoordinatedGraphicsLayer::didChangeAnimations()
{
m_shouldSyncAnimations = true;
if (client())
client()->notifyFlushRequired(this);
}
void CoordinatedGraphicsLayer::didChangeChildren()
{
m_shouldSyncChildren = true;
if (client())
client()->notifyFlushRequired(this);
}
#if ENABLE(CSS_FILTERS)
void CoordinatedGraphicsLayer::didChangeFilters()
{
m_shouldSyncFilters = true;
if (client())
client()->notifyFlushRequired(this);
}
#endif
void CoordinatedGraphicsLayer::didChangeImageBacking()
{
m_shouldSyncImageBacking = true;
if (client())
client()->notifyFlushRequired(this);
}
void CoordinatedGraphicsLayer::setShouldUpdateVisibleRect()
{
m_shouldUpdateVisibleRect = true;
for (size_t i = 0; i < children().size(); ++i)
toCoordinatedGraphicsLayer(children()[i])->setShouldUpdateVisibleRect();
if (replicaLayer())
toCoordinatedGraphicsLayer(replicaLayer())->setShouldUpdateVisibleRect();
}
void CoordinatedGraphicsLayer::didChangeGeometry()
{
didChangeLayerState();
setShouldUpdateVisibleRect();
}
CoordinatedGraphicsLayer::CoordinatedGraphicsLayer(GraphicsLayerClient* client)
: GraphicsLayer(client)
, m_maskTarget(0)
, m_inUpdateMode(false)
, m_shouldUpdateVisibleRect(true)
, m_shouldSyncLayerState(true)
, m_shouldSyncChildren(true)
, m_shouldSyncFilters(true)
, m_shouldSyncImageBacking(true)
, m_shouldSyncAnimations(true)
, m_fixedToViewport(false)
, m_canvasNeedsDisplay(false)
, m_coordinator(0)
, m_contentsScale(1)
, m_compositedNativeImagePtr(0)
, m_canvasPlatformLayer(0)
, m_animationStartedTimer(this, &CoordinatedGraphicsLayer::animationStartedTimerFired)
{
static WebLayerID nextLayerID = 1;
m_id = nextLayerID++;
layerByIDMap().add(id(), this);
}
CoordinatedGraphicsLayer::~CoordinatedGraphicsLayer()
{
layerByIDMap().remove(id());
if (m_coordinator) {
purgeBackingStores();
m_coordinator->detachLayer(this);
}
willBeDestroyed();
}
bool CoordinatedGraphicsLayer::setChildren(const Vector<GraphicsLayer*>& children)
{
bool ok = GraphicsLayer::setChildren(children);
if (!ok)
return false;
for (unsigned i = 0; i < children.size(); ++i) {
CoordinatedGraphicsLayer* child = toCoordinatedGraphicsLayer(children[i]);
child->didChangeLayerState();
}
didChangeChildren();
return true;
}
void CoordinatedGraphicsLayer::addChild(GraphicsLayer* layer)
{
GraphicsLayer::addChild(layer);
toCoordinatedGraphicsLayer(layer)->didChangeLayerState();
didChangeChildren();
}
void CoordinatedGraphicsLayer::addChildAtIndex(GraphicsLayer* layer, int index)
{
GraphicsLayer::addChildAtIndex(layer, index);
toCoordinatedGraphicsLayer(layer)->didChangeLayerState();
didChangeChildren();
}
void CoordinatedGraphicsLayer::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildAbove(layer, sibling);
toCoordinatedGraphicsLayer(layer)->didChangeLayerState();
didChangeChildren();
}
void CoordinatedGraphicsLayer::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildBelow(layer, sibling);
toCoordinatedGraphicsLayer(layer)->didChangeLayerState();
didChangeChildren();
}
bool CoordinatedGraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
{
bool ok = GraphicsLayer::replaceChild(oldChild, newChild);
if (!ok)
return false;
didChangeChildren();
toCoordinatedGraphicsLayer(oldChild)->didChangeLayerState();
toCoordinatedGraphicsLayer(newChild)->didChangeLayerState();
return true;
}
void CoordinatedGraphicsLayer::removeFromParent()
{
if (CoordinatedGraphicsLayer* parentLayer = toCoordinatedGraphicsLayer(parent()))
parentLayer->didChangeChildren();
GraphicsLayer::removeFromParent();
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setPosition(const FloatPoint& p)
{
if (position() == p)
return;
GraphicsLayer::setPosition(p);
didChangeGeometry();
}
void CoordinatedGraphicsLayer::setAnchorPoint(const FloatPoint3D& p)
{
if (anchorPoint() == p)
return;
GraphicsLayer::setAnchorPoint(p);
didChangeGeometry();
}
void CoordinatedGraphicsLayer::setSize(const FloatSize& size)
{
if (this->size() == size)
return;
GraphicsLayer::setSize(size);
setNeedsDisplay();
if (maskLayer())
maskLayer()->setSize(size);
didChangeGeometry();
}
void CoordinatedGraphicsLayer::setTransform(const TransformationMatrix& t)
{
if (transform() == t)
return;
GraphicsLayer::setTransform(t);
didChangeGeometry();
}
void CoordinatedGraphicsLayer::setChildrenTransform(const TransformationMatrix& t)
{
if (childrenTransform() == t)
return;
GraphicsLayer::setChildrenTransform(t);
didChangeGeometry();
}
void CoordinatedGraphicsLayer::setPreserves3D(bool b)
{
if (preserves3D() == b)
return;
GraphicsLayer::setPreserves3D(b);
didChangeGeometry();
}
void CoordinatedGraphicsLayer::setMasksToBounds(bool b)
{
if (masksToBounds() == b)
return;
GraphicsLayer::setMasksToBounds(b);
didChangeGeometry();
}
void CoordinatedGraphicsLayer::setDrawsContent(bool b)
{
if (drawsContent() == b)
return;
GraphicsLayer::setDrawsContent(b);
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setContentsVisible(bool b)
{
if (contentsAreVisible() == b)
return;
GraphicsLayer::setContentsVisible(b);
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setContentsOpaque(bool b)
{
if (contentsOpaque() == b)
return;
if (m_mainBackingStore)
m_mainBackingStore->setSupportsAlpha(!b);
GraphicsLayer::setContentsOpaque(b);
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setBackfaceVisibility(bool b)
{
if (backfaceVisibility() == b)
return;
GraphicsLayer::setBackfaceVisibility(b);
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setOpacity(float opacity)
{
if (this->opacity() == opacity)
return;
GraphicsLayer::setOpacity(opacity);
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setContentsRect(const IntRect& r)
{
if (contentsRect() == r)
return;
GraphicsLayer::setContentsRect(r);
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setContentsNeedsDisplay()
{
m_canvasNeedsDisplay = true;
if (client())
client()->notifyFlushRequired(this);
}
void CoordinatedGraphicsLayer::setContentsToCanvas(PlatformLayer* platformLayer)
{
m_canvasPlatformLayer = platformLayer;
m_canvasNeedsDisplay = true;
if (client())
client()->notifyFlushRequired(this);
}
#if ENABLE(CSS_FILTERS)
bool CoordinatedGraphicsLayer::setFilters(const FilterOperations& newFilters)
{
if (filters() == newFilters)
return true;
didChangeFilters();
return GraphicsLayer::setFilters(newFilters);
}
#endif
void CoordinatedGraphicsLayer::setContentsToImage(Image* image)
{
if (image) {
// This code makes the assumption that pointer equality on a NativeImagePtr is a valid way to tell if the image is changed.
// This assumption is true in Qt, GTK and EFL.
NativeImagePtr newNativeImagePtr = image->nativeImageForCurrentFrame();
if (!newNativeImagePtr)
return;
if (newNativeImagePtr == m_compositedNativeImagePtr)
return;
m_compositedImage = image;
m_compositedNativeImagePtr = newNativeImagePtr;
} else {
m_compositedImage = 0;
m_compositedNativeImagePtr = 0;
}
GraphicsLayer::setContentsToImage(image);
didChangeImageBacking();
}
void CoordinatedGraphicsLayer::setMaskLayer(GraphicsLayer* layer)
{
if (layer == maskLayer())
return;
GraphicsLayer::setMaskLayer(layer);
if (!layer)
return;
layer->setSize(size());
CoordinatedGraphicsLayer* CoordinatedGraphicsLayer = toCoordinatedGraphicsLayer(layer);
CoordinatedGraphicsLayer->setMaskTarget(this);
CoordinatedGraphicsLayer->didChangeLayerState();
didChangeLayerState();
}
bool CoordinatedGraphicsLayer::shouldDirectlyCompositeImage(Image* image) const
{
if (!image || !image->isBitmapImage())
return false;
enum { kMaxDimenstionForDirectCompositing = 2000 };
if (image->width() > kMaxDimenstionForDirectCompositing || image->height() > kMaxDimenstionForDirectCompositing)
return false;
return true;
}
void CoordinatedGraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
{
if (layer == replicaLayer())
return;
GraphicsLayer::setReplicatedByLayer(layer);
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setNeedsDisplay()
{
setNeedsDisplayInRect(IntRect(IntPoint::zero(), IntSize(size().width(), size().height())));
}
void CoordinatedGraphicsLayer::setNeedsDisplayInRect(const FloatRect& rect)
{
if (m_mainBackingStore)
m_mainBackingStore->invalidate(IntRect(rect));
didChangeLayerState();
}
WebLayerID CoordinatedGraphicsLayer::id() const
{
return m_id;
}
void CoordinatedGraphicsLayer::flushCompositingState(const FloatRect& rect)
{
if (CoordinatedGraphicsLayer* mask = toCoordinatedGraphicsLayer(maskLayer()))
mask->flushCompositingStateForThisLayerOnly();
if (CoordinatedGraphicsLayer* replica = toCoordinatedGraphicsLayer(replicaLayer()))
replica->flushCompositingStateForThisLayerOnly();
m_coordinator->syncFixedLayers();
flushCompositingStateForThisLayerOnly();
for (size_t i = 0; i < children().size(); ++i)
children()[i]->flushCompositingState(rect);
}
CoordinatedGraphicsLayer* toCoordinatedGraphicsLayer(GraphicsLayer* layer)
{
return static_cast<CoordinatedGraphicsLayer*>(layer);
}
void CoordinatedGraphicsLayer::syncChildren()
{
if (!m_shouldSyncChildren)
return;
m_shouldSyncChildren = false;
Vector<WebLayerID> childIDs;
for (size_t i = 0; i < children().size(); ++i)
childIDs.append(toWebLayerID(children()[i]));
m_coordinator->syncLayerChildren(m_id, childIDs);
}
#if ENABLE(CSS_FILTERS)
void CoordinatedGraphicsLayer::syncFilters()
{
if (!m_shouldSyncFilters)
return;
m_shouldSyncFilters = false;
m_coordinator->syncLayerFilters(m_id, filters());
}
#endif
void CoordinatedGraphicsLayer::syncImageBacking()
{
if (!m_shouldSyncImageBacking)
return;
m_shouldSyncImageBacking = false;
releaseImageBackingIfNeeded();
if (m_compositedNativeImagePtr) {
ASSERT(!m_mainBackingStore);
ASSERT(m_compositedImage);
m_layerInfo.imageBackingStoreID = m_coordinator->adoptImageBackingStore(m_compositedImage.get());
}
// This method changes m_layerInfo.imageBackingStoreID.
didChangeLayerState();
}
void CoordinatedGraphicsLayer::syncLayerState()
{
if (!m_shouldSyncLayerState)
return;
m_shouldSyncLayerState = false;
m_layerInfo.fixedToViewport = fixedToViewport();
m_layerInfo.anchorPoint = anchorPoint();
m_layerInfo.backfaceVisible = backfaceVisibility();
m_layerInfo.childrenTransform = childrenTransform();
m_layerInfo.contentsOpaque = contentsOpaque();
m_layerInfo.contentsRect = contentsRect();
m_layerInfo.drawsContent = drawsContent();
m_layerInfo.contentsVisible = contentsAreVisible();
m_layerInfo.mask = toWebLayerID(maskLayer());
m_layerInfo.masksToBounds = masksToBounds();
m_layerInfo.opacity = opacity();
m_layerInfo.pos = position();
m_layerInfo.preserves3D = preserves3D();
m_layerInfo.replica = toWebLayerID(replicaLayer());
m_layerInfo.size = size();
m_layerInfo.transform = transform();
m_coordinator->syncLayerState(m_id, m_layerInfo);
}
void CoordinatedGraphicsLayer::syncAnimations()
{
if (!m_shouldSyncAnimations)
return;
m_shouldSyncAnimations = false;
m_coordinator->setLayerAnimations(m_id, m_animations);
}
void CoordinatedGraphicsLayer::syncCanvas()
{
if (!m_canvasNeedsDisplay)
return;
if (!m_canvasPlatformLayer)
return;
#if USE(GRAPHICS_SURFACE)
uint32_t frontBuffer = m_canvasPlatformLayer->copyToGraphicsSurface();
GraphicsSurfaceToken token = m_canvasPlatformLayer->graphicsSurfaceToken();
m_coordinator->syncCanvas(m_id, IntSize(size().width(), size().height()), token, frontBuffer);
#endif
m_canvasNeedsDisplay = false;
}
void CoordinatedGraphicsLayer::flushCompositingStateForThisLayerOnly()
{
syncImageBacking();
syncLayerState();
syncAnimations();
computeTransformedVisibleRect();
syncChildren();
#if ENABLE(CSS_FILTERS)
syncFilters();
#endif
updateContentBuffers();
syncCanvas();
}
void CoordinatedGraphicsLayer::releaseImageBackingIfNeeded()
{
if (!m_layerInfo.imageBackingStoreID)
return;
ASSERT(m_coordinator);
m_coordinator->releaseImageBackingStore(m_layerInfo.imageBackingStoreID);
m_layerInfo.imageBackingStoreID = 0;
}
void CoordinatedGraphicsLayer::tiledBackingStorePaintBegin()
{
}
void CoordinatedGraphicsLayer::setRootLayer(bool isRoot)
{
m_layerInfo.isRootLayer = isRoot;
didChangeLayerState();
}
void CoordinatedGraphicsLayer::setVisibleContentRectTrajectoryVector(const FloatPoint& trajectoryVector)
{
if (m_mainBackingStore)
m_mainBackingStore->coverWithTilesIfNeeded(trajectoryVector);
}
void CoordinatedGraphicsLayer::setContentsScale(float scale)
{
m_contentsScale = scale;
adjustContentsScale();
}
float CoordinatedGraphicsLayer::effectiveContentsScale()
{
return shouldUseTiledBackingStore() ? m_contentsScale : 1;
}
void CoordinatedGraphicsLayer::adjustContentsScale()
{
if (!drawsContent() || !contentsAreVisible() || m_size.isEmpty())
return;
if (!m_mainBackingStore || m_mainBackingStore->contentsScale() == effectiveContentsScale())
return;
// Between creating the new backing store and painting the content,
// we do not want to drop the previous one as that might result in
// briefly seeing flickering as the old tiles may be dropped before
// something replaces them.
m_previousBackingStore = m_mainBackingStore.release();
// No reason to save the previous backing store for non-visible areas.
m_previousBackingStore->removeAllNonVisibleTiles();
createBackingStore();
}
void CoordinatedGraphicsLayer::createBackingStore()
{
m_mainBackingStore = adoptPtr(new TiledBackingStore(this, CoordinatedTileBackend::create(this)));
m_mainBackingStore->setSupportsAlpha(!contentsOpaque());
m_mainBackingStore->setContentsScale(effectiveContentsScale());
}
void CoordinatedGraphicsLayer::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
{
if (rect.isEmpty())
return;
paintGraphicsLayerContents(*context, rect);
}
void CoordinatedGraphicsLayer::tiledBackingStorePaintEnd(const Vector<IntRect>& /* updatedRects */)
{
}
bool CoordinatedGraphicsLayer::tiledBackingStoreUpdatesAllowed() const
{
if (!m_inUpdateMode)
return false;
return m_coordinator->layerTreeTileUpdatesAllowed();
}
IntRect CoordinatedGraphicsLayer::tiledBackingStoreContentsRect()
{
return IntRect(0, 0, size().width(), size().height());
}
bool CoordinatedGraphicsLayer::shouldUseTiledBackingStore()
{
return !selfOrAncestorHaveNonAffineTransforms();
}
IntRect CoordinatedGraphicsLayer::tiledBackingStoreVisibleRect()
{
if (!shouldUseTiledBackingStore())
return tiledBackingStoreContentsRect();
// Non-invertible layers are not visible.
if (!m_layerTransform.combined().isInvertible())
return IntRect();
// Return a projection of the visible rect (surface coordinates) onto the layer's plane (layer coordinates).
// The resulting quad might be squewed and the visible rect is the bounding box of this quad,
// so it might spread further than the real visible area (and then even more amplified by the cover rect multiplier).
return enclosingIntRect(m_layerTransform.combined().inverse().clampedBoundsOfProjectedQuad(FloatQuad(FloatRect(m_coordinator->visibleContentsRect()))));
}
Color CoordinatedGraphicsLayer::tiledBackingStoreBackgroundColor() const
{
return contentsOpaque() ? Color::white : Color::transparent;
}
PassOwnPtr<WebCore::GraphicsContext> CoordinatedGraphicsLayer::beginContentUpdate(const WebCore::IntSize& size, int& atlas, WebCore::IntPoint& offset)
{
return m_coordinator->beginContentUpdate(size, contentsOpaque() ? 0 : ShareableBitmap::SupportsAlpha, atlas, offset);
}
void CoordinatedGraphicsLayer::createTile(int tileID, const SurfaceUpdateInfo& updateInfo, const WebCore::IntRect& tileRect)
{
m_coordinator->createTile(id(), tileID, updateInfo, tileRect);
}
void CoordinatedGraphicsLayer::updateTile(int tileID, const SurfaceUpdateInfo& updateInfo, const IntRect& tileRect)
{
m_coordinator->updateTile(id(), tileID, updateInfo, tileRect);
}
void CoordinatedGraphicsLayer::removeTile(int tileID)
{
m_coordinator->removeTile(id(), tileID);
}
void CoordinatedGraphicsLayer::updateContentBuffers()
{
if (!drawsContent()) {
m_mainBackingStore.clear();
m_previousBackingStore.clear();
return;
}
m_inUpdateMode = true;
// This is the only place we (re)create the main tiled backing store, once we
// have a remote client and we are ready to send our data to the UI process.
if (!m_mainBackingStore)
createBackingStore();
m_mainBackingStore->updateTileBuffers();
m_inUpdateMode = false;
// The previous backing store is kept around to avoid flickering between
// removing the existing tiles and painting the new ones. The first time
// the visibleRect is full painted we remove the previous backing store.
if (m_mainBackingStore->visibleAreaIsCovered())
m_previousBackingStore.clear();
}
void CoordinatedGraphicsLayer::purgeBackingStores()
{
m_mainBackingStore.clear();
m_previousBackingStore.clear();
releaseImageBackingIfNeeded();
didChangeLayerState();
didChangeChildren();
}
void CoordinatedGraphicsLayer::setCoordinator(WebKit::CoordinatedGraphicsLayerClient* coordinator)
{
m_coordinator = coordinator;
}
void CoordinatedGraphicsLayer::adjustVisibleRect()
{
if (m_mainBackingStore)
m_mainBackingStore->coverWithTilesIfNeeded();
}
bool CoordinatedGraphicsLayer::hasPendingVisibleChanges()
{
if (opacity() < 0.01 && !m_animations.hasActiveAnimationsOfType(AnimatedPropertyOpacity))
return false;
for (size_t i = 0; i < children().size(); ++i) {
if (toCoordinatedGraphicsLayer(children()[i])->hasPendingVisibleChanges())
return true;
}
if (!m_shouldSyncLayerState && !m_shouldSyncChildren && !m_shouldSyncFilters && !m_shouldSyncImageBacking && !m_shouldSyncAnimations && !m_canvasNeedsDisplay)
return false;
return selfOrAncestorHaveNonAffineTransforms() || !tiledBackingStoreVisibleRect().isEmpty();
}
void CoordinatedGraphicsLayer::computeTransformedVisibleRect()
{
if (!m_shouldUpdateVisibleRect)
return;
m_shouldUpdateVisibleRect = false;
m_layerTransform.setLocalTransform(transform());
m_layerTransform.setPosition(position());
m_layerTransform.setAnchorPoint(anchorPoint());
m_layerTransform.setSize(size());
m_layerTransform.setFlattening(!preserves3D());
m_layerTransform.setChildrenTransform(childrenTransform());
m_layerTransform.combineTransforms(parent() ? toCoordinatedGraphicsLayer(parent())->m_layerTransform.combinedForChildren() : TransformationMatrix());
// The combined transform will be used in tiledBackingStoreVisibleRect.
adjustVisibleRect();
adjustContentsScale();
}
static PassOwnPtr<GraphicsLayer> createCoordinatedGraphicsLayer(GraphicsLayerClient* client)
{
return adoptPtr(new CoordinatedGraphicsLayer(client));
}
void CoordinatedGraphicsLayer::initFactory()
{
GraphicsLayer::setGraphicsLayerFactory(createCoordinatedGraphicsLayer);
}
bool CoordinatedGraphicsLayer::selfOrAncestorHaveNonAffineTransforms()
{
if (m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitTransform))
return true;
if (!m_layerTransform.combined().isAffine())
return true;
return false;
}
bool CoordinatedGraphicsLayer::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double delayAsNegativeTimeOffset)
{
ASSERT(!keyframesName.isEmpty());
if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyWebkitTransform && valueList.property() != AnimatedPropertyOpacity))
return false;
bool listsMatch = false;
bool ignoredHasBigRotation;
if (valueList.property() == AnimatedPropertyWebkitTransform)
listsMatch = validateTransformOperations(valueList, ignoredHasBigRotation) >= 0;
m_lastAnimationStartTime = WTF::currentTime() - delayAsNegativeTimeOffset;
m_animations.add(GraphicsLayerAnimation(keyframesName, valueList, boxSize, anim, m_lastAnimationStartTime, listsMatch));
m_animationStartedTimer.startOneShot(0);
didChangeAnimations();
return true;
}
void CoordinatedGraphicsLayer::pauseAnimation(const String& animationName, double time)
{
m_animations.pause(animationName, time);
didChangeAnimations();
}
void CoordinatedGraphicsLayer::removeAnimation(const String& animationName)
{
m_animations.remove(animationName);
didChangeAnimations();
}
void CoordinatedGraphicsLayer::animationStartedTimerFired(Timer<CoordinatedGraphicsLayer>*)
{
client()->notifyAnimationStarted(this, m_lastAnimationStartTime);
}
}
#endif