Commit 1fb233f7 authored by eric@webkit.org's avatar eric@webkit.org

2010-02-04 No'am Rosenthal <noam.rosenthal@nokia.com>

        Reviewed by Ariya Hidayat.

        [Qt] Tuning and optimizations to GraphicsLayerQt. Reduce unnecessary
        recaching, remove QTimer::singleShot and QPixmap::scaled, more
        accurate strategy of handling transform operation blends. Rotating a
        bordered-table, for example, now runs at 50FPS instead of 40FPS on Maemo5.

        https://bugs.webkit.org/show_bug.cgi?id=34062

        This is tested by https://bugs.webkit.org/show_bug.cgi?id=34450, fps measurements.

        * platform/graphics/qt/GraphicsLayerQt.cpp:
        (WebCore::GraphicsLayerQtImpl::flushChanges): Fine-tune caching
        (WebCore::TransformAnimationQt::TransformAnimationQt): transform bugs
        (WebCore::OpacityAnimationQt::updateState): style change
2010-02-04  No'am Rosenthal  <noam.rosenthal@nokia.com>

        Reviewed by Ariya Hidayat.

        [Qt] Tuning and optimizations to GraphicsLayerQt. Mainly reduced usage
        of QTimer::singleShot, and moved syncLayers() from paint() to update()
        https://bugs.webkit.org/show_bug.cgi?id=34062

        * Api/qgraphicswebview.cpp:
        (QGraphicsWebViewPrivate::update): Moved the sync operation to update
        (QGraphicsWebView::paint): Moved the sync operation to update

git-svn-id: svn://svn.chromium.org/blink/trunk@54344 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent d17b787d
2010-02-04 No'am Rosenthal <noam.rosenthal@nokia.com>
Reviewed by Ariya Hidayat.
[Qt] Tuning and optimizations to GraphicsLayerQt. Reduce unnecessary
recaching, remove QTimer::singleShot and QPixmap::scaled, more
accurate strategy of handling transform operation blends. Rotating a
bordered-table, for example, now runs at 50FPS instead of 40FPS on Maemo5.
https://bugs.webkit.org/show_bug.cgi?id=34062
This is tested by https://bugs.webkit.org/show_bug.cgi?id=34450, fps measurements.
* platform/graphics/qt/GraphicsLayerQt.cpp:
(WebCore::GraphicsLayerQtImpl::flushChanges): Fine-tune caching
(WebCore::TransformAnimationQt::TransformAnimationQt): transform bugs
(WebCore::OpacityAnimationQt::updateState): style change
2010-02-04 Pavel Feldman <pfeldman@chromium.org> 2010-02-04 Pavel Feldman <pfeldman@chromium.org>
Reviewed by Timothy Hatcher. Reviewed by Timothy Hatcher.
......
...@@ -99,14 +99,26 @@ public: ...@@ -99,14 +99,26 @@ public:
// or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP) // or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
void flushChanges(bool recursive = true); void flushChanges(bool recursive = true);
// optimization: when we have an animation running on an element with no contents, that has child-elements with contents,
// ALL of them have to have ItemCoordinateCache and not DeviceCoordinateCache
void adjustCachingRecursively(bool animationIsRunning);
// optimization: returns true if this or an ancestor has a transform animation running.
// this enables us to use ItemCoordinatesCache while the animation is running, otherwise we have to recache for every frame
bool isTransformAnimationRunning() const;
public slots: public slots:
// we need to notify the client (aka the layer compositor) when the animation actually starts // we need to notify the client (aka the layer compositor) when the animation actually starts
void notifyAnimationStarted(); void notifyAnimationStarted();
signals:
// optimization: we don't want to use QTimer::singleShot
void notifyAnimationStartedAsync();
public: public:
GraphicsLayerQt* m_layer; GraphicsLayerQt* m_layer;
QTransform m_baseTransfom; QTransform m_baseTransform;
bool m_transformAnimationRunning; bool m_transformAnimationRunning;
bool m_opacityAnimationRunning; bool m_opacityAnimationRunning;
...@@ -157,12 +169,14 @@ public: ...@@ -157,12 +169,14 @@ public:
bool backfaceVisibility: 1; bool backfaceVisibility: 1;
bool distributeOpacity: 1; bool distributeOpacity: 1;
bool align: 2; bool align: 2;
State(): maskLayer(0), opacity(1), preserves3D(false), masksToBounds(false), State(): maskLayer(0), opacity(1.f), preserves3D(false), masksToBounds(false),
drawsContent(false), contentsOpaque(false), backfaceVisibility(false), drawsContent(false), contentsOpaque(false), backfaceVisibility(false),
distributeOpacity(false) distributeOpacity(false)
{ {
} }
} m_state; } m_state;
friend class AnimationQtBase;
}; };
GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer) GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
...@@ -171,16 +185,14 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer) ...@@ -171,16 +185,14 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
, m_transformAnimationRunning(false) , m_transformAnimationRunning(false)
, m_changeMask(NoChanges) , m_changeMask(NoChanges)
{ {
// better to calculate the exposed rect in QGraphicsView than over-render in WebCore
// FIXME: test different approaches
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
// we use graphics-view for compositing, not for interactivity // we use graphics-view for compositing, not for interactivity
setAcceptedMouseButtons(Qt::NoButton); setAcceptedMouseButtons(Qt::NoButton);
setEnabled(false); setEnabled(false);
// we'll set the cache when we know what's going on // we'll set the cache when we know what's going on
setCacheMode(NoCache); setCacheMode(NoCache);
connect(this, SIGNAL(notifyAnimationStartedAsync()), this, SLOT(notifyAnimationStarted()), Qt::QueuedConnection);
} }
GraphicsLayerQtImpl::~GraphicsLayerQtImpl() GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
...@@ -203,22 +215,42 @@ GraphicsLayerQtImpl::~GraphicsLayerQtImpl() ...@@ -203,22 +215,42 @@ GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
delete anim; delete anim;
} }
void GraphicsLayerQtImpl::adjustCachingRecursively(bool animationIsRunning)
{
// optimization: we make sure all our children have ItemCoordinateCache -
// otherwise we end up re-rendering them during the animation
const QList<QGraphicsItem*> children = childItems();
for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) {
if (QGraphicsItem* item = *it)
if (GraphicsLayerQtImpl* layer = qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject())) {
if (layer->m_layer->drawsContent() && layer->m_currentContent.contentType == HTMLContentType)
layer->setCacheMode(animationIsRunning ? QGraphicsItem::ItemCoordinateCache : QGraphicsItem::DeviceCoordinateCache);
}
}
}
void GraphicsLayerQtImpl::setBaseTransform(const QTransform& transform) void GraphicsLayerQtImpl::setBaseTransform(const QTransform& transform)
{ {
if (!m_layer) if (!m_layer)
return; return;
// webkit has relative-to-size originPoint, graphics-view has a pixel originPoint // webkit has relative-to-size originPoint, graphics-view has a pixel originPoint, here we convert
// here we convert // we have to manage this ourselves because QGraphicsView's transformOrigin is incompatible
QPointF originTranslate( const qreal x = m_layer->anchorPoint().x() * m_layer->size().width();
m_layer->anchorPoint().x() * m_layer->size().width(), m_layer->anchorPoint().y() * m_layer->size().height()); const qreal y = m_layer->anchorPoint().y() * m_layer->size().height();
setTransform(QTransform::fromTranslate(x, y));
resetTransform();
// we have to manage this ourselves because QGraphicsView's transformOrigin is incomplete
translate(originTranslate.x(), originTranslate.y());
setTransform(transform, true); setTransform(transform, true);
translate(-originTranslate.x(), -originTranslate.y()); translate(-x, -y);
m_baseTransfom = transform; m_baseTransform = transform;
}
bool GraphicsLayerQtImpl::isTransformAnimationRunning() const
{
if (m_transformAnimationRunning)
return true;
if (GraphicsLayerQtImpl* parent = qobject_cast<GraphicsLayerQtImpl*>(parentObject()))
return parent->isTransformAnimationRunning();
return false;
} }
QPainterPath GraphicsLayerQtImpl::opaqueArea() const QPainterPath GraphicsLayerQtImpl::opaqueArea() const
...@@ -270,42 +302,31 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte ...@@ -270,42 +302,31 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte
drawContents(painter, option->exposedRect); drawContents(painter, option->exposedRect);
} }
void GraphicsLayerQtImpl::drawContents(QPainter* painter, const QRectF& r, bool mask) void GraphicsLayerQtImpl::drawContents(QPainter* painter, const QRectF& exposedRect, bool mask)
{ {
QRect rect = r.toAlignedRect();
if (m_currentContent.contentType != HTMLContentType && !m_state.contentsRect.isEmpty())
rect = rect.intersected(m_state.contentsRect);
if (m_currentContent.backgroundColor.isValid()) if (m_currentContent.backgroundColor.isValid())
painter->fillRect(r, QColor(m_currentContent.backgroundColor)); painter->fillRect(exposedRect, QColor(m_currentContent.backgroundColor));
if (!rect.isEmpty()) { switch (m_currentContent.contentType) {
switch (m_currentContent.contentType) { case PixmapContentType:
case PixmapContentType: painter->drawPixmap(m_state.contentsRect, m_currentContent.pixmap);
// we have to scale the image to the contentsRect break;
// FIXME: a better way would probably be drawPixmap with a src/target rect case ColorContentType:
painter->drawPixmap(rect.topLeft(), m_currentContent.pixmap.scaled(m_state.contentsRect.size()), r); painter->fillRect(m_state.contentsRect, m_currentContent.contentsBackgroundColor);
break; break;
case ColorContentType: default:
painter->fillRect(rect, m_currentContent.contentsBackgroundColor); if (m_state.drawsContent) {
break; // this is the "expensive" bit. we try to minimize calls to this neck of the woods by proper caching
default: GraphicsContext gc(painter);
if (m_state.drawsContent) { m_layer->paintGraphicsLayerContents(gc, exposedRect.toAlignedRect());
// this is the "expensive" bit. we try to minimize calls to this
// neck of the woods by proper caching
GraphicsContext gc(painter);
m_layer->paintGraphicsLayerContents(gc, rect);
}
break;
} }
break;
} }
} }
void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask) void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
{ {
if (!this) Q_ASSERT(this);
return;
m_changeMask |= changeMask; m_changeMask |= changeMask;
...@@ -342,14 +363,14 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive) ...@@ -342,14 +363,14 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
const QSet<QGraphicsItem*> currentChildren = childItems().toSet(); const QSet<QGraphicsItem*> currentChildren = childItems().toSet();
const QSet<QGraphicsItem*> childrenToAdd = newChildren - currentChildren; const QSet<QGraphicsItem*> childrenToAdd = newChildren - currentChildren;
const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren; const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren;
for (QSet<QGraphicsItem*>::const_iterator it = childrenToAdd.begin(); it != childrenToAdd.end(); ++it) {
for (QSet<QGraphicsItem*>::const_iterator it = childrenToAdd.begin(); it != childrenToAdd.end(); ++it)
if (QGraphicsItem* w = *it) if (QGraphicsItem* w = *it)
w->setParentItem(this); w->setParentItem(this);
}
for (QSet<QGraphicsItem*>::const_iterator it = childrenToRemove.begin(); it != childrenToRemove.end(); ++it) { for (QSet<QGraphicsItem*>::const_iterator it = childrenToRemove.begin(); it != childrenToRemove.end(); ++it)
if (QGraphicsItem* w = *it) if (QGraphicsItem* w = *it)
w->setParentItem(0); w->setParentItem(0);
}
// children are ordered by z-value, let graphics-view know. // children are ordered by z-value, let graphics-view know.
for (size_t i = 0; i < newChildrenVector.size(); ++i) for (size_t i = 0; i < newChildrenVector.size(); ++i)
...@@ -383,17 +404,17 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive) ...@@ -383,17 +404,17 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
// the anchor-point, transform and size from WebCore all affect the one // the anchor-point, transform and size from WebCore all affect the one
// that we give Qt // that we give Qt
if (m_state.transform != m_layer->transform() || m_state.anchorPoint != m_layer->anchorPoint() || m_state.size != m_layer->size()) if (m_state.transform != m_layer->transform() || m_state.anchorPoint != m_layer->anchorPoint() || m_state.size != m_layer->size())
setBaseTransform(QTransform(m_layer->transform())); setBaseTransform(m_layer->transform());
} }
if (m_changeMask & (ContentChange | DrawsContentChange)) { if (m_changeMask & (ContentChange | DrawsContentChange)) {
switch (m_pendingContent.contentType) { switch (m_pendingContent.contentType) {
case PixmapContentType: case PixmapContentType:
// we need cache even for images, because they need to be resized
// to the contents rect. maybe this can be optimized though
setCacheMode(m_transformAnimationRunning ? ItemCoordinateCache : DeviceCoordinateCache);
update(); update();
setFlag(ItemHasNoContents, false); setFlag(ItemHasNoContents, false);
// we only use ItemUsesExtendedStyleOption for HTML content - pixmap can be handled better with regular clipping
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
break; break;
case ColorContentType: case ColorContentType:
...@@ -403,6 +424,9 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive) ...@@ -403,6 +424,9 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
update(); update();
m_state.drawsContent = false; m_state.drawsContent = false;
setFlag(ItemHasNoContents, false); setFlag(ItemHasNoContents, false);
// we only use ItemUsesExtendedStyleOption for HTML content - colors don't gain much from that anyway
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
break; break;
case HTMLContentType: case HTMLContentType:
...@@ -410,8 +434,16 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive) ...@@ -410,8 +434,16 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
update(); update();
if (!m_state.drawsContent && m_layer->drawsContent()) if (!m_state.drawsContent && m_layer->drawsContent())
update(); update();
if (m_layer->drawsContent()) if (m_layer->drawsContent()) {
setCacheMode(m_transformAnimationRunning ? ItemCoordinateCache : DeviceCoordinateCache); const QGraphicsItem::CacheMode mewCacheMode = isTransformAnimationRunning() ? ItemCoordinateCache : DeviceCoordinateCache;
// optimization: QGraphicsItem doesn't always perform this test
if (mewCacheMode != cacheMode())
setCacheMode(mewCacheMode);
// HTML content: we want to use exposedRect so we don't use WebCore rendering if we don't have to
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
}
else else
setCacheMode(NoCache); setCacheMode(NoCache);
...@@ -448,7 +480,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive) ...@@ -448,7 +480,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
update(); update();
// FIXME: the following flags are currently not handled, as they don't have a clear test or are in low priority // FIXME: the following flags are currently not handled, as they don't have a clear test or are in low priority
// GeometryOrientationChange, ContentsOrientationChange, BackfaceVisibilityChange, ChildrenTransformChange // GeometryOrientationChange, ContentsOrientationChange, BackfaceVisibilityChange, ChildrenTransformChange, Preserves3DChange
m_state.maskLayer = m_layer->maskLayer(); m_state.maskLayer = m_layer->maskLayer();
m_state.pos = m_layer->position(); m_state.pos = m_layer->position();
...@@ -523,9 +555,9 @@ void GraphicsLayerQt::setNeedsDisplay() ...@@ -523,9 +555,9 @@ void GraphicsLayerQt::setNeedsDisplay()
} }
// reimp from GraphicsLayer.h // reimp from GraphicsLayer.h
void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& r) void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& rect)
{ {
m_impl->m_pendingContent.regionToUpdate|= QRectF(r).toAlignedRect(); m_impl->m_pendingContent.regionToUpdate|= QRectF(rect).toAlignedRect();
m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange); m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
} }
...@@ -807,16 +839,16 @@ static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, q ...@@ -807,16 +839,16 @@ static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, q
// Using easing-curves would probably work for some of the cases, but wouldn't really buy us anything as we'd have to convert the bezier function back to an easing curve // Using easing-curves would probably work for some of the cases, but wouldn't really buy us anything as we'd have to convert the bezier function back to an easing curve
static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, int duration) static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, int duration)
{ {
if (timingFunction.type() == LinearTimingFunction) if (timingFunction.type() == LinearTimingFunction)
return progress;
if (timingFunction.type() == CubicBezierTimingFunction) {
return solveCubicBezierFunction(timingFunction.x1(),
timingFunction.y1(),
timingFunction.x2(),
timingFunction.y2(),
double(progress), double(duration) / 1000);
}
return progress; return progress;
if (timingFunction.type() == CubicBezierTimingFunction) {
return solveCubicBezierFunction(timingFunction.x1(),
timingFunction.y1(),
timingFunction.x2(),
timingFunction.y2(),
double(progress), double(duration) / 1000);
}
return progress;
} }
// helper functions to safely get a value out of WebCore's AnimationValue* // helper functions to safely get a value out of WebCore's AnimationValue*
...@@ -826,9 +858,7 @@ static void webkitAnimationToQtAnimationValue(const AnimationValue* animationVal ...@@ -826,9 +858,7 @@ static void webkitAnimationToQtAnimationValue(const AnimationValue* animationVal
if (!animationValue) if (!animationValue)
return; return;
const TransformOperations* ops = static_cast<const TransformAnimationValue*>(animationValue)->value(); if (const TransformOperations* ops = static_cast<const TransformAnimationValue*>(animationValue)->value())
if (ops)
transformOperations = *ops; transformOperations = *ops;
} }
...@@ -856,8 +886,8 @@ public: ...@@ -856,8 +886,8 @@ public:
QAbstractAnimation::updateState(newState, oldState); QAbstractAnimation::updateState(newState, oldState);
// for some reason I have do this asynchronously - or the animation won't work // for some reason I have do this asynchronously - or the animation won't work
if (newState == Running && oldState == Stopped) if (newState == Running && oldState == Stopped && m_layer.data())
QTimer::singleShot(0, m_layer.data(), SLOT(notifyAnimationStarted())); m_layer.data()->notifyAnimationStartedAsync();
} }
virtual int duration() const { return m_duration; } virtual int duration() const { return m_duration; }
...@@ -932,9 +962,10 @@ protected: ...@@ -932,9 +962,10 @@ protected:
// now we have a source keyframe, origin keyframe and a timing function // now we have a source keyframe, origin keyframe and a timing function
// we can now process the progress and apply the frame // we can now process the progress and apply the frame
qreal normalizedProgress = (it.key() == it2.key()) ? 0 : (progress - it.key()) / (it2.key() - it.key()); progress = (!progress || progress == 1 || it.key() == it2.key())
normalizedProgress = applyTimingFunction(timingFunc, normalizedProgress, duration() / 1000); ? progress
applyFrame(fromValue, toValue, normalizedProgress); : applyTimingFunction(timingFunc, (progress - it.key()) / (it2.key() - it.key()), duration() / 1000);
applyFrame(fromValue, toValue, progress);
} }
QMap<qreal, KeyframeValueQt<T> > m_keyframeValues; QMap<qreal, KeyframeValueQt<T> > m_keyframeValues;
...@@ -943,7 +974,7 @@ protected: ...@@ -943,7 +974,7 @@ protected:
class TransformAnimationQt : public AnimationQt<TransformOperations> { class TransformAnimationQt : public AnimationQt<TransformOperations> {
public: public:
TransformAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name) TransformAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
: AnimationQt<TransformOperations>(layer, values, boxSize, anim, name) : AnimationQt<TransformOperations>(layer, values, boxSize, anim, name)
{ {
} }
...@@ -952,7 +983,7 @@ public: ...@@ -952,7 +983,7 @@ public:
// this came up during the compositing/animation LayoutTests // this came up during the compositing/animation LayoutTests
// when the animation dies, the transform has to go back to default // when the animation dies, the transform has to go back to default
if (m_layer) if (m_layer)
m_layer.data()->setBaseTransform(QTransform(m_layer.data()->m_layer->transform())); m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
} }
// the idea is that we let WebCore manage the transform-operations // the idea is that we let WebCore manage the transform-operations
...@@ -963,11 +994,22 @@ public: ...@@ -963,11 +994,22 @@ public:
{ {
TransformationMatrix transformMatrix; TransformationMatrix transformMatrix;
// this looks simple but is really tricky to get right. Use caution. // sometimes the animation values from WebCore are misleading and we have to use the actual matrix as source
for (size_t i = 0; i < targetOperations.size(); ++i) // The Mac implementation simply doesn't try to accelerate those (e.g. 360deg rotation), but we do.
targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize); if (progress == 1 || !targetOperations.size() || sourceOperations == targetOperations) {
TransformationMatrix sourceMatrix;
m_layer.data()->setBaseTransform(QTransform(transformMatrix)); sourceOperations.apply(m_boxSize, sourceMatrix);
transformMatrix = m_sourceMatrix;
transformMatrix.blend(sourceMatrix, 1 - progress);
} else if (targetOperations.size() != sourceOperations.size()) {
transformMatrix = m_sourceMatrix;
targetOperations.apply(m_boxSize, transformMatrix);
transformMatrix.blend(m_sourceMatrix, progress);
} else {
for (size_t i = 0; i < targetOperations.size(); ++i)
targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize);
}
m_layer.data()->setBaseTransform(transformMatrix);
} }
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
...@@ -980,15 +1022,16 @@ public: ...@@ -980,15 +1022,16 @@ public:
// to increase FPS, we use a less accurate caching mechanism while animation is going on // to increase FPS, we use a less accurate caching mechanism while animation is going on
// this is a UX choice that should probably be customizable // this is a UX choice that should probably be customizable
if (newState == QAbstractAnimation::Running) { if (newState == QAbstractAnimation::Running) {
m_sourceMatrix = m_layer.data()->m_layer->transform();
m_layer.data()->m_transformAnimationRunning = true; m_layer.data()->m_transformAnimationRunning = true;
if (m_layer.data()->cacheMode() == QGraphicsItem::DeviceCoordinateCache) m_layer.data()->adjustCachingRecursively(true);
m_layer.data()->setCacheMode(QGraphicsItem::ItemCoordinateCache);
} else { } else {
m_layer.data()->m_transformAnimationRunning = false; m_layer.data()->m_transformAnimationRunning = false;
if (m_layer.data()->cacheMode() == QGraphicsItem::ItemCoordinateCache) m_layer.data()->adjustCachingRecursively(false);
m_layer.data()->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
} }
} }
TransformationMatrix m_sourceMatrix;
}; };
class OpacityAnimationQt : public AnimationQt<qreal> { class OpacityAnimationQt : public AnimationQt<qreal> {
...@@ -1006,6 +1049,7 @@ public: ...@@ -1006,6 +1049,7 @@ public:
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{ {
QAbstractAnimation::updateState(newState, oldState); QAbstractAnimation::updateState(newState, oldState);
if (m_layer) if (m_layer)
m_layer.data()->m_opacityAnimationRunning = (newState == QAbstractAnimation::Running); m_layer.data()->m_opacityAnimationRunning = (newState == QAbstractAnimation::Running);
} }
...@@ -1079,11 +1123,12 @@ void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name) ...@@ -1079,11 +1123,12 @@ void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name)
void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset) void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset)
{ {
for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) { for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
if (*it) { if (!(*it))
AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data()); continue;
if (anim && anim->m_keyframesName == QString(name))
QTimer::singleShot(timeOffset * 1000, anim, SLOT(pause())); AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data());
} if (anim && anim->m_keyframesName == QString(name))
QTimer::singleShot(timeOffset * 1000, anim, SLOT(pause()));
} }
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "qwebpage_p.h" #include "qwebpage_p.h"
#include "QWebPageClient.h" #include "QWebPageClient.h"
#include <FrameView.h> #include <FrameView.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qsharedpointer.h> #include <QtCore/qsharedpointer.h>
#include <QtCore/qtimer.h> #include <QtCore/qtimer.h>
#include <QtGui/qapplication.h> #include <QtGui/qapplication.h>
...@@ -78,13 +79,14 @@ public: ...@@ -78,13 +79,14 @@ public:
, page(0) , page(0)
#if USE(ACCELERATED_COMPOSITING) #if USE(ACCELERATED_COMPOSITING)
, rootGraphicsLayer(0) , rootGraphicsLayer(0)
, shouldSync(true) , shouldSync(false)
#endif #endif
{ {
#if USE(ACCELERATED_COMPOSITING) #if USE(ACCELERATED_COMPOSITING)
// the overlay and stays alive for the lifetime of // the overlay and stays alive for the lifetime of
// this QGraphicsWebView as the scrollbars are needed when there's no compositing // this QGraphicsWebView as the scrollbars are needed when there's no compositing
q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
syncMetaMethod = q->metaObject()->method(q->metaObject()->indexOfMethod("syncLayers()"));
#endif #endif
} }
...@@ -131,6 +133,9 @@ public: ...@@ -131,6 +133,9 @@ public:
// compositor telling us to do so. We'll get that call from ChromeClientQt // compositor telling us to do so. We'll get that call from ChromeClientQt
bool shouldSync; bool shouldSync;
// we have to flush quite often, so we use a meta-method instead of QTimer::singleShot for putting the event in the queue
QMetaMethod syncMetaMethod;
// we need to put the root graphics layer behind the overlay (which contains the scrollbar) // we need to put the root graphics layer behind the overlay (which contains the scrollbar)
enum { RootGraphicsLayerZValue, OverlayZValue }; enum { RootGraphicsLayerZValue, OverlayZValue };
#endif #endif
...@@ -178,7 +183,7 @@ void QGraphicsWebViewPrivate::markForSync(bool scheduleSync) ...@@ -178,7 +183,7 @@ void QGraphicsWebViewPrivate::markForSync(bool scheduleSync)
{ {
shouldSync = true; shouldSync = true;
if (scheduleSync) if (scheduleSync)
QTimer::singleShot(0, q, SLOT(syncLayers())); syncMetaMethod.invoke(q, Qt::QueuedConnection);
} }
void QGraphicsWebViewPrivate::updateCompositingScrollPosition() void QGraphicsWebViewPrivate::updateCompositingScrollPosition()
...@@ -224,6 +229,7 @@ void QGraphicsWebViewPrivate::update(const QRect & dirtyRect) ...@@ -224,6 +229,7 @@ void QGraphicsWebViewPrivate::update(const QRect & dirtyRect)
#if USE(ACCELERATED_COMPOSITING) #if USE(ACCELERATED_COMPOSITING)
if (overlay) if (overlay)
overlay->update(QRectF(dirtyRect)); overlay->update(QRectF(dirtyRect));
syncLayers();
#endif #endif
} }
...@@ -442,7 +448,6 @@ void QGraphicsWebView::paint(QPainter* painter, const QStyleOptionGraphicsItem* ...@@ -442,7 +448,6 @@ void QGraphicsWebView::paint(QPainter* painter, const QStyleOptionGraphicsItem*
{ {
#if USE(ACCELERATED_COMPOSITING) #if USE(ACCELERATED_COMPOSITING)
page()->mainFrame()->render(painter, d->overlay ? QWebFrame::ContentsLayer : QWebFrame::AllLayers, option->exposedRect.toAlignedRect()); page()->mainFrame()->render(painter, d->overlay ? QWebFrame::ContentsLayer : QWebFrame::AllLayers, option->exposedRect.toAlignedRect());
d->syncLayers();
#else #else
page()->mainFrame()->render(painter, QWebFrame::AllLayers, option->exposedRect.toRect()); page()->mainFrame()->render(painter, QWebFrame::AllLayers, option->exposedRect.toRect());
#endif #endif
......
2010-02-04 No'am Rosenthal <noam.rosenthal@nokia.com>
Reviewed by Ariya Hidayat.
[Qt] Tuning and optimizations to GraphicsLayerQt. Mainly reduced usage
of QTimer::singleShot, and moved syncLayers() from paint() to update()
https://bugs.webkit.org/show_bug.cgi?id=34062
* Api/qgraphicswebview.cpp:
(QGraphicsWebViewPrivate::update): Moved the sync operation to update
(QGraphicsWebView::paint): Moved the sync operation to update
2010-02-03 Andras Becsi <abecsi@webkit.org> 2010-02-03 Andras Becsi <abecsi@webkit.org>
Unreviewed build fix. Unreviewed build fix.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment