[Qt] Implement GraphicsLayer for accelerated layer compositing
authorhausmann@webkit.org <hausmann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Jan 2010 09:49:02 +0000 (09:49 +0000)
committerhausmann@webkit.org <hausmann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Jan 2010 09:49:02 +0000 (09:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=33514

Patch by No'am Rosenthal <noam.rosenthal@nokia.com> on 2010-01-21
Reviewed by Antti Koivisto.

.:

* WebKit.pri: Addded compile flags to enable accelerated compositing
on versions higher than 4.5

WebCore:

No new tests: tests in LayoutTests/compositing are now relevant for
QtWebkit!

* WebCore.pro: added accelerated-compositing related files
* platform/graphics/GraphicsLayer.h: define Qt-specific implementation           of GraphicsLayer
* platform/graphics/qt/GraphicsLayerQt.cpp: Added.
(WebCore::GraphicsLayerQtImpl::): Implementation of GraphicsLayer with
a QGraphicsItem
(WebCore::GraphicsLayerQtImpl::ContentData::ContentData): save
pixmap/color info for directly composited content
(WebCore::GraphicsLayerQtImpl::State::State): save info for syncing
(WebCore::GraphicsLayerQtImpl::GraphicsLayerQtImpl): ctor
(WebCore::GraphicsLayerQtImpl::~GraphicsLayerQtImpl): dtor
(WebCore::GraphicsLayerQtImpl::setBaseTransform): set Qt
transformation in the way WebCore wants it
(WebCore::GraphicsLayerQtImpl::opaqueArea): calculate opaque area
based on info we have
(WebCore::GraphicsLayerQtImpl::boundingRect): reimp QGraphicsItem
(WebCore::GraphicsLayerQtImpl::paint): reimp QGraphicsItem
(WebCore::GraphicsLayerQtImpl::drawContents): draw HTML/Pixmap/Color
(WebCore::GraphicsLayerQtImpl::notifyChange): let WebCore know
something has changed
(WebCore::GraphicsLayerQtImpl::flushChanges): Make the changes appear
on screen by setting them to QGraphicsItems
(WebCore::GraphicsLayerQtImpl::notifyAnimationStarted): let WebCore
know the QAnimation started
(WebCore::GraphicsLayerQt::GraphicsLayerQt): ctor
(WebCore::GraphicsLayerQt::~GraphicsLayerQt): dtor
(WebCore::GraphicsLayer::create): hook for WebCore to know we're
implementing compositing
(WebCore::GraphicsLayer::compositingCoordinatesOrientation): hook for
WebCore to know we use a top-down system
(WebCore::GraphicsLayerQt::setNeedsDisplay): update the display
(WebCore::GraphicsLayerQt::setNeedsDisplayInRect): udpate part of the
display
(WebCore::GraphicsLayerQt::setName): reimp
(WebCore::GraphicsLayerQt::setParent): reimp
(WebCore::GraphicsLayerQt::setChildren): reimp
(WebCore::GraphicsLayerQt::addChild): reimp
(WebCore::GraphicsLayerQt::addChildAtIndex): reimp
(WebCore::GraphicsLayerQt::addChildAbove): reimp
(WebCore::GraphicsLayerQt::addChildBelow): reimp
(WebCore::GraphicsLayerQt::replaceChild): reimp
(WebCore::GraphicsLayerQt::removeFromParent): reimp
(WebCore::GraphicsLayerQt::setMaskLayer): reimp
(WebCore::GraphicsLayerQt::setPosition): reimp
(WebCore::GraphicsLayerQt::setAnchorPoint): reimp
(WebCore::GraphicsLayerQt::setSize): reimp
(WebCore::GraphicsLayerQt::setTransform): reimp
(WebCore::GraphicsLayerQt::setChildrenTransform): reimp
(WebCore::GraphicsLayerQt::setPreserves3D): reimp
(WebCore::GraphicsLayerQt::setMasksToBounds): reimp
(WebCore::GraphicsLayerQt::setDrawsContent): reimp
(WebCore::GraphicsLayerQt::setBackgroundColor): reimp
(WebCore::GraphicsLayerQt::clearBackgroundColor): reimp
(WebCore::GraphicsLayerQt::setContentsOpaque): reimp
(WebCore::GraphicsLayerQt::setBackfaceVisibility): reimp
(WebCore::GraphicsLayerQt::setOpacity): reimp
(WebCore::GraphicsLayerQt::setContentsRect): reimp
(WebCore::GraphicsLayerQt::setContentsToImage): reimp
(WebCore::GraphicsLayerQt::setContentsBackgroundColor): reimp
(WebCore::GraphicsLayerQt::setGeometryOrientation): reimp
(WebCore::GraphicsLayerQt::setContentsOrientation): reimp
(WebCore::GraphicsLayerQt::distributeOpacity): reimp
(WebCore::GraphicsLayerQt::accumulatedOpacity): reimp
(WebCore::GraphicsLayerQt::syncCompositingState): reimp
(WebCore::GraphicsLayerQt::nativeLayer): reimp (QGraphicsItem*)
(WebCore::GraphicsLayerQt::platformLayer): reimp (QGraphicsItem*)
(WebCore::solveEpsilon): copy from AnimationBase.cpp
(WebCore::solveCubicBezierFunction): copy from AniamtionBase.cpp
(WebCore::applyTimingFunction): use WebCore's timing and not Qt's
(WebCore::webkitAnimationToQtAnimationValue): safely figure out
animation values
(WebCore::AnimationQtBase::AnimationQtBase): base class for Qt-based
Webcore-initiated animations
(WebCore::AnimationQtBase::updateState): notify when an animation
starts
(WebCore::AnimationQtBase::duration): reimp QAbstractAnimation
(WebCore::AnimationQt:::AnimationQtBase):
(WebCore::AnimationQt::updateCurrentTime): realize keyframes from
progress
(WebCore::TransformAnimationQt::TransformAnimationQt): ctor
(WebCore::TransformAnimationQt::~TransformAnimationQt): dtor
(WebCore::TransformAnimationQt::applyFrame): set the actual QTransform
based on WebCore TransformOperations
(WebCore::TransformAnimationQt::updateState): change cache mode
(WebCore::OpacityAnimationQt::OpacityAnimationQt):
(WebCore::OpacityAnimationQt::applyFrame): change item's opacity
(WebCore::OpacityAnimationQt::updateState):
(WebCore::GraphicsLayerQt::addAnimation): convert WebCore Animation to
Qt Animation
(WebCore::GraphicsLayerQt::removeAnimationsForProperty):
(WebCore::GraphicsLayerQt::removeAnimationsForKeyframes):
(WebCore::GraphicsLayerQt::pauseAnimation):
(WebCore::GraphicsLayerQt::suspendAnimations):
(WebCore::GraphicsLayerQt::resumeAnimations):
* platform/graphics/qt/GraphicsLayerQt.h: Added.
* platform/qt/QWebPageClient.h: virtual functions for QGraphicsWebView
compositing
(QWebPageClient::setRootGraphicsLayer): let QGraphicsWebView know that
compositing has started/ended
(QWebPageClient::markForSync): let QGraphicsWebView know the
compositing layers need to sync, either soon or with the next update

WebKit/qt:

Here we have the QGraphicsWebView support for accelerated compositing

* Api/qgraphicswebview.cpp:
(QGraphicsWebViewOverlay::q): access to container object
(QGraphicsWebViewOverlay::boundingRect): overlay has same rect as the
webview
(QGraphicsWebViewOverlay::paint): paint everything but the contents
(QGraphicsWebViewPrivate::QGraphicsWebViewPrivate): some vars needed
for accelerated compositing
(QGraphicsWebViewPrivate::):
(QGraphicsWebViewPrivate::~QGraphicsWebViewPrivate):
(QGraphicsWebViewPrivate::setRootGraphicsLayer): make sure we have a
scrollbar overlay, and that the new graphics layer is parented by the
web-view
(QGraphicsWebViewPrivate::markForSync): flush changes at earliest
convenience or during the next draw

(QGraphicsWebViewPrivate::updateCompositingScrollPosition): sync the
position of the compositing layer with the scroll position
(QGraphicsWebViewPrivate::syncLayers): flush changes now
(QGraphicsWebViewPrivate::scroll): make sure we also move the
compositing layer
(QGraphicsWebViewPrivate::update): also update the overlay if needed
(QGraphicsWebView::QGraphicsWebView): initialize overlay with 0
(QGraphicsWebView::paint): paint only contents if we have an overlay,
sync the compositing layers now if needed
(QGraphicsWebView::setPage): also clean up the compositing
(QGraphicsWebView::updateGeometry): also update overlay geo
(QGraphicsWebView::setGeometry): also update overlay geo
* Api/qgraphicswebview.h: reimp compositing stuff from QWebPageClient
* Api/qwebsettings.cpp: init new settings flag for compositing as
false
(QWebSettingsPrivate::apply): apply new settings flag for compositing
(QWebSettings::QWebSettings):
* Api/qwebsettings.h: new settings flag for compositing
* Api/qwebview.cpp:
(QWebView::setPage): qwebview doesn't support compositing: always false
* QGVLauncher/main.cpp:
(WebView::WebView): some more cmdline arguments + compositing
(MainWindow::init): some more cmdline arguments
(main): ditto
* WebCoreSupport/ChromeClientQt.cpp:
(WebCore::ChromeClientQt::attachRootGraphicsLayer): reimp for
accel-compositing
(WebCore::ChromeClientQt::setNeedsOneShotDrawingSynchronization):
reimp for accel compositing
(WebCore::ChromeClientQt::scheduleCompositingLayerSync): reimp for
accel compositing
* WebCoreSupport/ChromeClientQt.h: reimps for accel compositing

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@53618 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
ChangeLog
WebCore/ChangeLog
WebCore/WebCore.pro
WebCore/platform/graphics/GraphicsLayer.h
WebCore/platform/graphics/qt/GraphicsLayerQt.cpp [new file with mode: 0644]
WebCore/platform/graphics/qt/GraphicsLayerQt.h [new file with mode: 0644]
WebCore/platform/qt/QWebPageClient.h
WebKit.pri
WebKit/qt/Api/qgraphicswebview.cpp
WebKit/qt/Api/qgraphicswebview.h
WebKit/qt/Api/qwebsettings.cpp
WebKit/qt/Api/qwebsettings.h
WebKit/qt/Api/qwebview.cpp
WebKit/qt/ChangeLog
WebKit/qt/QGVLauncher/main.cpp
WebKit/qt/WebCoreSupport/ChromeClientQt.cpp
WebKit/qt/WebCoreSupport/ChromeClientQt.h

index 6b0e084..fdefebe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2010-01-21  No'am Rosenthal  <noam.rosenthal@nokia.com>
+
+        Reviewed by Antti Koivisto.
+
+        [Qt] Implement GraphicsLayer for accelerated layer compositing
+        https://bugs.webkit.org/show_bug.cgi?id=33514
+
+        * WebKit.pri: Addded compile flags to enable accelerated compositing
+        on versions higher than 4.5
+
 2010-01-20  Tor Arne Vestbø  <tor.arne.vestbo@nokia.com>
 
         Reviewed by Simon Hausmann.
index 9e94f0f..2eca751 100644 (file)
 
 2010-01-21  No'am Rosenthal  <noam.rosenthal@nokia.com>
 
+        Reviewed by Antti Koivisto.
+
+        [Qt] Implement GraphicsLayer for accelerated layer compositing
+        https://bugs.webkit.org/show_bug.cgi?id=33514
+
+        No new tests: tests in LayoutTests/compositing are now relevant for
+        QtWebkit!
+
+        * WebCore.pro: added accelerated-compositing related files 
+        * platform/graphics/GraphicsLayer.h: define Qt-specific implementation           of GraphicsLayer
+        * platform/graphics/qt/GraphicsLayerQt.cpp: Added.
+        (WebCore::GraphicsLayerQtImpl::): Implementation of GraphicsLayer with
+        a QGraphicsItem
+        (WebCore::GraphicsLayerQtImpl::ContentData::ContentData): save 
+        pixmap/color info for directly composited content
+        (WebCore::GraphicsLayerQtImpl::State::State): save info for syncing
+        (WebCore::GraphicsLayerQtImpl::GraphicsLayerQtImpl): ctor
+        (WebCore::GraphicsLayerQtImpl::~GraphicsLayerQtImpl): dtor
+        (WebCore::GraphicsLayerQtImpl::setBaseTransform): set Qt
+        transformation in the way WebCore wants it
+        (WebCore::GraphicsLayerQtImpl::opaqueArea): calculate opaque area
+        based on info we have
+        (WebCore::GraphicsLayerQtImpl::boundingRect): reimp QGraphicsItem
+        (WebCore::GraphicsLayerQtImpl::paint): reimp QGraphicsItem
+        (WebCore::GraphicsLayerQtImpl::drawContents): draw HTML/Pixmap/Color
+        (WebCore::GraphicsLayerQtImpl::notifyChange): let WebCore know
+        something has changed
+        (WebCore::GraphicsLayerQtImpl::flushChanges): Make the changes appear
+        on screen by setting them to QGraphicsItems
+        (WebCore::GraphicsLayerQtImpl::notifyAnimationStarted): let WebCore
+        know the QAnimation started
+        (WebCore::GraphicsLayerQt::GraphicsLayerQt): ctor
+        (WebCore::GraphicsLayerQt::~GraphicsLayerQt): dtor
+        (WebCore::GraphicsLayer::create): hook for WebCore to know we're
+        implementing compositing
+        (WebCore::GraphicsLayer::compositingCoordinatesOrientation): hook for
+        WebCore to know we use a top-down system
+        (WebCore::GraphicsLayerQt::setNeedsDisplay): update the display
+        (WebCore::GraphicsLayerQt::setNeedsDisplayInRect): udpate part of the
+        display
+        (WebCore::GraphicsLayerQt::setName): reimp
+        (WebCore::GraphicsLayerQt::setParent): reimp
+        (WebCore::GraphicsLayerQt::setChildren): reimp
+        (WebCore::GraphicsLayerQt::addChild): reimp
+        (WebCore::GraphicsLayerQt::addChildAtIndex): reimp
+        (WebCore::GraphicsLayerQt::addChildAbove): reimp
+        (WebCore::GraphicsLayerQt::addChildBelow): reimp
+        (WebCore::GraphicsLayerQt::replaceChild): reimp
+        (WebCore::GraphicsLayerQt::removeFromParent): reimp
+        (WebCore::GraphicsLayerQt::setMaskLayer): reimp
+        (WebCore::GraphicsLayerQt::setPosition): reimp
+        (WebCore::GraphicsLayerQt::setAnchorPoint): reimp
+        (WebCore::GraphicsLayerQt::setSize): reimp
+        (WebCore::GraphicsLayerQt::setTransform): reimp
+        (WebCore::GraphicsLayerQt::setChildrenTransform): reimp
+        (WebCore::GraphicsLayerQt::setPreserves3D): reimp
+        (WebCore::GraphicsLayerQt::setMasksToBounds): reimp
+        (WebCore::GraphicsLayerQt::setDrawsContent): reimp
+        (WebCore::GraphicsLayerQt::setBackgroundColor): reimp
+        (WebCore::GraphicsLayerQt::clearBackgroundColor): reimp
+        (WebCore::GraphicsLayerQt::setContentsOpaque): reimp
+        (WebCore::GraphicsLayerQt::setBackfaceVisibility): reimp
+        (WebCore::GraphicsLayerQt::setOpacity): reimp
+        (WebCore::GraphicsLayerQt::setContentsRect): reimp
+        (WebCore::GraphicsLayerQt::setContentsToImage): reimp
+        (WebCore::GraphicsLayerQt::setContentsBackgroundColor): reimp
+        (WebCore::GraphicsLayerQt::setGeometryOrientation): reimp
+        (WebCore::GraphicsLayerQt::setContentsOrientation): reimp
+        (WebCore::GraphicsLayerQt::distributeOpacity): reimp
+        (WebCore::GraphicsLayerQt::accumulatedOpacity): reimp
+        (WebCore::GraphicsLayerQt::syncCompositingState): reimp
+        (WebCore::GraphicsLayerQt::nativeLayer): reimp (QGraphicsItem*)
+        (WebCore::GraphicsLayerQt::platformLayer): reimp (QGraphicsItem*)
+        (WebCore::solveEpsilon): copy from AnimationBase.cpp
+        (WebCore::solveCubicBezierFunction): copy from AniamtionBase.cpp
+        (WebCore::applyTimingFunction): use WebCore's timing and not Qt's
+        (WebCore::webkitAnimationToQtAnimationValue): safely figure out
+        animation values
+        (WebCore::AnimationQtBase::AnimationQtBase): base class for Qt-based
+        Webcore-initiated animations
+        (WebCore::AnimationQtBase::updateState): notify when an animation
+        starts
+        (WebCore::AnimationQtBase::duration): reimp QAbstractAnimation
+        (WebCore::AnimationQt:::AnimationQtBase):
+        (WebCore::AnimationQt::updateCurrentTime): realize keyframes from
+        progress
+        (WebCore::TransformAnimationQt::TransformAnimationQt): ctor
+        (WebCore::TransformAnimationQt::~TransformAnimationQt): dtor
+        (WebCore::TransformAnimationQt::applyFrame): set the actual QTransform
+        based on WebCore TransformOperations
+        (WebCore::TransformAnimationQt::updateState): change cache mode
+        (WebCore::OpacityAnimationQt::OpacityAnimationQt):
+        (WebCore::OpacityAnimationQt::applyFrame): change item's opacity
+        (WebCore::OpacityAnimationQt::updateState):
+        (WebCore::GraphicsLayerQt::addAnimation): convert WebCore Animation to
+        Qt Animation
+        (WebCore::GraphicsLayerQt::removeAnimationsForProperty):
+        (WebCore::GraphicsLayerQt::removeAnimationsForKeyframes):
+        (WebCore::GraphicsLayerQt::pauseAnimation):
+        (WebCore::GraphicsLayerQt::suspendAnimations):
+        (WebCore::GraphicsLayerQt::resumeAnimations):
+        * platform/graphics/qt/GraphicsLayerQt.h: Added.
+        * platform/qt/QWebPageClient.h: virtual functions for QGraphicsWebView
+        compositing
+        (QWebPageClient::setRootGraphicsLayer): let QGraphicsWebView know that
+        compositing has started/ended
+        (QWebPageClient::markForSync): let QGraphicsWebView know the
+        compositing layers need to sync, either soon or with the next update
+
+2010-01-21  No'am Rosenthal  <noam.rosenthal@nokia.com>
+
         Reviewed by Simon Hausmann.
 
         [Qt] Adding QPixmap/QImage support for the Qt hybrid layer
index 15bacde..445059d 100644 (file)
@@ -2722,6 +2722,19 @@ CONFIG(standalone_package):isEqual(QT_MAJOR_VERSION, 4):greaterThan(QT_MINOR_VER
             plugins/win/PaintHooks.asm
     }
 }
+contains(DEFINES, WTF_USE_ACCELERATED_COMPOSITING) {
+HEADERS += \
+    rendering/RenderLayerBacking.h \
+    rendering/RenderLayerCompositor.h \
+    platform/graphics/GraphicsLayer.h \
+    platform/graphics/GraphicsLayerClient.h \
+    platform/graphics/qt/GraphicsLayerQt.h
+SOURCES += \
+    platform/graphics/GraphicsLayer.cpp \
+    platform/graphics/qt/GraphicsLayerQt.cpp \
+    rendering/RenderLayerBacking.cpp \
+    rendering/RenderLayerCompositor.cpp
+}
 
 symbian {
     shared {
index 80e9378..844301e 100644 (file)
@@ -59,6 +59,10 @@ class WKCACFLayer;
 typedef WKCACFLayer PlatformLayer;
 typedef void* NativeLayer;
 }
+#elif PLATFORM(QT)
+class QGraphicsItem;
+typedef QGraphicsItem PlatformLayer;
+typedef QGraphicsItem* NativeLayer;
 #else
 typedef void* PlatformLayer;
 typedef void* NativeLayer;
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
new file mode 100644 (file)
index 0000000..5712eee
--- /dev/null
@@ -0,0 +1,1118 @@
+/*
+    Copyright (C) 2009 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"
+#include "GraphicsLayerQt.h"
+
+#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/qdebug.h>
+#include <QtCore/qset.h>
+#include <QtCore/qtimer.h>
+#include <QtGui/qbitmap.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qgraphicseffect.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qstyleoption.h>
+
+namespace WebCore {
+
+class GraphicsLayerQtImpl : public QGraphicsObject {
+    Q_OBJECT
+
+public:
+    // this set of flags help us defer which properties of the layer have been
+    // modified by the compositor, so we can know what to look for in the next flush
+    enum ChangeMask {
+        NoChanges =                 0,
+        ChildrenChange =            (1L << 1),
+        MaskLayerChange =           (1L << 2),
+        PositionChange =            (1L << 3),
+        AnchorPointChange =         (1L << 4),
+        SizeChange  =               (1L << 5),
+        TransformChange =           (1L << 6),
+        ContentChange =             (1L << 7),
+        GeometryOrientationChange = (1L << 8),
+        ContentsOrientationChange = (1L << 9),
+        OpacityChange =             (1L << 10),
+        ContentsRectChange =        (1L << 11),
+        Preserves3DChange =         (1L << 12),
+        MasksToBoundsChange =       (1L << 13),
+        DrawsContentChange =        (1L << 14),
+        ContentsOpaqueChange =      (1L << 15),
+        BackfaceVisibilityChange =  (1L << 16),
+        ChildrenTransformChange =   (1L << 17),
+        DisplayChange =             (1L << 18),
+        BackgroundColorChange =     (1L << 19),
+        ParentChange =              (1L << 20),
+        DistributesOpacityChange =  (1L << 21)
+    };
+
+    // the compositor lets us special-case images and colors, so we try to do so
+    enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType};
+
+    GraphicsLayerQtImpl(GraphicsLayerQt* newLayer);
+    virtual ~GraphicsLayerQtImpl();
+
+    // reimps from QGraphicsItem
+    virtual QPainterPath opaqueArea() const;
+    virtual QRectF boundingRect() const;
+    virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
+
+    // we manage transforms ourselves because transform-origin acts differently in webkit and in Qt
+    void setBaseTransform(const QTransform&);
+    void drawContents(QPainter*, const QRectF&, bool mask = false);
+
+    // let the compositor-API tell us which properties were changed
+    void notifyChange(ChangeMask);
+
+    // called when the compositor is ready for us to show the changes on screen
+    // this is called indirectly from ChromeClientQt::setNeedsOneShotDrawingSynchronization
+    // (meaning the sync would happen together with the next draw)
+    // or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
+    void flushChanges(bool recursive = true);
+
+public slots:
+    // we need to notify the client (aka the layer compositor) when the animation actually starts
+    void notifyAnimationStarted();
+
+public:
+    GraphicsLayerQt* m_layer;
+
+    QTransform m_baseTransfom;
+    bool m_transformAnimationRunning;
+    bool m_opacityAnimationRunning;
+
+    struct ContentData {
+        QPixmap pixmap;
+        QRegion regionToUpdate;
+        bool updateAll;
+        QColor contentsBackgroundColor;
+        QColor backgroundColor;
+        StaticContentType contentType;
+        float opacity;
+        ContentData()
+                : updateAll(false)
+                , contentType(HTMLContentType)
+                , opacity(1.f)
+        {
+        }
+
+    };
+
+    ContentData m_pendingContent;
+    ContentData m_currentContent;
+
+    int m_changeMask;
+
+    QSizeF m_size;
+    QList<QWeakPointer<QAbstractAnimation> > m_animations;
+    QTimer m_suspendTimer;
+
+    struct State {
+        GraphicsLayer* maskLayer;
+        FloatPoint pos;
+        FloatPoint3D anchorPoint;
+        FloatSize size;
+        TransformationMatrix transform;
+        TransformationMatrix childrenTransform;
+        Color backgroundColor;
+        Color currentColor;
+        GraphicsLayer::CompositingCoordinatesOrientation geoOrientation;
+        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), opacity(1), preserves3D(false), masksToBounds(false),
+                  drawsContent(false), contentsOpaque(false), backfaceVisibility(false),
+                  distributeOpacity(false)
+        {
+        }
+    } m_state;
+};
+
+GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
+    : QGraphicsObject(0)
+    , m_layer(newLayer)
+    , m_transformAnimationRunning(false)
+    , 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
+    setAcceptedMouseButtons(Qt::NoButton);
+    setEnabled(false);
+
+    // we'll set the cache when we know what's going on
+    setCacheMode(NoCache);
+}
+
+GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
+{
+    // the compositor manages item lifecycle - we don't want the graphics-view
+    // system to automatically delete our items
+
+    const QList<QGraphicsItem*> children = childItems();
+    for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) {
+        if (QGraphicsItem* item = *it) {
+            if (scene())
+                scene()->removeItem(item);
+            item->setParentItem(0);
+        }
+    }
+    
+    // we do, however, own the animations...
+    for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_animations.begin(); it != m_animations.end(); ++it)
+        if (QAbstractAnimation* anim = it->data())
+            delete anim;
+}
+
+void GraphicsLayerQtImpl::setBaseTransform(const QTransform& transform)
+{
+    if (!m_layer)
+        return;
+    // webkit has relative-to-size originPoint, graphics-view has a pixel originPoint
+    // here we convert
+    QPointF originTranslate(
+            m_layer->anchorPoint().x() * m_layer->size().width(), m_layer->anchorPoint().y() * m_layer->size().height());
+
+    resetTransform();
+
+    // we have to manage this ourselves because QGraphicsView's transformOrigin is incomplete
+    translate(originTranslate.x(), originTranslate.y());
+    setTransform(transform, true);
+    translate(-originTranslate.x(), -originTranslate.y());
+    m_baseTransfom = transform;
+}
+
+QPainterPath GraphicsLayerQtImpl::opaqueArea() const
+{
+    QPainterPath painterPath;
+    // we try out best to return the opaque area, maybe it will help graphics-view render less items
+    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 == 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 (m_state.maskLayer && m_state.maskLayer->platformLayer()) {
+        // FIXME: see if this is better done somewhere else
+        GraphicsLayerQtImpl* otherMask = static_cast<GraphicsLayerQtImpl*>(m_state.maskLayer->platformLayer());
+        otherMask->flushChanges(true);
+        
+        // CSS3 mask and QGraphicsOpacityEffect are the same thing! we just need to convert...
+        // The conversion is as fast as we can make it - we render the layer once and send it to the QGraphicsOpacityEffect
+        if (!graphicsEffect()) {
+            QPixmap mask(QSize(m_state.maskLayer->size().width(), m_state.maskLayer->size().height()));
+            mask.fill(Qt::transparent);
+            {
+                QPainter p(&mask);
+                p.setRenderHints(painter->renderHints(), true);
+                p.setCompositionMode(QPainter::CompositionMode_Source);
+                static_cast<GraphicsLayerQtImpl*>(m_state.maskLayer->platformLayer())->drawContents(&p, option->exposedRect, true);
+            }
+            QGraphicsOpacityEffect* opacityEffect = new QGraphicsOpacityEffect(this);
+            opacityEffect->setOpacity(1);
+            opacityEffect->setOpacityMask(QBrush(mask));
+            setGraphicsEffect(opacityEffect);
+        }
+    }
+    drawContents(painter, option->exposedRect);
+}
+
+void GraphicsLayerQtImpl::drawContents(QPainter* painter, const QRectF& r, 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())
+        painter->fillRect(r, QColor(m_currentContent.backgroundColor));
+
+    if (!rect.isEmpty()) {
+        switch (m_currentContent.contentType) {
+        case PixmapContentType:
+            // we have to scale the image to the contentsRect
+            // FIXME: a better way would probably be drawPixmap with a src/target rect
+            painter->drawPixmap(rect.topLeft(), m_currentContent.pixmap.scaled(m_state.contentsRect.size()), r);
+            break;
+        case ColorContentType:
+            painter->fillRect(rect, m_currentContent.contentsBackgroundColor);
+            break;
+        default:
+            if (m_state.drawsContent) {
+                // 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;
+        }
+    }
+}
+
+void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
+{
+    if (!this)
+        return;
+
+    m_changeMask |= changeMask;
+
+    if (m_layer->client())
+        m_layer->client()->notifySyncRequired(m_layer);
+}
+
+void GraphicsLayerQtImpl::flushChanges(bool recursive)
+{
+    // this is the bulk of the work. understanding what the compositor is trying to achieve,
+    // what graphics-view can do, and trying to find a sane common-grounds
+    if (!m_layer || m_changeMask == NoChanges)
+        goto afterLayerChanges;
+
+    if (m_currentContent.contentType == HTMLContentType && (m_changeMask & ParentChange)) {
+        // the WebCore compositor manages item ownership. We have to make sure
+        // graphics-view doesn't try to snatch that ownership...
+        if (!m_layer->parent() && !parentItem())
+            setParentItem(0);
+        else if (m_layer && m_layer->parent() && m_layer->parent()->nativeLayer() != parentItem())
+            setParentItem(m_layer->parent()->nativeLayer());
+    }
+
+    if (m_changeMask & ChildrenChange) {
+        // we basically do an XOR operation on the list of current children
+        // and the list of wanted children, and remove/add
+        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;
+        for (QSet<QGraphicsItem*>::const_iterator it = childrenToAdd.begin(); it != childrenToAdd.end(); ++it) {
+             if (QGraphicsItem* w = *it)
+                w->setParentItem(this);
+        }
+        for (QSet<QGraphicsItem*>::const_iterator it = childrenToRemove.begin(); it != childrenToRemove.end(); ++it) {
+             if (QGraphicsItem* w = *it)
+                w->setParentItem(0);
+        }
+
+        // children are ordered by z-value, let graphics-view know.
+        for (size_t i = 0; i < newChildrenVector.size(); ++i)
+            if (newChildrenVector[i]->platformLayer())
+                newChildrenVector[i]->platformLayer()->setZValue(i);
+    }
+
+    if (m_changeMask & MaskLayerChange) {
+        // we can't paint here, because we don't know if the mask layer
+        // itself is ready... we'll have to wait till this layer tries to paint
+        setGraphicsEffect(0);
+        if (m_layer->maskLayer())
+            setFlag(ItemClipsChildrenToShape, true);
+        else
+            setFlag(ItemClipsChildrenToShape, m_layer->masksToBounds());
+        update();
+    }
+
+    if ((m_changeMask & PositionChange) && (m_layer->position() != m_state.pos))
+        setPos(m_layer->position().x(), m_layer->position().y());
+
+    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 & (TransformChange | AnchorPointChange | SizeChange)) {
+        // since we convert a percentage-based origin-point to a pixel-based one,
+        // the anchor-point, transform and size from WebCore all affect the one
+        // that we give Qt
+        if (m_state.transform != m_layer->transform() || m_state.anchorPoint != m_layer->anchorPoint() || m_state.size != m_layer->size())
+            setBaseTransform(QTransform(m_layer->transform()));
+    }
+
+    if (m_changeMask & (ContentChange | DrawsContentChange)) {
+        switch (m_pendingContent.contentType) {
+        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();
+            setFlag(ItemHasNoContents, false);
+            break;
+
+        case ColorContentType:
+            // no point in caching a solid-color rectangle
+            setCacheMode(QGraphicsItem::NoCache);
+            if (m_pendingContent.contentType != m_currentContent.contentType || m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor)
+                update();
+            m_state.drawsContent = false;
+            setFlag(ItemHasNoContents, false);
+            break;
+
+        case HTMLContentType:
+            if (m_pendingContent.contentType != m_currentContent.contentType)
+                update();
+            if (!m_state.drawsContent && m_layer->drawsContent())
+                update();
+            if (m_layer->drawsContent())
+                setCacheMode(m_transformAnimationRunning ? ItemCoordinateCache : DeviceCoordinateCache);
+            else
+                setCacheMode(NoCache);
+
+            setFlag(ItemHasNoContents, !m_layer->drawsContent());
+            break;
+        }
+    }
+
+    if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity())
+        setOpacity(m_layer->opacity());
+
+    if (m_changeMask & ContentsRectChange) {
+        const QRect rect(m_layer->contentsRect());
+        if (m_state.contentsRect != rect) {
+            m_state.contentsRect = 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();
+
+    if (m_changeMask & DisplayChange)
+        update(m_pendingContent.regionToUpdate.boundingRect());
+
+    if ((m_changeMask & BackgroundColorChange) && (m_pendingContent.backgroundColor != m_currentContent.backgroundColor))
+        update();
+
+    // 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
+
+    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.geoOrientation = m_layer->geometryOrientation();
+    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_currentContent.pixmap = m_pendingContent.pixmap;
+    m_currentContent.contentType = m_pendingContent.contentType;
+    m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
+    m_currentContent.regionToUpdate |= m_pendingContent.regionToUpdate;
+    m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor;
+    m_pendingContent.regionToUpdate = QRegion();
+    m_changeMask = NoChanges;
+
+
+afterLayerChanges:
+    if (!recursive)
+        return;    
+
+    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()))
+                layer->flushChanges(true);
+    }
+}
+
+void GraphicsLayerQtImpl::notifyAnimationStarted()
+{
+    // WebCore notifies javascript when the animation starts
+    // here we're letting it know
+    m_layer->client()->notifyAnimationStarted(m_layer, WTF::currentTime());
+}
+
+GraphicsLayerQt::GraphicsLayerQt(GraphicsLayerClient* client)
+    : GraphicsLayer(client)
+    , m_impl(PassOwnPtr<GraphicsLayerQtImpl>(new GraphicsLayerQtImpl(this)))
+{
+}
+
+GraphicsLayerQt::~GraphicsLayerQt()
+{
+}
+
+// this is the hook for WebCore compositor to know that Qt implements compositing with GraphicsLayerQt
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+    return new GraphicsLayerQt(client);
+}
+
+// reimp from GraphicsLayer.h: Qt is top-down
+GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation()
+{
+    return CompositingCoordinatesTopDown;
+}
+
+// reimp from GraphicsLayer.h: we'll need to update the whole display, and we can't count on the current size because it might change
+void GraphicsLayerQt::setNeedsDisplay()
+{
+    m_impl->m_pendingContent.regionToUpdate = QRegion(QRect(QPoint(0, 0), QSize(size().width(), size().height())));
+    m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& r)
+{
+    m_impl->m_pendingContent.regionToUpdate|= QRectF(r).toAlignedRect();
+    m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setName(const String& name)
+{
+    m_impl->setObjectName(name);
+    GraphicsLayer::setName(name);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setParent(GraphicsLayer* layer)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+    GraphicsLayer::setParent(layer);
+}
+
+// reimp from GraphicsLayer.h
+bool GraphicsLayerQt::setChildren(const Vector<GraphicsLayer*>& children)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+    return GraphicsLayer::setChildren(children);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChild(GraphicsLayer* layer)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+    GraphicsLayer::addChild(layer);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChildAtIndex(GraphicsLayer* layer, int index)
+{
+    GraphicsLayer::addChildAtIndex(layer, index);
+    m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+     GraphicsLayer::addChildAbove(layer, sibling);
+     m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+
+    GraphicsLayer::addChildBelow(layer, sibling);
+    m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+// reimp from GraphicsLayer.h
+bool GraphicsLayerQt::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+    if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+        m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+        return true;
+    }
+
+    return false;
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::removeFromParent()
+{
+    if (parent())
+        m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+    GraphicsLayer::removeFromParent();
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setMaskLayer(GraphicsLayer* layer)
+{
+    GraphicsLayer::setMaskLayer(layer);
+    m_impl->notifyChange(GraphicsLayerQtImpl::MaskLayerChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setPosition(const FloatPoint& p)
+{
+    if (position() != p)
+       m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange);
+    GraphicsLayer::setPosition(p);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& p)
+{
+    if (anchorPoint() != p)
+        m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange);
+    GraphicsLayer::setAnchorPoint(p);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setSize(const FloatSize& size)
+{
+    if (this->size() != size)
+        m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange);
+    GraphicsLayer::setSize(size);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setTransform(const TransformationMatrix& t)
+{
+    if (!m_impl->m_transformAnimationRunning && transform() != t)
+       m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange);
+    GraphicsLayer::setTransform(t);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& t)
+{
+    GraphicsLayer::setChildrenTransform(t);
+    m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenTransformChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setPreserves3D(bool b)
+{
+    if (b != preserves3D());
+       m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange);
+    GraphicsLayer::setPreserves3D(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setMasksToBounds(bool b)
+{
+    GraphicsLayer::setMasksToBounds(b);
+    m_impl->notifyChange(GraphicsLayerQtImpl::MasksToBoundsChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setDrawsContent(bool b)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::DrawsContentChange);
+    GraphicsLayer::setDrawsContent(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setBackgroundColor(const Color& c)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
+    m_impl->m_pendingContent.backgroundColor = c;
+    GraphicsLayer::setBackgroundColor(c);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::clearBackgroundColor()
+{
+    m_impl->m_pendingContent.backgroundColor = QColor();
+    m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
+    GraphicsLayer::clearBackgroundColor();
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsOpaque(bool b)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOpaqueChange);
+    GraphicsLayer::setContentsOpaque(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setBackfaceVisibility(bool b)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::BackfaceVisibilityChange);
+    GraphicsLayer::setBackfaceVisibility(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setOpacity(float o)
+{
+    if (!m_impl->m_opacityAnimationRunning && opacity() != o)
+       m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+    GraphicsLayer::setOpacity(o);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsRect(const IntRect& r)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::ContentsRectChange);
+    GraphicsLayer::setContentsRect(r);
+}
+
+// reimp from GraphicsLayer.h
+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();
+}
+
+// reimp from GraphicsLayer.h
+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);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::GeometryOrientationChange);
+    GraphicsLayer::setGeometryOrientation(orientation);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsOrientation(CompositingCoordinatesOrientation orientation)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOrientationChange);
+    GraphicsLayer::setContentsOrientation(orientation);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::distributeOpacity(float o)
+{
+    m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+    m_impl->m_state.distributeOpacity = true;
+}
+
+// reimp from GraphicsLayer.h
+float GraphicsLayerQt::accumulatedOpacity() const
+{
+    return m_impl->effectiveOpacity();
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::syncCompositingState()
+{
+    m_impl->flushChanges();
+    GraphicsLayer::syncCompositingState();
+}
+
+// reimp from GraphicsLayer.h
+NativeLayer GraphicsLayerQt::nativeLayer() const
+{
+    return m_impl.get();
+}
+
+// reimp from GraphicsLayer.h
+PlatformLayer* GraphicsLayerQt::platformLayer() const
+{
+    return m_impl.get();
+}
+
+// now we start dealing with WebCore animations translated to Qt animations
+
+template <typename T>
+struct KeyframeValueQt {
+    TimingFunction timingFunction;
+    T value;
+};
+
+// we copy this from the AnimationBase.cpp
+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));
+}
+
+// we want the timing function to be as close as possible to what the web-developer intended, so we're using the same function used by WebCore when compositing is disabled
+// 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)
+{
+    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;
+}
+
+// helper functions to safely get a value out of WebCore's AnimationValue*
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, TransformOperations& transformOperations)
+{
+    transformOperations = TransformOperations();
+    if (!animationValue)
+        return;
+
+    const TransformOperations* ops = static_cast<const TransformAnimationValue*>(animationValue)->value();
+
+    if (ops)
+        transformOperations = *ops;
+}
+
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, qreal& realValue)
+{
+    realValue = animationValue ? static_cast<const FloatAnimationValue*>(animationValue)->value() : 0;
+}
+
+// we put a bit of the functionality in a base class to allow casting and to save some code size
+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_keyframesName(name)
+    {
+    }
+
+    virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+    {
+        QAbstractAnimation::updateState(newState, oldState);
+
+        // for some reason I have do this asynchronously - or the animation won't work
+        if (newState == Running && oldState == Stopped)
+            QTimer::singleShot(0, m_layer.data(), SLOT(notifyAnimationStarted()));
+    }
+
+    virtual int duration() const { return m_duration; }
+
+    QWeakPointer<GraphicsLayerQtImpl> m_layer;
+    IntSize m_boxSize;
+    int m_duration;
+    bool m_isAlternate;
+    AnimatedPropertyID m_webkitPropertyID;
+    QString m_keyframesName;
+};
+
+// we'd rather have a templatized QAbstractAnimation than QPropertyAnimation / QVariantAnimation;
+// Since we know the types that we're dealing with, the QObject/QProperty/QVariant abstraction
+// buys us very little in this case, for too much overhead
+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)
+    {
+        // copying those WebCore structures is not trivial, we have to do it like this
+        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();
+            webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value);
+            m_keyframeValues[animationValue->keyTime()] = keyframeValue;
+        }
+    }
+
+protected:
+
+    // this is the part that differs between animated properties
+    virtual void applyFrame(const T& fromValue, const T& toValue, qreal progress) = 0;
+
+    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;
+
+        // we find the current from-to keyframes in our little map
+        typename QMap<qreal, KeyframeValueQt<T> >::iterator it = m_keyframeValues.find(progress);
+
+        // we didn't find an exact match, we try the closest match (lower bound)
+        if (it == m_keyframeValues.end())
+            it = m_keyframeValues.lowerBound(progress)-1;
+
+        // we didn't find any match - we use the first keyframe
+        if (it == m_keyframeValues.end())
+            it = m_keyframeValues.begin();
+
+        typename QMap<qreal, KeyframeValueQt<T> >::iterator it2 = it+1;
+        if (it2 == m_keyframeValues.end())
+            it2 = m_keyframeValues.begin();
+        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;
+
+        // now we have a source keyframe, origin keyframe and a timing function
+        // we can now process the progress and apply the frame
+        qreal normalizedProgress = (it.key() == it2.key()) ? 0 : (progress - it.key()) / (it2.key() - it.key());
+        normalizedProgress = applyTimingFunction(timingFunc, normalizedProgress, duration() / 1000);
+        applyFrame(fromValue, toValue, normalizedProgress);
+    }
+
+    QMap<qreal, KeyframeValueQt<T> > m_keyframeValues;
+};
+
+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()
+    {
+        // this came up during the compositing/animation LayoutTests
+        // when the animation dies, the transform has to go back to default
+        if (m_layer)
+            m_layer.data()->setBaseTransform(QTransform(m_layer.data()->m_layer->transform()));
+    }
+
+    // the idea is that we let WebCore manage the transform-operations
+    // and Qt just manages the animation heartbeat and the bottom-line QTransform
+    // we get the performance not by using QTransform instead of TransformationMatrix, but by proper caching of
+    // items that are expensive for WebCore to render. We want the rest to be as close to WebCore's idea as possible.
+    virtual void applyFrame(const TransformOperations& sourceOperations, const TransformOperations& targetOperations, qreal progress)
+    {
+        TransformationMatrix transformMatrix;
+
+        // this looks simple but is really tricky to get right. Use caution.
+        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(QTransform(transformMatrix));
+    }
+
+    virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+    {
+        AnimationQtBase::updateState(newState, oldState);
+        if (!m_layer)
+            return;
+        m_layer.data()->flushChanges(true);
+
+        // 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
+        if (newState == QAbstractAnimation::Running) {
+            m_layer.data()->m_transformAnimationRunning = true;
+            if (m_layer.data()->cacheMode() == QGraphicsItem::DeviceCoordinateCache)
+                m_layer.data()->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+        } else {
+            m_layer.data()->m_transformAnimationRunning = false;
+            if (m_layer.data()->cacheMode() == QGraphicsItem::ItemCoordinateCache)
+                m_layer.data()->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+        }
+    }
+};
+
+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)
+    {
+    }
+
+    virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress)
+    {
+        m_layer.data()->setOpacity(qMin<qreal>(qMax<qreal>(fromValue + (toValue-fromValue)*progress, 0), 1));
+    }
+
+    virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+    {
+        QAbstractAnimation::updateState(newState, oldState);
+        if (m_layer)
+            m_layer.data()->m_opacityAnimationRunning = (newState == QAbstractAnimation::Running);
+    }
+};
+
+bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset)
+{
+    if (!anim->duration() || !anim->iterationCount())
+        return false;
+
+    QAbstractAnimation* 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;
+    }
+
+    // we make sure WebCore::Animation and QAnimation are on the same terms
+    newAnim->setLoopCount(anim->iterationCount());
+    m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim));
+    QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume()));
+    timeOffset += anim->delay();
+
+    // flush now or flicker...
+    m_impl->flushChanges(false);
+
+    if (timeOffset)
+        QTimer::singleShot(timeOffset * 1000, newAnim, SLOT(start()));
+    else
+        newAnim->start();
+
+    QObject::connect(newAnim, SIGNAL(finished()), newAnim, SLOT(deleteLater()));
+
+    return true;
+}
+
+void GraphicsLayerQt::removeAnimationsForProperty(AnimatedPropertyID id)
+{
+    for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+        if (*it) {
+            AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+            if (anim && anim->m_webkitPropertyID == id) {
+                delete anim;
+                it = m_impl->m_animations.erase(it);
+                --it;
+            }
+        }
+    }
+}
+
+void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name)
+{
+    for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+        if (*it) {
+            AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data());
+            if (anim && anim->m_keyframesName == QString(name)) {
+                (*it).data()->deleteLater();
+                it = m_impl->m_animations.erase(it);
+                --it;
+            }
+        }
+    }
+}
+
+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) {
+        if (*it) {
+            AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data());
+            if (anim && anim->m_keyframesName == QString(name))
+                QTimer::singleShot(timeOffset * 1000, anim, SLOT(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 {
+        for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+            QAbstractAnimation* anim = it->data();
+            if (anim)
+                anim->pause();
+        }
+    }
+}
+
+void GraphicsLayerQt::resumeAnimations()
+{
+    if (m_impl->m_suspendTimer.isActive()) {
+        m_impl->m_suspendTimer.stop();
+        for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+            QAbstractAnimation* anim = (*it).data();
+            if (anim)
+                anim->resume();
+        }
+    }
+}
+
+}
+
+#include <GraphicsLayerQt.moc>
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
new file mode 100644 (file)
index 0000000..3a53bd9
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+    Copyright (C) 2009 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.
+*/
+
+#ifndef GraphicsLayerQt_h
+#define GraphicsLayerQt_h
+
+#include "GraphicsLayer.h"
+#include "GraphicsLayerClient.h"
+
+namespace WebCore {
+
+class GraphicsLayerQtImpl;
+
+class GraphicsLayerQt : public GraphicsLayer {
+    friend class GraphicsLayerQtImpl;
+
+public:
+    GraphicsLayerQt(GraphicsLayerClient*);
+    virtual ~GraphicsLayerQt();
+
+    // reimps from GraphicsLayer.h
+    virtual NativeLayer nativeLayer() const;
+    virtual PlatformLayer* platformLayer() const;
+    virtual void setNeedsDisplay();
+    virtual void setNeedsDisplayInRect(const FloatRect&);
+    virtual void setParent(GraphicsLayer* layer);
+    virtual void setName(const String& name);
+    virtual bool setChildren(const Vector<GraphicsLayer*>&);
+    virtual void addChild(GraphicsLayer*);
+    virtual void addChildAtIndex(GraphicsLayer*, int index);
+    virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+    virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+    virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+    virtual void removeFromParent();
+    virtual void setMaskLayer(GraphicsLayer* layer);
+    virtual void setPosition(const FloatPoint& p);
+    virtual void setAnchorPoint(const FloatPoint3D& p);
+    virtual void setSize(const FloatSize& size);
+    virtual void setTransform(const TransformationMatrix& t);
+    virtual void setChildrenTransform(const TransformationMatrix& t);
+    virtual void setPreserves3D(bool b);
+    virtual void setMasksToBounds(bool b);
+    virtual void setDrawsContent(bool b);
+    virtual void setBackgroundColor(const Color&);
+    virtual void clearBackgroundColor();
+    virtual void setContentsOpaque(bool b);
+    virtual void setBackfaceVisibility(bool b);
+    virtual void setOpacity(float opacity);
+    virtual void setContentsRect(const IntRect& r);
+    virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset);
+    virtual void removeAnimationsForProperty(AnimatedPropertyID);
+    virtual void removeAnimationsForKeyframes(const String& keyframesName);
+    virtual void pauseAnimation(const String& keyframesName, double timeOffset);
+    virtual void suspendAnimations(double time);
+    virtual void resumeAnimations();
+    virtual void setContentsToImage(Image*);
+    virtual void setContentsBackgroundColor(const Color&);
+    virtual void setGeometryOrientation(CompositingCoordinatesOrientation orientation);
+    virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation);
+    virtual void distributeOpacity(float);
+    virtual float accumulatedOpacity() const;
+    virtual void syncCompositingState();
+
+private:
+    OwnPtr<GraphicsLayerQtImpl> m_impl;
+};
+
+}
+#endif // GraphicsLayerQt_h
index b510736..09fe768 100644 (file)
@@ -29,7 +29,9 @@
 #ifndef QT_NO_CURSOR
 #include <QCursor>
 #endif
+
 #include <QRect>
+class QGraphicsItem;
 
 class QWebPageClient {
 public:
@@ -39,6 +41,16 @@ public:
     virtual void update(const QRect&) = 0;
     virtual void setInputMethodEnabled(bool enable) = 0;
     virtual bool inputMethodEnabled() const = 0;
+#if USE(ACCELERATED_COMPOSITING)
+    // this gets called when we start/stop compositing.
+    virtual void setRootGraphicsLayer(QGraphicsItem* layer) {}
+
+    // this gets called when the compositor wants us to sync the layers
+    // if scheduleSync is true, we schedule a sync ourselves. otherwise,
+    // we wait for the next update and sync the layers then.
+    virtual void markForSync(bool scheduleSync = false) {}
+#endif
+
 #if QT_VERSION >= 0x040600
     virtual void setInputMethodHint(Qt::InputMethodHint hint, bool enable) = 0;
 #endif
index 211f6a4..7b68edb 100644 (file)
@@ -45,6 +45,7 @@ building-libs {
     }
     DEPENDPATH += $$PWD/WebKit/qt/Api
 }
+greaterThan(QT_MINOR_VERSION, 5):DEFINES += WTF_USE_ACCELERATED_COMPOSITING
 
 !mac:!unix|symbian {
     DEFINES += USE_SYSTEM_MALLOC
index 82aede5..d9e8a74 100644 (file)
 #include "qgraphicswebview.h"
 
 #include "qwebframe.h"
+#include "qwebframe_p.h"
 #include "qwebpage.h"
 #include "qwebpage_p.h"
 #include "QWebPageClient.h"
-#include <QtGui/QGraphicsScene>
-#include <QtGui/QGraphicsView>
+#include <FrameView.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qtimer.h>
 #include <QtGui/qapplication.h>
+#include <QtGui/qgraphicsscene.h>
 #include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtGui/qpixmapcache.h>
 #include <QtGui/qstyleoption.h>
 #if defined(Q_WS_X11)
 #include <QX11Info>
 #endif
+#include <Settings.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+
+// the overlay is here for one reason only: to have the scroll-bars and other
+// extra UI elements appear on top of any QGraphicsItems created by CSS compositing layers
+class QGraphicsWebViewOverlay : public QGraphicsItem {
+    public:
+    QGraphicsWebViewOverlay(QGraphicsWebView* view)
+            :QGraphicsItem(view)
+            , q(view)
+    {
+        setPos(0, 0);
+        setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
+        setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+    }
+
+    QRectF boundingRect() const
+    {
+        return q->boundingRect();
+    }
+
+    void paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget*)
+    {
+        q->page()->mainFrame()->render(painter, static_cast<QWebFrame::RenderLayer>(QWebFrame::AllLayers&(~QWebFrame::ContentsLayer)), options->exposedRect.toRect());
+    }
+
+    friend class QGraphicsWebView;
+    QGraphicsWebView* q;
+};
+
+#endif
 
 class QGraphicsWebViewPrivate : public QWebPageClient {
 public:
     QGraphicsWebViewPrivate(QGraphicsWebView* parent)
         : q(parent)
         , page(0)
-    {}
+#if USE(ACCELERATED_COMPOSITING)
+        , rootGraphicsLayer(0)
+        , shouldSync(true)
+#endif
+    {
+#if USE(ACCELERATED_COMPOSITING)
+        // the overlay and stays alive for the lifetime of
+        // this QGraphicsWebView as the scrollbars are needed when there's no compositing
+        q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
+#endif
+    }
 
     virtual ~QGraphicsWebViewPrivate();
     virtual void scroll(int dx, int dy, const QRect&);
@@ -61,14 +108,95 @@ public:
 
     virtual QObject* pluginParent() const;
 
+#if USE(ACCELERATED_COMPOSITING)
+    virtual void setRootGraphicsLayer(QGraphicsItem* layer);
+    virtual void markForSync(bool scheduleSync);
+    void updateCompositingScrollPosition();
+#endif
+
+    void syncLayers();
     void _q_doLoadFinished(bool success);
 
     QGraphicsWebView* q;
     QWebPage* page;
+#if USE(ACCELERATED_COMPOSITING)
+    QGraphicsItem* rootGraphicsLayer;
+
+    // the overlay gets instantiated when the root layer is attached, and get deleted when it's detached
+    QSharedPointer<QGraphicsWebViewOverlay> overlay;
+
+    // we need to sync the layers if we get a special call from the WebCore
+    // compositor telling us to do so. We'll get that call from ChromeClientQt
+    bool shouldSync;
+
+    // we need to put the root graphics layer behind the overlay (which contains the scrollbar)
+    enum { RootGraphicsLayerZValue, OverlayZValue };
+#endif
 };
 
 QGraphicsWebViewPrivate::~QGraphicsWebViewPrivate()
 {
+#if USE(ACCELERATED_COMPOSITING)
+    if (rootGraphicsLayer) {
+        // we don't need to delete the root graphics layer
+        // The lifecycle is managed in GraphicsLayerQt.cpp
+        rootGraphicsLayer->setParentItem(0);
+        q->scene()->removeItem(rootGraphicsLayer);
+    }
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void QGraphicsWebViewPrivate::setRootGraphicsLayer(QGraphicsItem* layer)
+{
+    if (rootGraphicsLayer) {
+        rootGraphicsLayer->setParentItem(0);
+        q->scene()->removeItem(rootGraphicsLayer);
+        QWebFramePrivate::core(q->page()->mainFrame())->view()->syncCompositingStateRecursive();
+    }
+
+    rootGraphicsLayer = layer;
+
+    if (layer) {
+        layer->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
+        layer->setParentItem(q);
+        layer->setZValue(RootGraphicsLayerZValue);
+        if (!overlay) {
+            overlay = QSharedPointer<QGraphicsWebViewOverlay>(new QGraphicsWebViewOverlay(q));
+            overlay->setZValue(OverlayZValue);
+        }
+        updateCompositingScrollPosition();
+    } else {
+        // we don't have compositing layers, we can render the scrollbars and content in one go
+        overlay.clear();
+    }
+}
+
+void QGraphicsWebViewPrivate::markForSync(bool scheduleSync)
+{
+    shouldSync = true;
+    if (scheduleSync)
+        QTimer::singleShot(0, q, SLOT(syncLayers()));
+}
+
+void QGraphicsWebViewPrivate::updateCompositingScrollPosition()
+{
+    if (rootGraphicsLayer && q->page() && q->page()->mainFrame()) {
+        const QPoint scrollPosition = q->page()->mainFrame()->scrollPosition();
+        rootGraphicsLayer->setPos(-scrollPosition);
+    }
+}
+
+#endif
+
+void QGraphicsWebViewPrivate::syncLayers()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (shouldSync) {
+        QWebFramePrivate::core(q->page()->mainFrame())->view()->syncCompositingStateRecursive();
+        shouldSync = false;
+    }
+#endif
 }
 
 void QGraphicsWebViewPrivate::_q_doLoadFinished(bool success)
@@ -83,11 +211,18 @@ void QGraphicsWebViewPrivate::_q_doLoadFinished(bool success)
 void QGraphicsWebViewPrivate::scroll(int dx, int dy, const QRect& rectToScroll)
 {
     q->scroll(qreal(dx), qreal(dy), QRectF(rectToScroll));
+#if USE(ACCELERATED_COMPOSITING)
+    updateCompositingScrollPosition();
+#endif
 }
 
 void QGraphicsWebViewPrivate::update(const QRect & dirtyRect)
 {
     q->update(QRectF(dirtyRect));
+#if USE(ACCELERATED_COMPOSITING)
+    if (overlay)
+        overlay->update(QRectF(dirtyRect));
+#endif
 }
 
 
@@ -248,6 +383,7 @@ QGraphicsWebView::QGraphicsWebView(QGraphicsItem* parent)
     setAcceptTouchEvents(true);
 #endif
     setFocusPolicy(Qt::StrongFocus);
+    setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
 }
 
 /*!
@@ -297,7 +433,12 @@ QWebPage* QGraphicsWebView::page() const
 */
 void QGraphicsWebView::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*)
 {
-    page()->mainFrame()->render(painter, option->exposedRect.toRect());
+#if USE(ACCELERATED_COMPOSITING)
+    page()->mainFrame()->render(painter, d->overlay ? QWebFrame::ContentsLayer : QWebFrame::AllLayers, option->exposedRect.toAlignedRect());
+    d->syncLayers();
+#else
+    page()->mainFrame()->render(painter, QWebFrame::AllLayers, option->exposedRect.toRect());
+#endif
 }
 
 /*! \reimp
@@ -425,6 +566,10 @@ void QGraphicsWebView::setPage(QWebPage* page)
     d->page = page;
     if (!d->page)
         return;
+#if USE(ACCELERATED_COMPOSITING)
+    if (d->overlay)
+        d->overlay->prepareGeometryChange();
+#endif
     d->page->d->client = d; // set the page client
 
     QSize size = geometry().size().toSize();
@@ -528,6 +673,12 @@ qreal QGraphicsWebView::zoomFactor() const
 */
 void QGraphicsWebView::updateGeometry()
 {
+
+#if USE(ACCELERATED_COMPOSITING)
+    if (d->overlay)
+        d->overlay->prepareGeometryChange();
+#endif
+
     QGraphicsWidget::updateGeometry();
 
     if (!d->page)
@@ -543,6 +694,11 @@ void QGraphicsWebView::setGeometry(const QRectF& rect)
 {
     QGraphicsWidget::setGeometry(rect);
 
+#if USE(ACCELERATED_COMPOSITING)
+    if (d->overlay)
+        d->overlay->prepareGeometryChange();
+#endif
+
     if (!d->page)
         return;
 
index f3afb4c..3cf51b2 100644 (file)
@@ -134,6 +134,9 @@ protected:
 
 private:
     Q_PRIVATE_SLOT(d, void _q_doLoadFinished(bool success))
+    // we don't want to change the moc based on USE() macro, so this function is here
+    // but will be empty if ACCLERATED_COMPOSITING is disabled
+    Q_PRIVATE_SLOT(d, void syncLayers())
 
     QGraphicsWebViewPrivate* const d;
     friend class QGraphicsWebViewPrivate;
index d7d375b..a94a3aa 100644 (file)
@@ -152,7 +152,12 @@ void QWebSettingsPrivate::apply()
         value = attributes.value(QWebSettings::JavascriptEnabled,
                                       global->attributes.value(QWebSettings::JavascriptEnabled));
         settings->setJavaScriptEnabled(value);
+#if USE(ACCELERATED_COMPOSITING)
+        value = attributes.value(QWebSettings::AcceleratedCompositingEnabled,
+                                      global->attributes.value(QWebSettings::AcceleratedCompositingEnabled));
 
+        settings->setAcceleratedCompositingEnabled(value);
+#endif
         value = attributes.value(QWebSettings::JavascriptCanOpenWindows,
                                       global->attributes.value(QWebSettings::JavascriptCanOpenWindows));
         settings->setJavaScriptCanOpenWindowsAutomatically(value);
@@ -389,6 +394,7 @@ QWebSettings::QWebSettings()
     d->attributes.insert(QWebSettings::OfflineWebApplicationCacheEnabled, false);
     d->attributes.insert(QWebSettings::LocalStorageEnabled, false);
     d->attributes.insert(QWebSettings::LocalContentCanAccessRemoteUrls, false);
+    d->attributes.insert(QWebSettings::AcceleratedCompositingEnabled, false);
     d->offlineStorageDefaultQuota = 5 * 1024 * 1024;
     d->defaultTextEncoding = QLatin1String("iso-8859-1");
 }
index 32af448..77f2167 100644 (file)
@@ -68,7 +68,8 @@ public:
 #endif
         LocalContentCanAccessRemoteUrls,
         DnsPrefetchEnabled,
-        XSSAuditorEnabled
+        XSSAuditorEnabled,
+        AcceleratedCompositingEnabled
     };
     enum WebGraphic {
         MissingImageGraphic,
index 275f208..9ef2e55 100644 (file)
 #include "config.h"
 #include "qwebview.h"
 
+#include "Page.h"
 #include "QWebPageClient.h"
+#include "Settings.h"
 #include "qwebframe.h"
 #include "qwebpage_p.h"
-
 #include "qbitmap.h"
 #include "qevent.h"
 #include "qpainter.h"
@@ -247,6 +248,9 @@ void QWebView::setPage(QWebPage* page)
                 this, SLOT(_q_pageDestroyed()));
     }
     setAttribute(Qt::WA_OpaquePaintEvent, d->page);
+#if USE(ACCELERATED_COMPOSITING)
+    d->page->d->page->settings()->setAcceleratedCompositingEnabled(false);
+#endif
     update();
 }
 
index a6b4124..3244aee 100644 (file)
@@ -1,3 +1,60 @@
+2010-01-21  No'am Rosenthal  <noam.rosenthal@nokia.com>
+
+        Reviewed by Antti Koivisto.
+
+        [Qt] Implement GraphicsLayer for accelerated layer compositing
+        https://bugs.webkit.org/show_bug.cgi?id=33514
+
+        Here we have the QGraphicsWebView support for accelerated compositing
+
+        * Api/qgraphicswebview.cpp:
+        (QGraphicsWebViewOverlay::q): access to container object
+        (QGraphicsWebViewOverlay::boundingRect): overlay has same rect as the
+        webview
+        (QGraphicsWebViewOverlay::paint): paint everything but the contents
+        (QGraphicsWebViewPrivate::QGraphicsWebViewPrivate): some vars needed
+        for accelerated compositing
+        (QGraphicsWebViewPrivate::):
+        (QGraphicsWebViewPrivate::~QGraphicsWebViewPrivate):
+        (QGraphicsWebViewPrivate::setRootGraphicsLayer): make sure we have a
+        scrollbar overlay, and that the new graphics layer is parented by the
+        web-view
+        (QGraphicsWebViewPrivate::markForSync): flush changes at earliest
+        convenience or during the next draw
+
+        (QGraphicsWebViewPrivate::updateCompositingScrollPosition): sync the
+        position of the compositing layer with the scroll position
+        (QGraphicsWebViewPrivate::syncLayers): flush changes now
+        (QGraphicsWebViewPrivate::scroll): make sure we also move the
+        compositing layer
+        (QGraphicsWebViewPrivate::update): also update the overlay if needed
+        (QGraphicsWebView::QGraphicsWebView): initialize overlay with 0
+        (QGraphicsWebView::paint): paint only contents if we have an overlay,
+        sync the compositing layers now if needed
+        (QGraphicsWebView::setPage): also clean up the compositing
+        (QGraphicsWebView::updateGeometry): also update overlay geo
+        (QGraphicsWebView::setGeometry): also update overlay geo
+        * Api/qgraphicswebview.h: reimp compositing stuff from QWebPageClient
+        * Api/qwebsettings.cpp: init new settings flag for compositing as
+        false
+        (QWebSettingsPrivate::apply): apply new settings flag for compositing
+        (QWebSettings::QWebSettings):
+        * Api/qwebsettings.h: new settings flag for compositing
+        * Api/qwebview.cpp: 
+        (QWebView::setPage): qwebview doesn't support compositing: always false
+        * QGVLauncher/main.cpp:
+        (WebView::WebView): some more cmdline arguments + compositing
+        (MainWindow::init): some more cmdline arguments
+        (main): ditto
+        * WebCoreSupport/ChromeClientQt.cpp:
+        (WebCore::ChromeClientQt::attachRootGraphicsLayer): reimp for
+        accel-compositing
+        (WebCore::ChromeClientQt::setNeedsOneShotDrawingSynchronization):
+        reimp for accel compositing
+        (WebCore::ChromeClientQt::scheduleCompositingLayerSync): reimp for
+        accel compositing
+        * WebCoreSupport/ChromeClientQt.h: reimps for accel compositing
+
 2010-01-21  Benjamin Poulain  <benjamin.poulain@nokia.com>
 
         Reviewed by Simon Hausmann.
index b82347e..1b04c60 100644 (file)
@@ -72,6 +72,8 @@ public:
     WebView(QGraphicsItem* parent = 0)
         : QGraphicsWebView(parent)
     {
+        if (QApplication::instance()->arguments().contains("--cacheWebView"))
+            setCacheMode(QGraphicsItem::DeviceCoordinateCache);
     }
     void setYRotation(qreal angle)
     {
@@ -253,6 +255,12 @@ public:
         setAttribute(Qt::WA_DeleteOnClose);
 
         view->setScene(scene->scene());
+        const QStringList arguments = QApplication::instance()->arguments();
+        const int indexOfViewportUpdateMode = arguments.indexOf("--updateMode");
+        if (indexOfViewportUpdateMode > 1 && indexOfViewportUpdateMode < arguments.count() - 1) {
+            const QString updateMode = arguments[indexOfViewportUpdateMode+1] + "ViewportUpdate";
+            view->setViewportUpdateMode(static_cast<QGraphicsView::ViewportUpdateMode>(QGraphicsView::staticMetaObject.enumerator(QGraphicsView::staticMetaObject.indexOfEnumerator("ViewportUpdateMode")).keysToValue(updateMode.toAscii())));
+        }
 
         setCentralWidget(view);
 
@@ -447,6 +455,10 @@ QWebPage* WebPage::createWindow(QWebPage::WebWindowType)
 int main(int argc, char** argv)
 {
     QApplication app(argc, argv);
+    if (app.arguments().contains("--help")) {
+        qDebug() << "Usage: QGVLauncher [--url url] [--compositing] [--updateMode Full|Minimal|Smart|No|BoundingRect] [--cacheWebView]\n";
+        return 0;
+    }
     QString url = QString("file://%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
 
     app.setApplicationName("GQVLauncher");
@@ -458,14 +470,20 @@ int main(int argc, char** argv)
     QWebSettings::enablePersistentStorage();
 
     const QStringList args = app.arguments();
-    if (args.count() > 1)
+    const int indexOfUrl = args.indexOf("--url");
+    if (indexOfUrl > 0 && indexOfUrl < args.count() - 1)
+        url = args.at(indexOfUrl+1);
+    else if (args.count() > 1)
         url = args.at(1);
+    if (args.contains("--compositing"))
+        QWebSettings::globalSettings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, true);
 
     MainWindow* window = new MainWindow;
     window->load(url);
 
-    for (int i = 2; i < args.count(); i++)
-        window->newWindow(args.at(i));
+    for (int i = 2; i < args.count(); ++i)
+        if (!args.at(i).startsWith("-") && !args.at(i - 1).startsWith("-"))
+            window->newWindow(args.at(i));
 
     window->show();
     return app.exec();
index 6345539..5a269dd 100644 (file)
@@ -25,6 +25,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include "config.h"
 #include "ChromeClientQt.h"
 
 #include "QWebPageClient.h"
 #include "SecurityOrigin.h"
 
+#include <qdebug.h>
+#include <qtextdocument.h>
+#include <qtooltip.h>
+
 #include "qwebpage.h"
 #include "qwebpage_p.h"
 #include "qwebframe_p.h"
 #include "qwebsecurityorigin_p.h"
 #include "qwebview.h"
 
-#include <qtooltip.h>
-#include <qtextdocument.h>
-
-namespace WebCore
-{
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerQt.h"
+#endif
 
+namespace WebCore {
 
 ChromeClientQt::ChromeClientQt(QWebPage* webPage)
     : m_webPage(webPage)
@@ -466,6 +470,28 @@ void ChromeClientQt::requestGeolocationPermissionForFrame(Frame*, Geolocation*)
     notImplemented();
 }
 
+#if USE(ACCELERATED_COMPOSITING)
+void ChromeClientQt::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
+{    
+    if (platformPageClient())
+        platformPageClient()->setRootGraphicsLayer(graphicsLayer ? graphicsLayer->nativeLayer() : 0);
+}
+
+void ChromeClientQt::setNeedsOneShotDrawingSynchronization()
+{
+    // we want the layers to synchronize next time we update the screen anyway
+    if (platformPageClient())
+        platformPageClient()->markForSync(false);
+}
+
+void ChromeClientQt::scheduleCompositingLayerSync()
+{
+    // we want the layers to synchronize ASAP
+    if (platformPageClient())
+        platformPageClient()->markForSync(true);
+}
+#endif
+
 QtAbstractWebPopup* ChromeClientQt::createSelectPopup()
 {
     return new QtFallbackWebPopup;
index 7077501..d60ec06 100644 (file)
@@ -123,6 +123,15 @@ namespace WebCore {
 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
         virtual void reachedMaxAppCacheSize(int64_t spaceNeeded);
 #endif
+
+#if USE(ACCELERATED_COMPOSITING)
+        // see ChromeClient.h
+        // this is a hook for WebCore to tell us what we need to do with the GraphicsLayers
+        virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*);
+        virtual void setNeedsOneShotDrawingSynchronization();
+        virtual void scheduleCompositingLayerSync();
+#endif
+
         virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>);
 
         virtual void formStateDidChange(const Node*) { }