GraphicsLayerQt.cpp [plain text]
#include "config.h"
#include "GraphicsLayerQt.h"
#if !defined(QT_NO_GRAPHICSVIEW)
#include "CurrentTime.h"
#include "FloatRect.h"
#include "GraphicsContext.h"
#include "Image.h"
#include "RefCounted.h"
#include "TranslateTransformOperation.h"
#include "UnitBezier.h"
#include <QtCore/qabstractanimation.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qset.h>
#include <QtCore/qtimer.h>
#include <QtGui/qcolor.h>
#include <QtGui/qgraphicseffect.h>
#include <QtGui/qgraphicsitem.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qgraphicswidget.h>
#include <QtGui/qpainter.h>
#include <QtGui/qpixmap.h>
#include <QtGui/qpixmapcache.h>
#include <QtGui/qstyleoption.h>
#if ENABLE(TILED_BACKING_STORE)
#include "TiledBackingStore.h"
#include "TiledBackingStoreClient.h"
#define GRAPHICS_LAYER_TILING_THRESHOLD 2000
#endif
#define QT_DEBUG_RECACHE 0
#define QT_DEBUG_CACHEDUMP 0
#define QT_DEBUG_FPS 0
namespace WebCore {
static const int gMinimumPixmapCacheLimit = 2048;
#ifndef QT_NO_GRAPHICSEFFECT
class MaskEffectQt : public QGraphicsEffect {
public:
MaskEffectQt(QObject* parent, QGraphicsItem* maskLayer)
: QGraphicsEffect(parent)
, m_maskLayer(maskLayer)
{
}
void draw(QPainter* painter)
{
const QSize maskSize = sourceBoundingRect().toAlignedRect().size();
if (!maskSize.isValid() || maskSize.isEmpty()) {
drawSource(painter);
return;
}
QPixmap maskPixmap(maskSize);
maskPixmap.fill(Qt::transparent);
QPainter maskPainter(&maskPixmap);
QStyleOptionGraphicsItem option;
option.exposedRect = option.rect = maskPixmap.rect();
maskPainter.setRenderHints(painter->renderHints(), true);
m_maskLayer->paint(&maskPainter, &option, 0);
maskPainter.end();
QPoint offset;
QPixmap srcPixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, QGraphicsEffect::NoPad);
QPixmap pixmap(srcPixmap.size());
pixmap.fill(Qt::transparent);
if (pixmap.isNull())
return;
QPainter pixmapPainter(&pixmap);
pixmapPainter.setRenderHints(painter->renderHints());
pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
pixmapPainter.drawPixmap(0, 0, srcPixmap);
pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
pixmapPainter.drawPixmap(0, 0, maskPixmap);
pixmapPainter.end();
painter->drawPixmap(offset, pixmap);
}
QGraphicsItem* m_maskLayer;
};
#endif // QT_NO_GRAPHICSEFFECT
class GraphicsLayerQtImpl : public QGraphicsObject
#if ENABLE(TILED_BACKING_STORE)
, public virtual TiledBackingStoreClient
#endif
{
Q_OBJECT
public:
enum ChangeMask {
NoChanges = 0,
ParentChange = (1L << 0),
ChildrenChange = (1L << 1),
MaskLayerChange = (1L << 2),
PositionChange = (1L << 3),
AnchorPointChange = (1L << 4),
SizeChange = (1L << 5),
TransformChange = (1L << 6),
ContentChange = (1L << 7),
ContentsOrientationChange = (1L << 8),
OpacityChange = (1L << 9),
ContentsRectChange = (1L << 10),
Preserves3DChange = (1L << 11),
MasksToBoundsChange = (1L << 12),
DrawsContentChange = (1L << 13),
ContentsOpaqueChange = (1L << 14),
BackfaceVisibilityChange = (1L << 15),
ChildrenTransformChange = (1L << 16),
DisplayChange = (1L << 17),
BackgroundColorChange = (1L << 18),
DistributesOpacityChange = (1L << 19)
};
enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType, MediaContentType, Canvas3DContentType};
const GraphicsLayerQtImpl* rootLayer() const;
GraphicsLayerQtImpl(GraphicsLayerQt* newLayer);
virtual ~GraphicsLayerQtImpl();
virtual QPainterPath opaqueArea() const;
virtual QRectF boundingRect() const;
virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
void setBaseTransform(const TransformationMatrix&);
void updateTransform();
void notifyChange(ChangeMask);
QPixmap recache(const QRegion&);
void flushChanges(bool recursive = true, bool forceTransformUpdate = false);
#if ENABLE(TILED_BACKING_STORE)
virtual void tiledBackingStorePaintBegin();
virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&);
virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea);
virtual IntRect tiledBackingStoreContentsRect();
virtual IntRect tiledBackingStoreVisibleRect();
virtual Color tiledBackingStoreBackgroundColor() const;
#endif
static bool allowAcceleratedCompositingCache() { return QPixmapCache::cacheLimit() > gMinimumPixmapCacheLimit; }
void drawLayerContent(QPainter*, const QRect&);
public slots:
void notifyAnimationStarted();
void notifySyncRequired();
signals:
void notifyAnimationStartedAsync();
public:
GraphicsLayerQt* m_layer;
TransformationMatrix m_baseTransform;
TransformationMatrix m_transformRelativeToRootLayer;
bool m_transformAnimationRunning;
bool m_opacityAnimationRunning;
bool m_blockNotifySyncRequired;
#ifndef QT_NO_GRAPHICSEFFECT
QWeakPointer<MaskEffectQt> m_maskEffect;
#endif
struct ContentData {
QPixmap pixmap;
QRegion regionToUpdate;
bool updateAll;
QColor contentsBackgroundColor;
QColor backgroundColor;
QWeakPointer<QGraphicsObject> mediaLayer;
StaticContentType contentType;
float opacity;
ContentData()
: updateAll(false)
, contentType(HTMLContentType)
, opacity(1.f)
{
}
};
ContentData m_pendingContent;
ContentData m_currentContent;
int m_changeMask;
#if ENABLE(TILED_BACKING_STORE)
TiledBackingStore* m_tiledBackingStore;
#endif
QSizeF m_size;
struct {
QPixmapCache::Key key;
QSizeF size;
} m_backingStore;
#ifndef QT_NO_ANIMATION
QList<QWeakPointer<QAbstractAnimation> > m_animations;
#endif
QTimer m_suspendTimer;
struct State {
GraphicsLayer* maskLayer;
FloatPoint pos;
FloatPoint3D anchorPoint;
FloatSize size;
TransformationMatrix transform;
TransformationMatrix childrenTransform;
Color backgroundColor;
Color currentColor;
GraphicsLayer::CompositingCoordinatesOrientation contentsOrientation;
float opacity;
QRect contentsRect;
bool preserves3D: 1;
bool masksToBounds: 1;
bool drawsContent: 1;
bool contentsOpaque: 1;
bool backfaceVisibility: 1;
bool distributeOpacity: 1;
bool align: 2;
State()
: maskLayer(0)
, contentsOrientation(GraphicsLayer::CompositingCoordinatesTopDown)
, opacity(1.f)
, preserves3D(false)
, masksToBounds(false)
, drawsContent(false)
, contentsOpaque(false)
, backfaceVisibility(true)
, distributeOpacity(false)
{
}
} m_state;
#ifndef QT_NO_ANIMATION
friend class AnimationQtBase;
#endif
};
inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsItem* item)
{
ASSERT(item);
return qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject());
}
inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsObject* item)
{
return qobject_cast<GraphicsLayerQtImpl*>(item);
}
GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
: QGraphicsObject(0)
, m_layer(newLayer)
, m_transformAnimationRunning(false)
, m_opacityAnimationRunning(false)
, m_blockNotifySyncRequired(false)
, m_changeMask(NoChanges)
#if ENABLE(TILED_BACKING_STORE)
, m_tiledBackingStore(0)
#endif
{
setAcceptedMouseButtons(Qt::NoButton);
setEnabled(true);
connect(this, SIGNAL(notifyAnimationStartedAsync()), this, SLOT(notifyAnimationStarted()), Qt::QueuedConnection);
}
GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
{
const QList<QGraphicsItem*> children = childItems();
QList<QGraphicsItem*>::const_iterator cit;
for (cit = children.constBegin(); cit != children.constEnd(); ++cit) {
if (QGraphicsItem* item = *cit) {
if (scene())
scene()->removeItem(item);
item->setParentItem(0);
}
}
#if ENABLE(TILED_BACKING_STORE)
delete m_tiledBackingStore;
#endif
#ifndef QT_NO_ANIMATION
QList<QWeakPointer<QAbstractAnimation> >::iterator it;
for (it = m_animations.begin(); it != m_animations.end(); ++it)
if (QAbstractAnimation* anim = it->data())
delete anim;
#endif
}
const GraphicsLayerQtImpl* GraphicsLayerQtImpl::rootLayer() const
{
if (const GraphicsLayerQtImpl* parent = toGraphicsLayerQtImpl(parentObject()))
return parent->rootLayer();
return this;
}
void GraphicsLayerQtImpl::drawLayerContent(QPainter* painter, const QRect& clipRect)
{
painter->setClipRect(clipRect, Qt::IntersectClip);
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
GraphicsContext gc(painter);
m_layer->paintGraphicsLayerContents(gc, clipRect);
}
QPixmap GraphicsLayerQtImpl::recache(const QRegion& regionToUpdate)
{
if (!m_layer->drawsContent() || m_size.isEmpty() || !m_size.isValid())
return QPixmap();
#if ENABLE(TILED_BACKING_STORE)
const bool requiresTiling = (m_state.drawsContent && m_currentContent.contentType == HTMLContentType) && (m_size.width() > GRAPHICS_LAYER_TILING_THRESHOLD || m_size.height() > GRAPHICS_LAYER_TILING_THRESHOLD);
if (requiresTiling && !m_tiledBackingStore) {
m_tiledBackingStore = new TiledBackingStore(this);
m_tiledBackingStore->setTileCreationDelay(0);
setFlag(ItemUsesExtendedStyleOption, true);
} else if (!requiresTiling && m_tiledBackingStore) {
delete m_tiledBackingStore;
m_tiledBackingStore = 0;
setFlag(ItemUsesExtendedStyleOption, false);
}
if (m_tiledBackingStore) {
m_tiledBackingStore->adjustVisibleRect();
const QVector<QRect> rects = regionToUpdate.rects();
for (int i = 0; i < rects.size(); ++i)
m_tiledBackingStore->invalidate(rects[i]);
return QPixmap();
}
#endif
QPixmap pixmap;
QRegion region = regionToUpdate;
if (QPixmapCache::find(m_backingStore.key, &pixmap)) {
if (region.isEmpty())
return pixmap;
QPixmapCache::remove(m_backingStore.key); }
{
bool erased = false;
if (pixmap.isNull() || m_size != m_backingStore.size) {
#if QT_DEBUG_RECACHE
if (pixmap.isNull())
qDebug() << "CacheMiss" << this << m_size;
#endif
bool fill = true;
QRegion newRegion;
QPixmap oldPixmap = pixmap;
if (pixmap.width() < m_size.width() || pixmap.height() < m_size.height()) {
#if QT_DEBUG_RECACHE
qDebug() << "CacheGrow" << this << m_size;
#endif
pixmap = QPixmap(m_size.toSize());
pixmap.fill(Qt::transparent);
newRegion = QRegion(0, 0, m_size.width(), m_size.height());
}
#if 1
if (!oldPixmap.isNull()) {
const QRegion cleanRegion = (QRegion(0, 0, m_size.width(), m_size.height())
& QRegion(0, 0, m_backingStore.size.width(), m_backingStore.size.height())) - regionToUpdate;
if (!cleanRegion.isEmpty()) {
#if QT_DEBUG_RECACHE
qDebug() << "CacheBlit" << this << cleanRegion;
#endif
const QRect cleanBounds(cleanRegion.boundingRect());
QPainter painter(&pixmap);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawPixmap(cleanBounds.topLeft(), oldPixmap, cleanBounds);
newRegion -= cleanRegion;
fill = false; }
oldPixmap = QPixmap();
}
#endif
region += newRegion;
if (fill && !region.isEmpty()) { #if QT_DEBUG_RECACHE
qDebug() << "CacheErase" << this << m_size << background;
#endif
erased = true;
pixmap.fill(Qt::transparent);
}
}
region &= QRegion(0, 0, m_size.width(), m_size.height());
if (!region.isEmpty()) {
#if QT_DEBUG_CACHEDUMP
static int recacheCount = 0;
++recacheCount;
qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
pixmap.save(QString().sprintf("/tmp/%05d_A.png", recacheCount), "PNG");
#endif
QPainter painter(&pixmap);
GraphicsContext gc(&painter);
painter.setClipRegion(region);
if (!erased) { painter.setCompositionMode(QPainter::CompositionMode_Clear);
painter.fillRect(region.boundingRect(), Qt::transparent);
#if QT_DEBUG_CACHEDUMP
qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
pixmap.save(QString().sprintf("/tmp/%05d_B.png", recacheCount), "PNG");
#endif
}
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
m_layer->paintGraphicsLayerContents(gc, region.boundingRect());
painter.end();
#if QT_DEBUG_CACHEDUMP
qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
pixmap.save(QString().sprintf("/tmp/%05d_C.png", recacheCount), "PNG");
#endif
}
m_backingStore.size = m_size; }
m_backingStore.key = QPixmapCache::insert(pixmap);
return pixmap;
}
void GraphicsLayerQtImpl::updateTransform()
{
if (!m_transformAnimationRunning)
m_baseTransform = m_layer->transform();
TransformationMatrix localTransform;
GraphicsLayerQtImpl* parent = toGraphicsLayerQtImpl(parentObject());
const qreal originX = m_state.anchorPoint.x() * m_size.width();
const qreal originY = m_state.anchorPoint.y() * m_size.height();
localTransform
.translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z())
.multiply(m_baseTransform)
.translate3d(-originX, -originY, -m_state.anchorPoint.z());
m_transformRelativeToRootLayer = TransformationMatrix(parent ? parent->m_transformRelativeToRootLayer : TransformationMatrix())
.multiply(localTransform);
if (!m_state.backfaceVisibility && m_transformRelativeToRootLayer.inverse().m33() < 0) {
setVisible(false);
return;
}
setVisible(true);
if (!m_state.preserves3D) {
m_transformRelativeToRootLayer.setM13(0);
m_transformRelativeToRootLayer.setM23(0);
m_transformRelativeToRootLayer.setM31(0);
m_transformRelativeToRootLayer.setM32(0);
m_transformRelativeToRootLayer.setM33(1);
m_transformRelativeToRootLayer.setM34(0);
m_transformRelativeToRootLayer.setM43(0);
}
if (!m_state.childrenTransform.isIdentity()) {
m_transformRelativeToRootLayer
.translate(m_size.width() / 2, m_size.height() /2)
.multiply(m_state.childrenTransform)
.translate(-m_size.width() / 2, -m_size.height() /2);
}
bool inverseOk = true;
const QTransform parentTransform = parent ? parent->itemTransform(rootLayer()) : QTransform();
const QTransform transform2D = QTransform(m_transformRelativeToRootLayer) * parentTransform.inverted(&inverseOk);
if (!inverseOk)
return;
setTransform(transform2D);
const QList<QGraphicsItem*> children = childItems();
QList<QGraphicsItem*>::const_iterator it;
for (it = children.constBegin(); it != children.constEnd(); ++it)
if (GraphicsLayerQtImpl* layer= toGraphicsLayerQtImpl(*it))
layer->updateTransform();
}
void GraphicsLayerQtImpl::setBaseTransform(const TransformationMatrix& baseTransform)
{
m_baseTransform = baseTransform;
updateTransform();
}
QPainterPath GraphicsLayerQtImpl::opaqueArea() const
{
QPainterPath painterPath;
if (m_currentContent.backgroundColor.isValid() && m_currentContent.backgroundColor.alpha() == 0xff)
painterPath.addRect(boundingRect());
else {
if (m_state.contentsOpaque
|| (m_currentContent.contentType == ColorContentType && m_currentContent.contentsBackgroundColor.alpha() == 0xff)
|| (m_currentContent.contentType == MediaContentType)
|| (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlpha())) {
painterPath.addRect(m_state.contentsRect);
}
}
return painterPath;
}
QRectF GraphicsLayerQtImpl::boundingRect() const
{
return QRectF(QPointF(0, 0), QSizeF(m_size));
}
void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
#if ENABLE(TILED_BACKING_STORE)
if (m_tiledBackingStore)
m_tiledBackingStore->adjustVisibleRect();
#endif
if (m_currentContent.backgroundColor.isValid())
painter->fillRect(option->exposedRect, QColor(m_currentContent.backgroundColor));
switch (m_currentContent.contentType) {
case HTMLContentType:
if (m_state.drawsContent) {
if (!allowAcceleratedCompositingCache())
drawLayerContent(painter, option->exposedRect.toRect());
else {
QPixmap backingStore;
if (!QPixmapCache::find(m_backingStore.key, &backingStore) || backingStore.size() != m_size.toSize())
backingStore = recache(QRegion(m_state.contentsRect));
painter->drawPixmap(0, 0, backingStore);
}
}
break;
case PixmapContentType:
painter->drawPixmap(m_state.contentsRect, m_currentContent.pixmap);
break;
case ColorContentType:
painter->fillRect(m_state.contentsRect, m_currentContent.contentsBackgroundColor);
break;
case MediaContentType:
break;
}
}
void GraphicsLayerQtImpl::notifySyncRequired()
{
m_blockNotifySyncRequired = false;
if (m_layer->client())
m_layer->client()->notifySyncRequired(m_layer);
}
void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
{
m_changeMask |= changeMask;
if (m_blockNotifySyncRequired)
return;
static QMetaMethod syncMethod = staticMetaObject.method(staticMetaObject.indexOfMethod("notifySyncRequired()"));
syncMethod.invoke(this, Qt::QueuedConnection);
m_blockNotifySyncRequired = true;
}
void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform)
{
if (!m_layer || m_changeMask == NoChanges)
goto afterLayerChanges;
if (m_changeMask & ParentChange) {
if (!m_layer->parent() && !parentItem())
setParentItem(0);
else if (m_layer && m_layer->parent() && m_layer->parent()->platformLayer() != parentItem())
setParentItem(m_layer->parent()->platformLayer());
}
if (m_changeMask & ChildrenChange) {
QSet<QGraphicsItem*> newChildren;
const Vector<GraphicsLayer*> newChildrenVector = (m_layer->children());
newChildren.reserve(newChildrenVector.size());
for (size_t i = 0; i < newChildrenVector.size(); ++i)
newChildren.insert(newChildrenVector[i]->platformLayer());
const QSet<QGraphicsItem*> currentChildren = childItems().toSet();
const QSet<QGraphicsItem*> childrenToAdd = newChildren - currentChildren;
const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren;
QSet<QGraphicsItem*>::const_iterator it;
for (it = childrenToAdd.constBegin(); it != childrenToAdd.constEnd(); ++it) {
if (QGraphicsItem* w = *it)
w->setParentItem(this);
}
QSet<QGraphicsItem*>::const_iterator rit;
for (rit = childrenToRemove.constBegin(); rit != childrenToRemove.constEnd(); ++rit) {
if (GraphicsLayerQtImpl* w = toGraphicsLayerQtImpl(*rit))
w->setParentItem(0);
}
for (size_t i = 0; i < newChildrenVector.size(); ++i) {
if (newChildrenVector[i]->platformLayer())
newChildrenVector[i]->platformLayer()->setZValue(i);
}
}
if (m_changeMask & MaskLayerChange) {
setFlag(ItemClipsChildrenToShape, m_layer->maskLayer() || m_layer->masksToBounds());
#ifndef QT_NO_GRAPHICSEFFECT
setGraphicsEffect(0);
if (m_layer->maskLayer()) {
if (GraphicsLayerQtImpl* mask = toGraphicsLayerQtImpl(m_layer->maskLayer()->platformLayer())) {
mask->m_maskEffect = new MaskEffectQt(this, mask);
setGraphicsEffect(mask->m_maskEffect.data());
}
}
#endif
}
if (m_changeMask & SizeChange) {
if (m_layer->size() != m_state.size) {
prepareGeometryChange();
m_size = QSizeF(m_layer->size().width(), m_layer->size().height());
}
}
if ((m_changeMask & ChildrenTransformChange) && m_state.childrenTransform != m_layer->childrenTransform())
if (scene())
scene()->update();
if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | BackfaceVisibilityChange | PositionChange | ParentChange)) {
forceUpdateTransform = true;
}
if (m_changeMask & (ContentChange | DrawsContentChange | MaskLayerChange)) {
switch (m_pendingContent.contentType) {
case PixmapContentType:
update();
setFlag(ItemHasNoContents, false);
break;
case MediaContentType:
setFlag(ItemHasNoContents, true);
m_pendingContent.mediaLayer.data()->setParentItem(this);
break;
case ColorContentType:
if (m_pendingContent.contentType != m_currentContent.contentType
|| m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor)
update();
m_state.drawsContent = false;
setFlag(ItemHasNoContents, false);
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
break;
case HTMLContentType:
if (m_pendingContent.contentType != m_currentContent.contentType)
update();
else if (!m_state.drawsContent && m_layer->drawsContent())
update();
setFlag(ItemHasNoContents, !m_layer->drawsContent());
break;
}
}
if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity() && !m_opacityAnimationRunning)
setOpacity(m_layer->opacity());
if (m_changeMask & ContentsRectChange) {
const QRect rect(m_layer->contentsRect());
if (m_state.contentsRect != rect) {
m_state.contentsRect = rect;
if (m_pendingContent.mediaLayer) {
QGraphicsWidget* widget = qobject_cast<QGraphicsWidget*>(m_pendingContent.mediaLayer.data());
if (widget)
widget->setGeometry(rect);
}
update();
}
}
if ((m_changeMask & MasksToBoundsChange) && m_state.masksToBounds != m_layer->masksToBounds()) {
setFlag(QGraphicsItem::ItemClipsToShape, m_layer->masksToBounds());
setFlag(QGraphicsItem::ItemClipsChildrenToShape, m_layer->masksToBounds());
}
if ((m_changeMask & ContentsOpaqueChange) && m_state.contentsOpaque != m_layer->contentsOpaque())
prepareGeometryChange();
#ifndef QT_NO_GRAPHICSEFFECT
if (m_maskEffect)
m_maskEffect.data()->update();
else
#endif
if (m_changeMask & DisplayChange) {
#ifndef QT_GRAPHICS_LAYER_NO_RECACHE_ON_DISPLAY_CHANGE
if (m_pendingContent.contentType == HTMLContentType && allowAcceleratedCompositingCache())
recache(m_pendingContent.regionToUpdate);
#endif
update(m_pendingContent.regionToUpdate.boundingRect());
m_pendingContent.regionToUpdate = QRegion();
}
if ((m_changeMask & BackgroundColorChange)
&& (m_pendingContent.backgroundColor != m_currentContent.backgroundColor))
update();
m_state.maskLayer = m_layer->maskLayer();
m_state.pos = m_layer->position();
m_state.anchorPoint = m_layer->anchorPoint();
m_state.size = m_layer->size();
m_state.transform = m_layer->transform();
m_state.contentsOrientation =m_layer->contentsOrientation();
m_state.opacity = m_layer->opacity();
m_state.contentsRect = m_layer->contentsRect();
m_state.preserves3D = m_layer->preserves3D();
m_state.masksToBounds = m_layer->masksToBounds();
m_state.drawsContent = m_layer->drawsContent();
m_state.contentsOpaque = m_layer->contentsOpaque();
m_state.backfaceVisibility = m_layer->backfaceVisibility();
m_state.childrenTransform = m_layer->childrenTransform();
m_currentContent.pixmap = m_pendingContent.pixmap;
m_currentContent.contentType = m_pendingContent.contentType;
m_currentContent.mediaLayer = m_pendingContent.mediaLayer;
m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor;
m_pendingContent.regionToUpdate = QRegion();
m_changeMask = NoChanges;
afterLayerChanges:
if (forceUpdateTransform)
updateTransform();
if (!recursive)
return;
QList<QGraphicsItem*> children = childItems();
if (m_state.maskLayer)
children.append(m_state.maskLayer->platformLayer());
QList<QGraphicsItem*>::const_iterator it;
for (it = children.constBegin(); it != children.constEnd(); ++it) {
if (QGraphicsItem* item = *it) {
if (GraphicsLayerQtImpl* layer = toGraphicsLayerQtImpl(item))
layer->flushChanges(true, forceUpdateTransform);
}
}
}
#if ENABLE(TILED_BACKING_STORE)
void GraphicsLayerQtImpl::tiledBackingStorePaintBegin()
{
}
void GraphicsLayerQtImpl::tiledBackingStorePaint(GraphicsContext* gc, const IntRect& rect)
{
m_layer->paintGraphicsLayerContents(*gc, rect);
}
void GraphicsLayerQtImpl::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
{
for (int i = 0; i < paintedArea.size(); ++i)
update(QRectF(paintedArea[i]));
}
IntRect GraphicsLayerQtImpl::tiledBackingStoreContentsRect()
{
return m_layer->contentsRect();
}
Color GraphicsLayerQtImpl::tiledBackingStoreBackgroundColor() const
{
if (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlphaChannel())
return Color(0, 0, 0);
return Color(0, 0, 0, 0);
}
IntRect GraphicsLayerQtImpl::tiledBackingStoreVisibleRect()
{
const QGraphicsView* view = scene()->views().isEmpty() ? 0 : scene()->views().first();
if (!view)
return mapFromScene(scene()->sceneRect()).boundingRect().toAlignedRect();
return mapFromScene(view->mapToScene(view->viewport()->visibleRegion().boundingRect()).boundingRect()).boundingRect().toAlignedRect();
}
#endif
void GraphicsLayerQtImpl::notifyAnimationStarted()
{
m_layer->client()->notifyAnimationStarted(m_layer, WTF::currentTime());
}
GraphicsLayerQt::GraphicsLayerQt(GraphicsLayerClient* client)
: GraphicsLayer(client)
, m_impl(adoptPtr(new GraphicsLayerQtImpl(this)))
{
}
GraphicsLayerQt::~GraphicsLayerQt()
{
}
PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
{
return adoptPtr(new GraphicsLayerQt(client));
}
void GraphicsLayerQt::setNeedsDisplay()
{
m_impl->m_pendingContent.regionToUpdate = QRegion(QRect(QPoint(0, 0), QSize(size().width(), size().height())));
m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
}
void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& rect)
{
m_impl->m_pendingContent.regionToUpdate |= QRectF(rect).toAlignedRect();
m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
}
void GraphicsLayerQt::setContentsNeedsDisplay()
{
switch (m_impl->m_pendingContent.contentType) {
case GraphicsLayerQtImpl::MediaContentType:
if (!m_impl->m_pendingContent.mediaLayer)
return;
m_impl->m_pendingContent.mediaLayer.data()->update();
break;
default:
setNeedsDisplay();
break;
}
}
void GraphicsLayerQt::setName(const String& name)
{
m_impl->setObjectName(name);
GraphicsLayer::setName(name);
}
void GraphicsLayerQt::setParent(GraphicsLayer* layer)
{
m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
GraphicsLayer::setParent(layer);
}
bool GraphicsLayerQt::setChildren(const Vector<GraphicsLayer*>& children)
{
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
return GraphicsLayer::setChildren(children);
}
void GraphicsLayerQt::addChild(GraphicsLayer* layer)
{
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
GraphicsLayer::addChild(layer);
}
void GraphicsLayerQt::addChildAtIndex(GraphicsLayer* layer, int index)
{
GraphicsLayer::addChildAtIndex(layer, index);
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
}
void GraphicsLayerQt::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildAbove(layer, sibling);
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
}
void GraphicsLayerQt::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildBelow(layer, sibling);
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
}
bool GraphicsLayerQt::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
{
if (GraphicsLayer::replaceChild(oldChild, newChild)) {
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
return true;
}
return false;
}
void GraphicsLayerQt::removeFromParent()
{
if (parent())
m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
GraphicsLayer::removeFromParent();
}
void GraphicsLayerQt::setMaskLayer(GraphicsLayer* value)
{
if (value == maskLayer())
return;
GraphicsLayer::setMaskLayer(value);
m_impl->notifyChange(GraphicsLayerQtImpl::MaskLayerChange);
}
void GraphicsLayerQt::setPosition(const FloatPoint& value)
{
if (value == position())
return;
GraphicsLayer::setPosition(value);
m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange);
}
void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& value)
{
if (value == anchorPoint())
return;
GraphicsLayer::setAnchorPoint(value);
m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange);
}
void GraphicsLayerQt::setSize(const FloatSize& value)
{
if (value == size())
return;
GraphicsLayer::setSize(value);
m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange);
}
void GraphicsLayerQt::setTransform(const TransformationMatrix& value)
{
if (value == transform())
return;
GraphicsLayer::setTransform(value);
m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange);
}
void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& value)
{
if (value == childrenTransform())
return;
GraphicsLayer::setChildrenTransform(value);
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenTransformChange);
}
void GraphicsLayerQt::setPreserves3D(bool value)
{
if (value == preserves3D())
return;
GraphicsLayer::setPreserves3D(value);
m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange);
}
void GraphicsLayerQt::setMasksToBounds(bool value)
{
if (value == masksToBounds())
return;
GraphicsLayer::setMasksToBounds(value);
m_impl->notifyChange(GraphicsLayerQtImpl::MasksToBoundsChange);
}
void GraphicsLayerQt::setDrawsContent(bool value)
{
if (value == drawsContent())
return;
m_impl->notifyChange(GraphicsLayerQtImpl::DrawsContentChange);
GraphicsLayer::setDrawsContent(value);
}
void GraphicsLayerQt::setBackgroundColor(const Color& value)
{
if (value == m_impl->m_pendingContent.backgroundColor)
return;
m_impl->m_pendingContent.backgroundColor = value;
GraphicsLayer::setBackgroundColor(value);
m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
}
void GraphicsLayerQt::clearBackgroundColor()
{
if (!m_impl->m_pendingContent.backgroundColor.isValid())
return;
m_impl->m_pendingContent.backgroundColor = QColor();
GraphicsLayer::clearBackgroundColor();
m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
}
void GraphicsLayerQt::setContentsOpaque(bool value)
{
if (value == contentsOpaque())
return;
m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOpaqueChange);
GraphicsLayer::setContentsOpaque(value);
}
void GraphicsLayerQt::setBackfaceVisibility(bool value)
{
if (value == backfaceVisibility())
return;
GraphicsLayer::setBackfaceVisibility(value);
m_impl->notifyChange(GraphicsLayerQtImpl::BackfaceVisibilityChange);
}
void GraphicsLayerQt::setOpacity(float value)
{
if (value == opacity())
return;
GraphicsLayer::setOpacity(value);
m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
}
void GraphicsLayerQt::setContentsRect(const IntRect& value)
{
if (value == contentsRect())
return;
GraphicsLayer::setContentsRect(value);
m_impl->notifyChange(GraphicsLayerQtImpl::ContentsRectChange);
}
void GraphicsLayerQt::setContentsToImage(Image* image)
{
m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType;
GraphicsLayer::setContentsToImage(image);
if (image) {
QPixmap* pxm = image->nativeImageForCurrentFrame();
if (pxm) {
m_impl->m_pendingContent.pixmap = *pxm;
m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::PixmapContentType;
return;
}
}
m_impl->m_pendingContent.pixmap = QPixmap();
}
void GraphicsLayerQt::setContentsBackgroundColor(const Color& color)
{
m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::ColorContentType;
m_impl->m_pendingContent.contentsBackgroundColor = QColor(color);
GraphicsLayer::setContentsBackgroundColor(color);
}
void GraphicsLayerQt::setContentsToMedia(PlatformLayer* media)
{
if (media) {
m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::MediaContentType;
m_impl->m_pendingContent.mediaLayer = media->toGraphicsObject();
} else
m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType;
m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
GraphicsLayer::setContentsToMedia(media);
}
void GraphicsLayerQt::setContentsToCanvas(PlatformLayer* canvas)
{
setContentsToMedia(canvas);
}
void GraphicsLayerQt::setContentsOrientation(CompositingCoordinatesOrientation orientation)
{
m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOrientationChange);
GraphicsLayer::setContentsOrientation(orientation);
}
void GraphicsLayerQt::distributeOpacity(float o)
{
m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
m_impl->m_state.distributeOpacity = true;
}
float GraphicsLayerQt::accumulatedOpacity() const
{
return m_impl->effectiveOpacity();
}
void GraphicsLayerQt::syncCompositingState()
{
m_impl->flushChanges();
GraphicsLayer::syncCompositingState();
}
void GraphicsLayerQt::syncCompositingStateForThisLayerOnly()
{
m_impl->flushChanges(false);
GraphicsLayer::syncCompositingStateForThisLayerOnly();
}
PlatformLayer* GraphicsLayerQt::platformLayer() const
{
return m_impl.get();
}
template <typename T>
struct KeyframeValueQt {
const TimingFunction* timingFunction;
T value;
};
static inline double solveEpsilon(double duration)
{
return 1.0 / (200.0 * duration);
}
static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, qreal p2y, double t, double duration)
{
UnitBezier bezier(p1x, p1y, p2x, p2y);
return bezier.solve(t, solveEpsilon(duration));
}
static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t)
{
if (stepAtStart)
return qMin(1.0, (floor(numSteps * t) + 1) / numSteps);
return floor(numSteps * t) / numSteps;
}
static inline qreal applyTimingFunction(const TimingFunction* timingFunction, qreal progress, double duration)
{
if (timingFunction->isCubicBezierTimingFunction()) {
const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction);
return solveCubicBezierFunction(ctf->x1(),
ctf->y1(),
ctf->x2(),
ctf->y2(),
double(progress), double(duration) / 1000);
} else if (timingFunction->isStepsTimingFunction()) {
const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(timingFunction);
return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), double(progress));
} else
return progress;
}
#ifndef QT_NO_ANIMATION
static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, TransformOperations& transformOperations)
{
transformOperations = TransformOperations();
if (!animationValue)
return;
if (const TransformOperations* ops = static_cast<const TransformAnimationValue*>(animationValue)->value())
transformOperations = *ops;
}
static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, qreal& realValue)
{
realValue = animationValue ? static_cast<const FloatAnimationValue*>(animationValue)->value() : 0;
}
class AnimationQtBase : public QAbstractAnimation {
public:
AnimationQtBase(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
: QAbstractAnimation(0)
, m_layer(layer)
, m_boxSize(boxSize)
, m_duration(anim->duration() * 1000)
, m_isAlternate(anim->direction() == Animation::AnimationDirectionAlternate)
, m_webkitPropertyID(values.property())
, m_webkitAnimation(anim)
, m_keyframesName(name)
, m_fillsForwards(false)
{
}
virtual AnimatedPropertyID animatedProperty() const = 0;
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{
QAbstractAnimation::updateState(newState, oldState);
if (newState == Running && oldState == Stopped && m_layer.data())
m_layer.data()->notifyAnimationStartedAsync();
}
virtual int duration() const { return m_duration; }
QWeakPointer<GraphicsLayerQtImpl> m_layer;
IntSize m_boxSize;
int m_duration;
bool m_isAlternate;
AnimatedPropertyID m_webkitPropertyID;
const Animation* m_webkitAnimation;
QString m_keyframesName;
bool m_fillsForwards;
};
template <typename T>
class AnimationQt : public AnimationQtBase {
public:
AnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
: AnimationQtBase(layer, values, boxSize, anim, name)
{
for (size_t i = 0; i < values.size(); ++i) {
const AnimationValue* animationValue = values.at(i);
KeyframeValueQt<T> keyframeValue;
if (animationValue->timingFunction())
keyframeValue.timingFunction = animationValue->timingFunction();
else
keyframeValue.timingFunction = anim->timingFunction().get();
webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value);
m_keyframeValues[animationValue->keyTime()] = keyframeValue;
}
}
protected:
virtual void applyFrame(const T& fromValue, const T& toValue, qreal progress) = 0;
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{
#if QT_DEBUG_FPS
if (newState == Running && oldState == Stopped) {
qDebug("Animation Started!");
m_fps.frames = 0;
m_fps.duration.start();
} else if (newState == Stopped && oldState == Running) {
const int duration = m_fps.duration.elapsed();
qDebug("Animation Ended! %dms [%f FPS]", duration,
(1000 / (((float)duration) / m_fps.frames)));
}
#endif
AnimationQtBase::updateState(newState, oldState);
}
virtual void updateCurrentTime(int currentTime)
{
if (!m_layer)
return;
qreal progress = qreal(currentLoopTime()) / duration();
if (m_isAlternate && currentLoop()%2)
progress = 1-progress;
if (m_keyframeValues.isEmpty())
return;
typename QMap<qreal, KeyframeValueQt<T> >::iterator it = m_keyframeValues.find(progress);
if (it == m_keyframeValues.end())
it = m_keyframeValues.lowerBound(progress)-1;
if (it == m_keyframeValues.end())
it = m_keyframeValues.begin();
typename QMap<qreal, KeyframeValueQt<T> >::iterator it2 = it + 1;
if (it2 == m_keyframeValues.end())
it2 = it;
const KeyframeValueQt<T>& fromKeyframe = it.value();
const KeyframeValueQt<T>& toKeyframe = it2.value();
const TimingFunction* timingFunc = fromKeyframe.timingFunction;
const T& fromValue = fromKeyframe.value;
const T& toValue = toKeyframe.value;
progress = (!progress || progress == 1 || it.key() == it2.key()) ?
progress : applyTimingFunction(timingFunc, (progress - it.key()) / (it2.key() - it.key()), duration());
applyFrame(fromValue, toValue, progress);
#if QT_DEBUG_FPS
++m_fps.frames;
#endif
}
QMap<qreal, KeyframeValueQt<T> > m_keyframeValues;
#if QT_DEBUG_FPS
struct {
QTime duration;
int frames;
} m_fps;
#endif
};
class TransformAnimationQt : public AnimationQt<TransformOperations> {
public:
TransformAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
: AnimationQt<TransformOperations>(layer, values, boxSize, anim, name)
{
}
~TransformAnimationQt()
{
if (m_fillsForwards)
setCurrentTime(1);
}
virtual AnimatedPropertyID animatedProperty() const { return AnimatedPropertyWebkitTransform; }
virtual void applyFrame(const TransformOperations& sourceOperations, const TransformOperations& targetOperations, qreal progress)
{
TransformationMatrix transformMatrix;
bool validTransformLists = true;
const int sourceOperationCount = sourceOperations.size();
if (sourceOperationCount) {
if (targetOperations.size() != sourceOperationCount)
validTransformLists = false;
else {
for (size_t j = 0; j < sourceOperationCount && validTransformLists; ++j) {
if (!sourceOperations.operations()[j]->isSameType(*targetOperations.operations()[j]))
validTransformLists = false;
}
}
}
if (validTransformLists) {
for (size_t i = 0; i < targetOperations.size(); ++i)
targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize);
} else {
targetOperations.apply(m_boxSize, transformMatrix);
transformMatrix.blend(m_sourceMatrix, progress);
}
m_layer.data()->m_layer->setTransform(transformMatrix);
m_layer.data()->setBaseTransform(transformMatrix);
}
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{
AnimationQt<TransformOperations>::updateState(newState, oldState);
if (!m_layer)
return;
m_layer.data()->flushChanges(true);
if (newState == QAbstractAnimation::Running) {
m_sourceMatrix = m_layer.data()->m_layer->transform();
m_layer.data()->m_transformAnimationRunning = true;
} else if (newState == QAbstractAnimation::Stopped) {
m_layer.data()->m_transformAnimationRunning = false;
if (m_layer && m_layer.data()->m_layer)
m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
}
}
TransformationMatrix m_sourceMatrix;
};
class OpacityAnimationQt : public AnimationQt<qreal> {
public:
OpacityAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString& name)
: AnimationQt<qreal>(layer, values, boxSize, anim, name)
{
}
~OpacityAnimationQt()
{
if (m_fillsForwards)
setCurrentTime(1);
}
virtual AnimatedPropertyID animatedProperty() const { return AnimatedPropertyOpacity; }
virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress)
{
qreal opacity = qBound(qreal(0), fromValue + (toValue - fromValue) * progress, qreal(1));
if (m_layer.data()->scene() && !m_layer.data()->opacity() && opacity)
m_layer.data()->scene()->update();
m_layer.data()->m_layer->setOpacity(opacity);
m_layer.data()->setOpacity(opacity);
}
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{
AnimationQt<qreal>::updateState(newState, oldState);
if (m_layer)
m_layer.data()->m_opacityAnimationRunning = (newState == QAbstractAnimation::Running);
if (newState == Stopped)
if (m_layer && m_layer.data()->m_layer)
m_layer.data()->setOpacity(m_layer.data()->m_layer->opacity());
}
};
bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset)
{
if (!anim->duration() || !anim->iterationCount())
return false;
AnimationQtBase* newAnim = 0;
QList<QWeakPointer<QAbstractAnimation> >::iterator it;
for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
if (*it) {
AnimationQtBase* curAnimation = static_cast<AnimationQtBase*>(it->data());
if (curAnimation && curAnimation->m_webkitAnimation == anim
&& values.property() == curAnimation->animatedProperty()) {
newAnim = curAnimation;
break;
}
}
}
if (!newAnim) {
switch (values.property()) {
case AnimatedPropertyOpacity:
newAnim = new OpacityAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
break;
case AnimatedPropertyWebkitTransform:
newAnim = new TransformAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
break;
default:
return false;
}
newAnim->setLoopCount(anim->iterationCount());
newAnim->m_fillsForwards = anim->fillsForwards();
m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim));
QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume()));
}
m_impl->flushChanges(false);
if (anim->fillsBackwards())
newAnim->setCurrentTime(0);
newAnim->start();
newAnim->setCurrentTime(timeOffset * 1000);
return true;
}
void GraphicsLayerQt::removeAnimationsForProperty(AnimatedPropertyID id)
{
QList<QWeakPointer<QAbstractAnimation> >::iterator it;
for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
if (!(*it))
continue;
AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
if (anim && anim->m_webkitPropertyID == id) {
anim->stop();
anim->deleteLater();
it = m_impl->m_animations.erase(it);
--it;
}
}
}
void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name)
{
QList<QWeakPointer<QAbstractAnimation> >::iterator it;
for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
if (!(*it))
continue;
AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
if (anim && anim->m_keyframesName == QString(name)) {
anim->stop();
anim->deleteLater();
it = m_impl->m_animations.erase(it);
--it;
}
}
}
void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset)
{
QList<QWeakPointer<QAbstractAnimation> >::iterator it;
for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
if (!(*it))
continue;
AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
if (anim && anim->m_keyframesName == QString(name)) {
anim->setCurrentTime(timeOffset * 1000);
anim->pause();
}
}
}
void GraphicsLayerQt::suspendAnimations(double time)
{
if (m_impl->m_suspendTimer.isActive()) {
m_impl->m_suspendTimer.stop();
m_impl->m_suspendTimer.start(time * 1000);
} else {
QList<QWeakPointer<QAbstractAnimation> >::iterator it;
for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
if (QAbstractAnimation* anim = it->data())
anim->pause();
}
}
}
void GraphicsLayerQt::resumeAnimations()
{
if (m_impl->m_suspendTimer.isActive()) {
m_impl->m_suspendTimer.stop();
QList<QWeakPointer<QAbstractAnimation> >::iterator it;
for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
if (QAbstractAnimation* anim = it->data())
anim->resume();
}
}
}
#endif // QT_NO_ANIMATION
}
#include <GraphicsLayerQt.moc>
#endif // QT_NO_GRAPHICSVIEW