<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[46645] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/46645">46645</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2009-07-31 16:03:25 -0700 (Fri, 31 Jul 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>2009-07-31  Simon Fraser  &lt;simon.fraser@apple.com&gt;

        Reviewed by Anders Carlsson.

        Accelerated animations stutter on pages with lots of animations and 3d transforms
        https://bugs.webkit.org/show_bug.cgi?id=27884

        This patch changes the strategy for synchronizing painting view the view,
        and compositing layer updates. Previously the strategy was to disable screen
        updates between the time we updated the layer tree, and painted the view. That
        left screen updates disabled for too long (hundreds of milliseconds) in some
        cases, causing animation stutter.

        The new strategy is to batch up changes to the CA layer tree, and commit them
        all at once just before painting happens (referred to as a &quot;sync&quot; in the code).
        GraphicsLayerCA now keeps a bitmask of changed properties, and then migrates
        the values stored in GraphicsLayer into the CA layer tree at commit time.

        Compositing layers are then synced in FrameView::paintContents(). However, not
        all style/layout changes will result in painting; to deal with style changes that
        touch only compositing properties, we set up a runloop observer that takes care
        of comitting layer changes when no painting happens.

        * WebCore.base.exp: Export FrameView::syncCompositingStateRecursive()

        * loader/EmptyClients.h: scheduleViewUpdate() renamed to syncCompositingStateRecursive()
        * page/ChromeClient.h: scheduleViewUpdate() renamed to syncCompositingStateRecursive()

        * page/FrameView.h:
        * page/FrameView.cpp:
        (WebCore::FrameView::syncCompositingStateRecursive): syncCompositingState() on the
        view and all subviews. Like layoutIfNeededRecursive(). If layout is pending, does not
        sync and returns false, since we only want to sync when layout is done.

        (WebCore::FrameView::paintContents): syncCompositingState() before painting.

        * page/animation/KeyframeAnimation.cpp:
        (WebCore::KeyframeAnimation::endAnimation):
        Call animationPaused() to notify the graphics layers about animation pausing.

        * platform/graphics/FloatPoint3D.h:
        (WebCore::operator==):
        (WebCore::operator!=):
        Add missing comparison operators.

        * platform/graphics/GraphicsLayer.cpp:
        (WebCore::GraphicsLayer::setOpacity):
        (WebCore::GraphicsLayer::setBackgroundColor): Simple setters no longer care about animation info.

        (WebCore::GraphicsLayer::paintGraphicsLayerContents): Null-check client.

        * platform/graphics/GraphicsLayer.h:
        (WebCore::AnimationValue:):
        (WebCore::TransformAnimationValue:):
        (WebCore::KeyframeValueList:):
        (WebCore::KeyframeValueList::insert):
        Cleaned up versions of FloatValue and TransformValue, used to store information
        about keyframes values.

        (WebCore::GraphicsLayer::contentsRect):
        (WebCore::GraphicsLayer::setContentsRect):
        ContentsRect is now a simple setter.

        (WebCore::GraphicsLayer::addAnimation):
        (WebCore::GraphicsLayer::removeAnimationsForProperty):
        (WebCore::GraphicsLayer::removeAnimationsForKeyframes):
        (WebCore::GraphicsLayer::pauseAnimation):
        Simplified animation api.

        (WebCore::GraphicsLayer::setGeometryOrientation):
        (WebCore::GraphicsLayer::geometryOrientation):
        setGeometryOrientation is now just a normal member variable.

        (WebCore::GraphicsLayer::contentsOrientation): add a getter.
        (WebCore::GraphicsLayer::syncCompositingState): Entry into the layer sync code.

        * platform/graphics/GraphicsLayerClient.h: scheduleViewUpdate() renamed to syncCompositingStateRecursive)

        * platform/graphics/mac/GraphicsLayerCA.h:
        * platform/graphics/mac/GraphicsLayerCA.mm:
        Lots of cleanup and refactoring. Main points:
        - Layer changes are all batched, and only committed to the CA layer on syncCompositingState().
        - Bitmask is used to store which properties have changed. More efficient than before.
        - Simpler animation interface; simple setters are no longer confounded with animations.
        - Refactored code that creates CA animations, and stores which animations are running.

        * platform/graphics/transforms/TransformOperations.h:
        (WebCore::TransformOperations::size):
        (WebCore::TransformOperations::at): Useful accessors for size and indexed access.

        * rendering/RenderLayerBacking.h:
        * rendering/RenderLayerBacking.cpp:
        Renamed 'contentsLayer' to 'foregroundLayer' to avoid confusion with GraphicsLayer's
        contentsLayer.
        Adapt to GraphicsLayer's simpler animation API.
        Pass animation pausing through to the graphics layers.
        contentsBox() is no longer a callback via GraphicsLayerClient.

        * rendering/RenderLayerCompositor.h:
        * rendering/RenderLayerCompositor.cpp:
        (WebCore::RenderLayerCompositor::setCompositingLayersNeedRebuild):
        (WebCore::RenderLayerCompositor::scheduleSync):
        (WebCore::RenderLayerCompositor::rebuildCompositingLayerTree):
        scheduleViewUpdate() is no longer required. Instead, we plumb through &quot;compositingLayerSync&quot;
        notifications, which travel up to WebKit and set up a runloop observer.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebCoreChangeLog">trunk/WebCore/ChangeLog</a></li>
<li><a href="#trunkWebCoreWebCorebaseexp">trunk/WebCore/WebCore.base.exp</a></li>
<li><a href="#trunkWebCoreloaderEmptyClientsh">trunk/WebCore/loader/EmptyClients.h</a></li>
<li><a href="#trunkWebCorepageChromeClienth">trunk/WebCore/page/ChromeClient.h</a></li>
<li><a href="#trunkWebCorepageFrameViewcpp">trunk/WebCore/page/FrameView.cpp</a></li>
<li><a href="#trunkWebCorepageFrameViewh">trunk/WebCore/page/FrameView.h</a></li>
<li><a href="#trunkWebCorepageanimationKeyframeAnimationcpp">trunk/WebCore/page/animation/KeyframeAnimation.cpp</a></li>
<li><a href="#trunkWebCoreplatformgraphicsFloatPoint3Dh">trunk/WebCore/platform/graphics/FloatPoint3D.h</a></li>
<li><a href="#trunkWebCoreplatformgraphicsGraphicsLayercpp">trunk/WebCore/platform/graphics/GraphicsLayer.cpp</a></li>
<li><a href="#trunkWebCoreplatformgraphicsGraphicsLayerh">trunk/WebCore/platform/graphics/GraphicsLayer.h</a></li>
<li><a href="#trunkWebCoreplatformgraphicsGraphicsLayerClienth">trunk/WebCore/platform/graphics/GraphicsLayerClient.h</a></li>
<li><a href="#trunkWebCoreplatformgraphicsmacGraphicsLayerCAh">trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.h</a></li>
<li><a href="#trunkWebCoreplatformgraphicsmacGraphicsLayerCAmm">trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.mm</a></li>
<li><a href="#trunkWebCoreplatformgraphicstransformsTransformOperationsh">trunk/WebCore/platform/graphics/transforms/TransformOperations.h</a></li>
<li><a href="#trunkWebCorerenderingRenderLayerBackingcpp">trunk/WebCore/rendering/RenderLayerBacking.cpp</a></li>
<li><a href="#trunkWebCorerenderingRenderLayerBackingh">trunk/WebCore/rendering/RenderLayerBacking.h</a></li>
<li><a href="#trunkWebCorerenderingRenderLayerCompositorcpp">trunk/WebCore/rendering/RenderLayerCompositor.cpp</a></li>
<li><a href="#trunkWebCorerenderingRenderLayerCompositorh">trunk/WebCore/rendering/RenderLayerCompositor.h</a></li>
<li><a href="#trunkWebKitmacChangeLog">trunk/WebKit/mac/ChangeLog</a></li>
<li><a href="#trunkWebKitmacWebCoreSupportWebChromeClienth">trunk/WebKit/mac/WebCoreSupport/WebChromeClient.h</a></li>
<li><a href="#trunkWebKitmacWebCoreSupportWebChromeClientmm">trunk/WebKit/mac/WebCoreSupport/WebChromeClient.mm</a></li>
<li><a href="#trunkWebKitmacWebViewWebViewmm">trunk/WebKit/mac/WebView/WebView.mm</a></li>
<li><a href="#trunkWebKitmacWebViewWebViewDatah">trunk/WebKit/mac/WebView/WebViewData.h</a></li>
<li><a href="#trunkWebKitmacWebViewWebViewInternalh">trunk/WebKit/mac/WebView/WebViewInternal.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/ChangeLog (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/ChangeLog        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/ChangeLog        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -1,3 +1,109 @@
</span><ins>+2009-07-31  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Reviewed by Anders Carlsson.
+        
+        Accelerated animations stutter on pages with lots of animations and 3d transforms
+        https://bugs.webkit.org/show_bug.cgi?id=27884
+        
+        This patch changes the strategy for synchronizing painting view the view,
+        and compositing layer updates. Previously the strategy was to disable screen
+        updates between the time we updated the layer tree, and painted the view. That
+        left screen updates disabled for too long (hundreds of milliseconds) in some
+        cases, causing animation stutter.
+        
+        The new strategy is to batch up changes to the CA layer tree, and commit them
+        all at once just before painting happens (referred to as a &quot;sync&quot; in the code).
+        GraphicsLayerCA now keeps a bitmask of changed properties, and then migrates
+        the values stored in GraphicsLayer into the CA layer tree at commit time.
+        
+        Compositing layers are then synced in FrameView::paintContents(). However, not
+        all style/layout changes will result in painting; to deal with style changes that
+        touch only compositing properties, we set up a runloop observer that takes care
+        of comitting layer changes when no painting happens.
+
+        * WebCore.base.exp: Export FrameView::syncCompositingStateRecursive()
+
+        * loader/EmptyClients.h: scheduleViewUpdate() renamed to syncCompositingStateRecursive()
+        * page/ChromeClient.h: scheduleViewUpdate() renamed to syncCompositingStateRecursive()
+
+        * page/FrameView.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::syncCompositingStateRecursive): syncCompositingState() on the
+        view and all subviews. Like layoutIfNeededRecursive(). If layout is pending, does not
+        sync and returns false, since we only want to sync when layout is done.
+        
+        (WebCore::FrameView::paintContents): syncCompositingState() before painting.
+
+        * page/animation/KeyframeAnimation.cpp:
+        (WebCore::KeyframeAnimation::endAnimation):
+        Call animationPaused() to notify the graphics layers about animation pausing.
+        
+        * platform/graphics/FloatPoint3D.h:
+        (WebCore::operator==):
+        (WebCore::operator!=): 
+        Add missing comparison operators.
+        
+        * platform/graphics/GraphicsLayer.cpp:
+        (WebCore::GraphicsLayer::setOpacity):
+        (WebCore::GraphicsLayer::setBackgroundColor): Simple setters no longer care about animation info.
+        
+        (WebCore::GraphicsLayer::paintGraphicsLayerContents): Null-check client.
+        
+        * platform/graphics/GraphicsLayer.h:
+        (WebCore::AnimationValue:):
+        (WebCore::TransformAnimationValue:):
+        (WebCore::KeyframeValueList:):
+        (WebCore::KeyframeValueList::insert):
+        Cleaned up versions of FloatValue and TransformValue, used to store information
+        about keyframes values.
+
+        (WebCore::GraphicsLayer::contentsRect):
+        (WebCore::GraphicsLayer::setContentsRect):
+        ContentsRect is now a simple setter.
+        
+        (WebCore::GraphicsLayer::addAnimation):
+        (WebCore::GraphicsLayer::removeAnimationsForProperty):
+        (WebCore::GraphicsLayer::removeAnimationsForKeyframes):
+        (WebCore::GraphicsLayer::pauseAnimation):
+        Simplified animation api.
+        
+        (WebCore::GraphicsLayer::setGeometryOrientation):
+        (WebCore::GraphicsLayer::geometryOrientation):
+        setGeometryOrientation is now just a normal member variable.
+        
+        (WebCore::GraphicsLayer::contentsOrientation): add a getter.
+        (WebCore::GraphicsLayer::syncCompositingState): Entry into the layer sync code.
+        
+        * platform/graphics/GraphicsLayerClient.h: scheduleViewUpdate() renamed to syncCompositingStateRecursive)
+
+        * platform/graphics/mac/GraphicsLayerCA.h:
+        * platform/graphics/mac/GraphicsLayerCA.mm:
+        Lots of cleanup and refactoring. Main points:
+        - Layer changes are all batched, and only committed to the CA layer on syncCompositingState().
+        - Bitmask is used to store which properties have changed. More efficient than before.
+        - Simpler animation interface; simple setters are no longer confounded with animations.
+        - Refactored code that creates CA animations, and stores which animations are running.
+
+        * platform/graphics/transforms/TransformOperations.h:
+        (WebCore::TransformOperations::size):
+        (WebCore::TransformOperations::at): Useful accessors for size and indexed access.
+        
+        * rendering/RenderLayerBacking.h:
+        * rendering/RenderLayerBacking.cpp:
+        Renamed 'contentsLayer' to 'foregroundLayer' to avoid confusion with GraphicsLayer's
+        contentsLayer.
+        Adapt to GraphicsLayer's simpler animation API.
+        Pass animation pausing through to the graphics layers.
+        contentsBox() is no longer a callback via GraphicsLayerClient.
+        
+        * rendering/RenderLayerCompositor.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::setCompositingLayersNeedRebuild):
+        (WebCore::RenderLayerCompositor::scheduleSync):
+        (WebCore::RenderLayerCompositor::rebuildCompositingLayerTree):
+        scheduleViewUpdate() is no longer required. Instead, we plumb through &quot;compositingLayerSync&quot;
+        notifications, which travel up to WebKit and set up a runloop observer.
+        
</ins><span class="cx"> 2009-07-30  Jeremy Orlow  &lt;jorlow@chromium.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by David Levin.
</span></span></pre></div>
<a id="trunkWebCoreWebCorebaseexp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/WebCore.base.exp (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/WebCore.base.exp        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/WebCore.base.exp        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -697,6 +697,7 @@
</span><span class="cx"> __ZN7WebCore9FrameView18updateControlTintsEv
</span><span class="cx"> __ZN7WebCore9FrameView22setBaseBackgroundColorENS_5ColorE
</span><span class="cx"> __ZN7WebCore9FrameView23layoutIfNeededRecursiveEv
</span><ins>+__ZN7WebCore9FrameView29syncCompositingStateRecursiveEv
</ins><span class="cx"> __ZN7WebCore9FrameView29forceLayoutWithPageWidthRangeEffb
</span><span class="cx"> __ZN7WebCore9FrameView29setShouldUpdateWhileOffscreenEb
</span><span class="cx"> __ZN7WebCore9FrameView6createEPNS_5FrameE
</span></span></pre></div>
<a id="trunkWebCoreloaderEmptyClientsh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/loader/EmptyClients.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/loader/EmptyClients.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/loader/EmptyClients.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -155,7 +155,7 @@
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><span class="cx">     virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) {};
</span><span class="cx">     virtual void setNeedsOneShotDrawingSynchronization() {};
</span><del>-    virtual void scheduleViewUpdate() {};
</del><ins>+    virtual void scheduleCompositingLayerSync() {};
</ins><span class="cx"> #endif
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebCorepageChromeClienth"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/page/ChromeClient.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/page/ChromeClient.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/page/ChromeClient.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -191,7 +191,7 @@
</span><span class="cx">         virtual void setNeedsOneShotDrawingSynchronization() = 0;
</span><span class="cx">         // Sets a flag to specify that the view needs to be updated, so we need
</span><span class="cx">         // to do an eager layout before the drawing.
</span><del>-        virtual void scheduleViewUpdate() = 0;
</del><ins>+        virtual void scheduleCompositingLayerSync() = 0;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(MAC)
</span></span></pre></div>
<a id="trunkWebCorepageFrameViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/page/FrameView.cpp (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/page/FrameView.cpp        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/page/FrameView.cpp        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -439,6 +439,37 @@
</span><span class="cx"> }
</span><span class="cx"> #endif // USE(ACCELERATED_COMPOSITING)
</span><span class="cx"> 
</span><ins>+bool FrameView::syncCompositingStateRecursive()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    ASSERT(m_frame-&gt;view() == this);
+    RenderView* contentRenderer = m_frame-&gt;contentRenderer();
+    if (!contentRenderer)
+        return true;    // We don't want to keep trying to update layers if we have no renderer.
+
+    if (m_layoutTimer.isActive()) {
+        // Don't sync layers if there's a layout pending.
+        return false;
+    }
+    
+    if (GraphicsLayer* rootLayer = contentRenderer-&gt;compositor()-&gt;rootPlatformLayer())
+        rootLayer-&gt;syncCompositingState();
+
+    bool allSubframesSynced = true;
+    const HashSet&lt;RefPtr&lt;Widget&gt; &gt;* viewChildren = children();
+    HashSet&lt;RefPtr&lt;Widget&gt; &gt;::const_iterator end = viewChildren-&gt;end();
+    for (HashSet&lt;RefPtr&lt;Widget&gt; &gt;::const_iterator current = viewChildren-&gt;begin(); current != end; ++current) {
+        Widget* widget = (*current).get();
+        if (widget-&gt;isFrameView()) {
+            bool synced = static_cast&lt;FrameView*&gt;(widget)-&gt;syncCompositingStateRecursive();
+            allSubframesSynced &amp;= synced;
+        }
+    }
+    return allSubframesSynced;
+#endif // USE(ACCELERATED_COMPOSITING)
+    return true;
+}
+
</ins><span class="cx"> void FrameView::didMoveOnscreen()
</span><span class="cx"> {
</span><span class="cx">     RenderView* view = m_frame-&gt;contentRenderer();
</span><span class="lines">@@ -1443,6 +1474,13 @@
</span><span class="cx">     if (needsLayout())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+#if USE(ACCELERATED_COMPOSITING)
+    if (!p-&gt;paintingDisabled()) {
+        if (GraphicsLayer* rootLayer = contentRenderer-&gt;compositor()-&gt;rootPlatformLayer())
+            rootLayer-&gt;syncCompositingState();
+    }
+#endif
+
</ins><span class="cx">     ASSERT(!m_isPainting);
</span><span class="cx">         
</span><span class="cx">     m_isPainting = true;
</span></span></pre></div>
<a id="trunkWebCorepageFrameViewh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/page/FrameView.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/page/FrameView.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/page/FrameView.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -99,6 +99,9 @@
</span><span class="cx">     // content rendered via the normal painting path.
</span><span class="cx">     void setNeedsOneShotDrawingSynchronization();
</span><span class="cx"> #endif
</span><ins>+    // Only used with accelerated compositing, but outside the #ifdef to make linkage easier.
+    // Returns true if the sync was completed.
+    bool syncCompositingStateRecursive();
</ins><span class="cx"> 
</span><span class="cx">     void didMoveOnscreen();
</span><span class="cx">     void willMoveOffscreen();
</span></span></pre></div>
<a id="trunkWebCorepageanimationKeyframeAnimationcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/page/animation/KeyframeAnimation.cpp (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/page/animation/KeyframeAnimation.cpp        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/page/animation/KeyframeAnimation.cpp        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -211,8 +211,12 @@
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><span class="cx">         if (m_object-&gt;hasLayer()) {
</span><span class="cx">             RenderLayer* layer = toRenderBoxModelObject(m_object)-&gt;layer();
</span><del>-            if (layer-&gt;isComposited())
-                layer-&gt;backing()-&gt;animationFinished(m_keyframes.animationName(), 0, reset);
</del><ins>+            if (layer-&gt;isComposited()) {
+                if (reset)
+                    layer-&gt;backing()-&gt;animationFinished(m_keyframes.animationName());
+                else
+                    layer-&gt;backing()-&gt;animationPaused(m_keyframes.animationName());
+            }
</ins><span class="cx">         }
</span><span class="cx"> #else
</span><span class="cx">         UNUSED_PARAM(reset);
</span></span></pre></div>
<a id="trunkWebCoreplatformgraphicsFloatPoint3Dh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/platform/graphics/FloatPoint3D.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/graphics/FloatPoint3D.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/platform/graphics/FloatPoint3D.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -49,6 +49,16 @@
</span><span class="cx">     float m_z;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+inline bool operator==(const FloatPoint3D&amp; a, const FloatPoint3D&amp; b)
+{
+    return a.x() == b.x() &amp;&amp; a.y() == b.y() &amp;&amp; a.z() == b.z();
+}
+
+inline bool operator!=(const FloatPoint3D&amp; a, const FloatPoint3D&amp; b)
+{
+    return a.x() != b.x() || a.y() != b.y() || a.z() != b.z();
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // FloatPoint3D_h
</span></span></pre></div>
<a id="trunkWebCoreplatformgraphicsGraphicsLayercpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/platform/graphics/GraphicsLayer.cpp (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/graphics/GraphicsLayer.cpp        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/platform/graphics/GraphicsLayer.cpp        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -35,149 +35,26 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-void GraphicsLayer::FloatValue::set(float key, float value, const TimingFunction* timingFunction)
</del><ins>+void KeyframeValueList::insert(const AnimationValue* value)
</ins><span class="cx"> {
</span><del>-    m_key = key;
-    m_value = value;
-    if (timingFunction != m_timingFunction) {
-        if (timingFunction)
-            m_timingFunction.set(new TimingFunction(*timingFunction));
-        else
-            m_timingFunction.clear();
-    }
-}
-
-void GraphicsLayer::TransformValue::set(float key, const TransformOperations* value, const TimingFunction* timingFunction)
-{
-    m_key = key;
-    if (value != m_value) {
-        if (value)
-            m_value.set(new TransformOperations(*value));
-        else
-            m_value.clear();
-    }
-    if (timingFunction != m_timingFunction) {
-        if (timingFunction)
-            m_timingFunction.set(new TimingFunction(*timingFunction));
-        else
-            m_timingFunction.clear();
-    }
-}
-
-void GraphicsLayer::FloatValueList::insert(float key, float value, const TimingFunction* timingFunction)
-{
</del><span class="cx">     for (size_t i = 0; i &lt; m_values.size(); ++i) {
</span><del>-        FloatValue&amp; curFloatValue = m_values[i];
-        if (curFloatValue.key() == key) {
-            curFloatValue.set(key, value, timingFunction);
</del><ins>+        const AnimationValue* curValue = m_values[i];
+        if (curValue-&gt;keyTime() == value-&gt;keyTime()) {
+            ASSERT_NOT_REACHED();
+            // insert after
+            m_values.insert(i + 1, value);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        if (curFloatValue.key() &gt; key) {
</del><ins>+        if (curValue-&gt;keyTime() &gt; value-&gt;keyTime()) {
</ins><span class="cx">             // insert before
</span><del>-            m_values.insert(i, FloatValue(key, value, timingFunction));
</del><ins>+            m_values.insert(i, value);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    // append
-    m_values.append(FloatValue(key, value, timingFunction));
</del><ins>+    m_values.append(value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayer::TransformValueList::insert(float key, const TransformOperations* value, const TimingFunction* timingFunction)
-{
-    for (size_t i = 0; i &lt; m_values.size(); ++i) {
-        TransformValue&amp; curTransValue = m_values[i];
-        if (curTransValue.key() == key) {
-            curTransValue.set(key, value, timingFunction);
-            return;
-        }
-        if (curTransValue.key() &gt; key) {
-            // insert before
-            m_values.insert(i, TransformValue(key, value, timingFunction));
-            return;
-        }
-    }
-    
-    // append
-    m_values.append(TransformValue(key, value, timingFunction));
-}
-
-// An &quot;invalid&quot; list is one whose functions don't match, and therefore has to be animated as a Matrix
-// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is 
-// true if the rotation between any two keyframes is &gt;= 180 degrees.
-void GraphicsLayer::TransformValueList::makeFunctionList(FunctionList&amp; list, bool&amp; isValid, bool&amp; hasBigRotation) const
-{
-    list.clear();
-    isValid = false;
-    hasBigRotation = false;
-    
-    if (m_values.size() &lt; 2)
-        return;
-    
-    // empty transforms match anything, so find the first non-empty entry as the reference
-    size_t firstIndex = 0;
-    for ( ; firstIndex &lt; m_values.size(); ++firstIndex) {
-        if (m_values[firstIndex].value()-&gt;operations().size() &gt; 0)
-            break;
-    }
-    
-    if (firstIndex &gt;= m_values.size())
-        return;
-        
-    const TransformOperations* firstVal = m_values[firstIndex].value();
-    
-    // see if the keyframes are valid
-    for (size_t i = firstIndex + 1; i &lt; m_values.size(); ++i) {
-        const TransformOperations* val = m_values[i].value();
-        
-        // a null transform matches anything
-        if (val-&gt;operations().isEmpty())
-            continue;
-            
-        if (firstVal-&gt;operations().size() != val-&gt;operations().size())
-            return;
-            
-        for (size_t j = 0; j &lt; firstVal-&gt;operations().size(); ++j) {
-            if (!firstVal-&gt;operations().at(j)-&gt;isSameType(*val-&gt;operations().at(j)))
-                return;
-        }
-    }
-
-    // keyframes are valid, fill in the list
-    isValid = true;
-    
-    double lastRotAngle = 0.0;
-    double maxRotAngle = -1.0;
-        
-    list.resize(firstVal-&gt;operations().size());
-    for (size_t j = 0; j &lt; firstVal-&gt;operations().size(); ++j) {
-        TransformOperation::OperationType type = firstVal-&gt;operations().at(j)-&gt;getOperationType();
-        list[j] = type;
-        
-        // if this is a rotation entry, we need to see if any angle differences are &gt;= 180 deg
-        if (type == TransformOperation::ROTATE_X ||
-            type == TransformOperation::ROTATE_Y ||
-            type == TransformOperation::ROTATE_Z ||
-            type == TransformOperation::ROTATE_3D) {
-            lastRotAngle = static_cast&lt;RotateTransformOperation*&gt;(firstVal-&gt;operations().at(j).get())-&gt;angle();
-            
-            if (maxRotAngle &lt; 0)
-                maxRotAngle = fabs(lastRotAngle);
-            
-            for (size_t i = firstIndex + 1; i &lt; m_values.size(); ++i) {
-                const TransformOperations* val = m_values[i].value();
-                double rotAngle = val-&gt;operations().isEmpty() ? 0 : (static_cast&lt;RotateTransformOperation*&gt;(val-&gt;operations().at(j).get())-&gt;angle());
-                double diffAngle = fabs(rotAngle - lastRotAngle);
-                if (diffAngle &gt; maxRotAngle)
-                    maxRotAngle = diffAngle;
-                lastRotAngle = rotAngle;
-            }
-        }
-    }
-    
-    hasBigRotation = maxRotAngle &gt;= 180.0;
-}
-
</del><span class="cx"> GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
</span><span class="cx">     : m_client(client)
</span><span class="cx">     , m_anchorPoint(0.5f, 0.5f, 0)
</span><span class="lines">@@ -193,6 +70,7 @@
</span><span class="cx">     , m_masksToBounds(false)
</span><span class="cx">     , m_drawsContent(false)
</span><span class="cx">     , m_paintingPhase(GraphicsLayerPaintAllMask)
</span><ins>+    , m_geometryOrientation(CompositingCoordinatesTopDown)
</ins><span class="cx">     , m_contentsOrientation(CompositingCoordinatesTopDown)
</span><span class="cx">     , m_parent(0)
</span><span class="cx"> #ifndef NDEBUG
</span><span class="lines">@@ -203,8 +81,6 @@
</span><span class="cx"> 
</span><span class="cx"> GraphicsLayer::~GraphicsLayer()
</span><span class="cx"> {
</span><del>-    removeAllAnimations();    
-
</del><span class="cx">     removeAllChildren();
</span><span class="cx">     removeFromParent();
</span><span class="cx"> }
</span><span class="lines">@@ -316,9 +192,9 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayer::setBackgroundColor(const Color&amp; inColor, const Animation*, double /*beginTime*/)
</del><ins>+void GraphicsLayer::setBackgroundColor(const Color&amp; color)
</ins><span class="cx"> {
</span><del>-    m_backgroundColor = inColor;
</del><ins>+    m_backgroundColor = color;
</ins><span class="cx">     m_backgroundColorSet = true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -328,95 +204,12 @@
</span><span class="cx">     m_backgroundColorSet = false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool GraphicsLayer::setOpacity(float opacity, const Animation*, double)
-{
-    m_opacity = opacity;
-    return false;       // not animating
-}
-
</del><span class="cx"> void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext&amp; context, const IntRect&amp; clip)
</span><span class="cx"> {
</span><del>-    m_client-&gt;paintContents(this, context, m_paintingPhase, clip);
</del><ins>+    if (m_client)
+        m_client-&gt;paintContents(this, context, m_paintingPhase, clip);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-String GraphicsLayer::propertyIdToString(AnimatedPropertyID property)
-{
-    switch (property) {
-        case AnimatedPropertyWebkitTransform:
-            return &quot;transform&quot;;
-        case AnimatedPropertyOpacity:
-            return &quot;opacity&quot;;
-        case AnimatedPropertyBackgroundColor:
-            return &quot;backgroundColor&quot;;
-        case AnimatedPropertyInvalid:
-            ASSERT_NOT_REACHED();
-    }
-    ASSERT_NOT_REACHED();
-    return &quot;&quot;;
-}
-
-int GraphicsLayer::findAnimationEntry(AnimatedPropertyID property, short index) const
-{
-    for (size_t i = 0; i &lt; m_animations.size(); ++i) {
-        if (m_animations[i].matches(property, index))
-            return static_cast&lt;int&gt;(i);
-    }
-    return -1;
-}
-
-void GraphicsLayer::addAnimationEntry(AnimatedPropertyID property, short index, bool isTransition, const Animation* transition)
-{
-    int i = findAnimationEntry(property, index);
-    
-    if (i &gt;= 0)
-        m_animations[i].reset(transition, isTransition);
-    else
-        m_animations.append(AnimationEntry(transition, property, index, isTransition));
-}
-
-void GraphicsLayer::removeAllAnimations()
-{
-    size_t size = m_animations.size();
-    for (size_t i = 0; i &lt; size; ++i)
-        removeAnimation(0, true);
-}
-
-void GraphicsLayer::removeAllAnimationsForProperty(AnimatedPropertyID property)
-{
-    for (short j = 0; ; ++j) {
-        int i = findAnimationEntry(property, j);
-        if (i &lt; 0)
-            break;
-        removeAnimation(i, false);
-    }
-}
-
-void GraphicsLayer::removeFinishedAnimations(const String&amp; name, int /*index*/, bool reset)
-{
-    size_t size = m_animations.size();
-    for (size_t i = 0; i &lt; size; ) {
-        AnimationEntry&amp; anim = m_animations[i];
-        if (!anim.isTransition() &amp;&amp; anim.animation()-&gt;name() == name) {
-            removeAnimation(i, reset);
-            --size;
-        } else
-            ++i;
-    }
-}
-
-void GraphicsLayer::removeFinishedTransitions(AnimatedPropertyID property)
-{
-    size_t size = m_animations.size();
-    for (size_t i = 0; i &lt; size; ) {
-        AnimationEntry&amp; anim = m_animations[i];
-        if (anim.isTransition() &amp;&amp; property == anim.property()) {
-            removeAnimation(i, false);
-            --size;
-        } else
-            ++i;
-    }
-}
-
</del><span class="cx"> void GraphicsLayer::suspendAnimations()
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="lines">@@ -474,6 +267,91 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// An &quot;invalid&quot; list is one whose functions don't match, and therefore has to be animated as a Matrix
+// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is 
+// true if the rotation between any two keyframes is &gt;= 180 degrees.
+
+static inline const TransformOperations* operationsAt(const KeyframeValueList&amp; valueList, size_t index)
+{
+    return static_cast&lt;const TransformAnimationValue*&gt;(valueList.at(index))-&gt;value();
+}
+
+void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList&amp; valueList, TransformOperationList&amp; list, bool&amp; isValid, bool&amp; hasBigRotation)
+{
+    ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
+
+    list.clear();
+    isValid = false;
+    hasBigRotation = false;
+    
+    if (valueList.size() &lt; 2)
+        return;
+    
+    // Empty transforms match anything, so find the first non-empty entry as the reference.
+    size_t firstIndex = 0;
+    for ( ; firstIndex &lt; valueList.size(); ++firstIndex) {
+        if (operationsAt(valueList, firstIndex)-&gt;operations().size() &gt; 0)
+            break;
+    }
+    
+    if (firstIndex &gt;= valueList.size())
+        return;
+        
+    const TransformOperations* firstVal = operationsAt(valueList, firstIndex);
+    
+    // See if the keyframes are valid.
+    for (size_t i = firstIndex + 1; i &lt; valueList.size(); ++i) {
+        const TransformOperations* val = operationsAt(valueList, i);
+        
+        // a null transform matches anything
+        if (val-&gt;operations().isEmpty())
+            continue;
+            
+        if (firstVal-&gt;operations().size() != val-&gt;operations().size())
+            return;
+            
+        for (size_t j = 0; j &lt; firstVal-&gt;operations().size(); ++j) {
+            if (!firstVal-&gt;operations().at(j)-&gt;isSameType(*val-&gt;operations().at(j)))
+                return;
+        }
+    }
+
+    // Keyframes are valid, fill in the list.
+    isValid = true;
+    
+    double lastRotAngle = 0.0;
+    double maxRotAngle = -1.0;
+        
+    list.resize(firstVal-&gt;operations().size());
+    for (size_t j = 0; j &lt; firstVal-&gt;operations().size(); ++j) {
+        TransformOperation::OperationType type = firstVal-&gt;operations().at(j)-&gt;getOperationType();
+        list[j] = type;
+        
+        // if this is a rotation entry, we need to see if any angle differences are &gt;= 180 deg
+        if (type == TransformOperation::ROTATE_X ||
+            type == TransformOperation::ROTATE_Y ||
+            type == TransformOperation::ROTATE_Z ||
+            type == TransformOperation::ROTATE_3D) {
+            lastRotAngle = static_cast&lt;RotateTransformOperation*&gt;(firstVal-&gt;operations().at(j).get())-&gt;angle();
+            
+            if (maxRotAngle &lt; 0)
+                maxRotAngle = fabs(lastRotAngle);
+            
+            for (size_t i = firstIndex + 1; i &lt; valueList.size(); ++i) {
+                const TransformOperations* val = operationsAt(valueList, i);
+                double rotAngle = val-&gt;operations().isEmpty() ? 0 : (static_cast&lt;RotateTransformOperation*&gt;(val-&gt;operations().at(j).get())-&gt;angle());
+                double diffAngle = fabs(rotAngle - lastRotAngle);
+                if (diffAngle &gt; maxRotAngle)
+                    maxRotAngle = diffAngle;
+                lastRotAngle = rotAngle;
+            }
+        }
+    }
+    
+    hasBigRotation = maxRotAngle &gt;= 180.0;
+}
+
+
</ins><span class="cx"> static void writeIndent(TextStream&amp; ts, int indent)
</span><span class="cx"> {
</span><span class="cx">     for (int i = 0; i != indent; ++i)
</span></span></pre></div>
<a id="trunkWebCoreplatformgraphicsGraphicsLayerh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/platform/graphics/GraphicsLayer.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/graphics/GraphicsLayer.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/platform/graphics/GraphicsLayer.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;FloatPoint3D.h&quot;
</span><span class="cx"> #include &quot;FloatSize.h&quot;
</span><span class="cx"> #include &quot;GraphicsLayerClient.h&quot;
</span><ins>+#include &quot;IntRect.h&quot;
</ins><span class="cx"> #include &quot;TransformationMatrix.h&quot;
</span><span class="cx"> #include &quot;TransformOperations.h&quot;
</span><span class="cx"> #include &lt;wtf/OwnPtr.h&gt;
</span><span class="lines">@@ -42,7 +43,7 @@
</span><span class="cx"> #ifdef __OBJC__
</span><span class="cx"> @class WebLayer;
</span><span class="cx"> @class CALayer;
</span><del>-typedef WebLayer PlatformLayer;
</del><ins>+typedef CALayer PlatformLayer;
</ins><span class="cx"> typedef CALayer* NativeLayer;
</span><span class="cx"> #else
</span><span class="cx"> typedef void* PlatformLayer;
</span><span class="lines">@@ -61,118 +62,96 @@
</span><span class="cx"> class TextStream;
</span><span class="cx"> class TimingFunction;
</span><span class="cx"> 
</span><del>-// GraphicsLayer is an abstraction for a rendering surface with backing store,
-// which may have associated transformation and animations.
-
-class GraphicsLayer {
</del><ins>+// Base class for animation values (also used for transitions). Here to
+// represent values for properties being animated via the GraphicsLayer,
+// without pulling in style-related data from outside of the platform directory.
+class AnimationValue : public Noncopyable {
</ins><span class="cx"> public:
</span><del>-    // Used to store one float value of a keyframe animation.
-    class FloatValue {
-    public:
-        FloatValue(float key, float value, const TimingFunction* timingFunction = 0)
-            : m_key(key), m_value(value), m_timingFunction(0)
-        {
-            if (timingFunction)
-                m_timingFunction.set(new TimingFunction(*timingFunction));
-        }
</del><ins>+    AnimationValue(float keyTime, const TimingFunction* timingFunction = 0)
+        : m_keyTime(keyTime)
+        , m_timingFunction(0)
+    {
+        if (timingFunction)
+            m_timingFunction.set(new TimingFunction(*timingFunction));
+    }
+    
+    virtual ~AnimationValue() { }
</ins><span class="cx"> 
</span><del>-        FloatValue(const FloatValue&amp; other)
-            : m_key(other.key()), m_value(other.value()), m_timingFunction(0)
-        {
-            if (other.timingFunction())
-                m_timingFunction.set(new TimingFunction(*other.timingFunction()));
-        }
</del><ins>+    float keyTime() const { return m_keyTime; }
+    const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
</ins><span class="cx"> 
</span><del>-        const FloatValue&amp; operator=(const FloatValue&amp; other)
-        {
-            if (&amp;other != this)
-                set(other.key(), other.value(), other.timingFunction());
-            return *this;
-        }
</del><ins>+private:
+    float m_keyTime;
+    OwnPtr&lt;TimingFunction&gt; m_timingFunction;
+};
</ins><span class="cx"> 
</span><del>-        void set(float key, float value, const TimingFunction*);
-        
-        float key() const { return m_key; }
-        float value() const { return m_value; }
-        const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
</del><ins>+// Used to store one float value of an animation.
+class FloatAnimationValue : public AnimationValue {
+public:
+    FloatAnimationValue(float keyTime, float value, const TimingFunction* timingFunction = 0)
+        : AnimationValue(keyTime, timingFunction)
+        , m_value(value)
+    {
+    }
</ins><span class="cx"> 
</span><del>-    private:
-        float m_key;
-        float m_value;
-        OwnPtr&lt;TimingFunction&gt; m_timingFunction;
-    };
-    
-    
-    class FloatValueList {
-    public:
-        void insert(float key, float value, const TimingFunction* timingFunction);
</del><ins>+    float value() const { return m_value; }
</ins><span class="cx"> 
</span><del>-        size_t size() const { return m_values.size(); }
-        const FloatValue&amp; at(size_t i) const { return m_values.at(i); }
-        const Vector&lt;FloatValue&gt;&amp; values() const { return m_values; }
</del><ins>+private:
+    float m_value;
+};
</ins><span class="cx"> 
</span><del>-    private:
-        Vector&lt;FloatValue&gt; m_values;
-    };
</del><ins>+// Used to store one transform value in a keyframe list.
+class TransformAnimationValue : public AnimationValue {
+public:
+    TransformAnimationValue(float keyTime, const TransformOperations* value = 0, const TimingFunction* timingFunction = 0)
+        : AnimationValue(keyTime, timingFunction)
+    {
+        if (value)
+            m_value.set(new TransformOperations(*value));
+    }
</ins><span class="cx"> 
</span><del>-    // Used to store one transform in a keyframe list.
-    class TransformValue {
-    public:
-        TransformValue(float key = NAN, const TransformOperations* value = 0, const TimingFunction* timingFunction = 0)
-            : m_key(key)
-        {
-            if (value)
-                m_value.set(new TransformOperations(*value));
-            if (timingFunction)
-                m_timingFunction.set(new TimingFunction(*timingFunction));
-        }
</del><ins>+    const TransformOperations* value() const { return m_value.get(); }
</ins><span class="cx"> 
</span><del>-        TransformValue(const TransformValue&amp; other)
-            : m_key(other.key())
-        {
-            if (other.value())
-                m_value.set(new TransformOperations(*other.value()));
-            if (other.timingFunction())
-                m_timingFunction.set(new TimingFunction(*other.timingFunction()));
-        }
</del><ins>+private:
+    OwnPtr&lt;TransformOperations&gt; m_value;
+};
</ins><span class="cx"> 
</span><del>-        const TransformValue&amp; operator=(const TransformValue&amp; other)
-        {
-            if (&amp;other != this)
-                set(other.key(), other.value(), other.timingFunction());
-            return *this;
-        }
</del><ins>+// Used to store a series of values in a keyframe list. Values will all be of the same type,
+// which can be inferred from the property.
+class KeyframeValueList : public Noncopyable {
+public:
</ins><span class="cx"> 
</span><del>-        void set(float key, const TransformOperations* value, const TimingFunction* timingFunction);
</del><ins>+    KeyframeValueList(AnimatedPropertyID property)
+        : m_property(property)
+    {
+    }
+    
+    ~KeyframeValueList()
+    {
+        deleteAllValues(m_values);
+    }
+    
+    AnimatedPropertyID property() const { return m_property; }
</ins><span class="cx"> 
</span><del>-        float key() const { return m_key; }
-        const TransformOperations* value() const { return m_value.get(); }
-        const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
-        
-    private:
-        float m_key;
-        OwnPtr&lt;TransformOperations&gt; m_value;
-        OwnPtr&lt;TimingFunction&gt; m_timingFunction;
-    };
</del><ins>+    size_t size() const { return m_values.size(); }
+    const AnimationValue* at(size_t i) const { return m_values.at(i); }
</ins><span class="cx">     
</span><del>-    // Used to store a series of transforms in a keyframe list.
-    class TransformValueList {
-    public:
-        typedef Vector&lt;TransformOperation::OperationType&gt; FunctionList;
</del><ins>+    // Insert, sorted by keyTime. Takes ownership of the pointer.
+    void insert(const AnimationValue*);
+    
+protected:
+    Vector&lt;const AnimationValue*&gt; m_values;
+    AnimatedPropertyID m_property;
+};
</ins><span class="cx"> 
</span><del>-        size_t size() const { return m_values.size(); }
-        const TransformValue&amp; at(size_t i) const { return m_values.at(i); }
-        const Vector&lt;TransformValue&gt;&amp; values() const { return m_values; }
-        
-        void insert(float key, const TransformOperations* value, const TimingFunction* timingFunction);
-        
-        // return a list of the required functions. List is empty if keyframes are not valid
-        // If return value is true, functions contain rotations of &gt;= 180 degrees
-        void makeFunctionList(FunctionList&amp; list, bool&amp; isValid, bool&amp; hasBigRotation) const;
-    private:
-        Vector&lt;TransformValue&gt; m_values;
-    };
</del><span class="cx"> 
</span><ins>+
+// GraphicsLayer is an abstraction for a rendering surface with backing store,
+// which may have associated transformation and animations.
+
+class GraphicsLayer {
+public:
+
</ins><span class="cx">     static GraphicsLayer* createGraphicsLayer(GraphicsLayerClient*);
</span><span class="cx">     
</span><span class="cx">     virtual ~GraphicsLayer();
</span><span class="lines">@@ -235,7 +214,7 @@
</span><span class="cx"> 
</span><span class="cx">     // The color used to paint the layer backgrounds
</span><span class="cx">     const Color&amp; backgroundColor() const { return m_backgroundColor; }
</span><del>-    virtual void setBackgroundColor(const Color&amp;, const Animation* = 0, double beginTime = 0);
</del><ins>+    virtual void setBackgroundColor(const Color&amp;);
</ins><span class="cx">     virtual void clearBackgroundColor();
</span><span class="cx">     bool backgroundColorSet() const { return m_backgroundColorSet; }
</span><span class="cx"> 
</span><span class="lines">@@ -247,8 +226,7 @@
</span><span class="cx">     virtual void setBackfaceVisibility(bool b) { m_backfaceVisibility = b; }
</span><span class="cx"> 
</span><span class="cx">     float opacity() const { return m_opacity; }
</span><del>-    // return true if we started an animation
-    virtual bool setOpacity(float o, const Animation* = 0, double beginTime = 0);
</del><ins>+    virtual void setOpacity(float opacity) { m_opacity = opacity; }
</ins><span class="cx"> 
</span><span class="cx">     // Some GraphicsLayers paint only the foreground or the background content
</span><span class="cx">     GraphicsLayerPaintingPhase drawingPhase() const { return m_paintingPhase; }
</span><span class="lines">@@ -258,13 +236,17 @@
</span><span class="cx">     // mark the given rect (in layer coords) as needing dispay. Never goes deep.
</span><span class="cx">     virtual void setNeedsDisplayInRect(const FloatRect&amp;) = 0;
</span><span class="cx"> 
</span><del>-    virtual bool animateTransform(const TransformValueList&amp;, const IntSize&amp;, const Animation*, double beginTime, bool isTransition) = 0;
-    virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&amp;, const Animation*, double beginTime) = 0;
</del><ins>+    // Set that the position/size of the contents (image or video).
+    IntRect contentsRect() const { return m_contentsRect; }
+    virtual void setContentsRect(const IntRect&amp; r) { m_contentsRect = r; }
</ins><span class="cx">     
</span><del>-    void removeFinishedAnimations(const String&amp; name, int index, bool reset);
-    void removeFinishedTransitions(AnimatedPropertyID);
-    void removeAllAnimations();
-
</del><ins>+    // Return true if the animation is handled by the compositing system. If this returns
+    // false, the animation will be run by AnimationController.
+    virtual bool addAnimation(const KeyframeValueList&amp;, const IntSize&amp; /*boxSize*/, const Animation*, const String&amp; /*keyframesName*/, double /*beginTime*/) { return false; }
+    virtual void removeAnimationsForProperty(AnimatedPropertyID) { }
+    virtual void removeAnimationsForKeyframes(const String&amp; /* keyframesName */) { }
+    virtual void pauseAnimation(const String&amp; /* keyframesName */) { }
+    
</ins><span class="cx">     virtual void suspendAnimations();
</span><span class="cx">     virtual void resumeAnimations();
</span><span class="cx">     
</span><span class="lines">@@ -272,10 +254,7 @@
</span><span class="cx">     virtual void setContentsToImage(Image*) { }
</span><span class="cx">     virtual void setContentsToVideo(PlatformLayer*) { }
</span><span class="cx">     virtual void setContentsBackgroundColor(const Color&amp;) { }
</span><del>-    virtual void clearContents() { }
</del><span class="cx">     
</span><del>-    virtual void updateContentsRect() { }
-
</del><span class="cx">     // Callback from the underlying graphics system to draw layer contents.
</span><span class="cx">     void paintGraphicsLayerContents(GraphicsContext&amp;, const IntRect&amp; clip);
</span><span class="cx">     
</span><span class="lines">@@ -294,12 +273,12 @@
</span><span class="cx">     static CompositingCoordinatesOrientation compositingCoordinatesOrientation();
</span><span class="cx"> 
</span><span class="cx">     // Set the geometry orientation (top-down, or bottom-up) for this layer, which also controls sublayer geometry.
</span><del>-    virtual void setGeometryOrientation(CompositingCoordinatesOrientation) { }
-    virtual CompositingCoordinatesOrientation geometryOrientation() const { return CompositingCoordinatesTopDown; }
</del><ins>+    virtual void setGeometryOrientation(CompositingCoordinatesOrientation orientation) { m_geometryOrientation = orientation; }
+    CompositingCoordinatesOrientation geometryOrientation() const { return m_geometryOrientation; }
</ins><span class="cx"> 
</span><span class="cx">     // Flippedness of the contents of this layer. Does not affect sublayer geometry.
</span><span class="cx">     virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; }
</span><del>-    virtual CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; }
</del><ins>+    CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; }
</ins><span class="cx"> 
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     static bool showDebugBorders();
</span><span class="lines">@@ -314,25 +293,26 @@
</span><span class="cx">     virtual void setZPosition(float);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    static String propertyIdToString(AnimatedPropertyID);
-    
</del><span class="cx">     virtual void distributeOpacity(float);
</span><span class="cx">     virtual float accumulatedOpacity() const;
</span><span class="cx"> 
</span><ins>+    // Some compositing systems may do internal batching to synchronize compositing updates
+    // with updates drawn into the window. This is a signal to flush any internal batched state.
+    virtual void syncCompositingState() { }
+
</ins><span class="cx"> protected:
</span><ins>+
+    typedef Vector&lt;TransformOperation::OperationType&gt; TransformOperationList;
+    // Given a list of TransformAnimationValues, return an array of transform operations.
+    // On return, if hasBigRotation is true, functions contain rotations of &gt;= 180 degrees
+    static void fetchTransformOperationList(const KeyframeValueList&amp;, TransformOperationList&amp;, bool&amp; isValid, bool&amp; hasBigRotation);
+
</ins><span class="cx">     virtual void setOpacityInternal(float) { }
</span><span class="cx">     
</span><span class="cx">     GraphicsLayer(GraphicsLayerClient*);
</span><span class="cx"> 
</span><span class="cx">     void dumpProperties(TextStream&amp;, int indent) const;
</span><span class="cx"> 
</span><del>-    // returns -1 if not found
-    int findAnimationEntry(AnimatedPropertyID, short index) const;
-    void addAnimationEntry(AnimatedPropertyID, short index, bool isTransition, const Animation*);
-
-    virtual void removeAnimation(int /*index*/, bool /*reset*/) {}
-    void removeAllAnimationsForProperty(AnimatedPropertyID);
-
</del><span class="cx">     GraphicsLayerClient* m_client;
</span><span class="cx">     String m_name;
</span><span class="cx">     
</span><span class="lines">@@ -361,54 +341,14 @@
</span><span class="cx">     bool m_drawsContent : 1;
</span><span class="cx"> 
</span><span class="cx">     GraphicsLayerPaintingPhase m_paintingPhase;
</span><del>-    CompositingCoordinatesOrientation m_contentsOrientation;
</del><ins>+    CompositingCoordinatesOrientation m_geometryOrientation;    // affects geometry of layer positions
+    CompositingCoordinatesOrientation m_contentsOrientation;    // affects orientation of layer contents
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;GraphicsLayer*&gt; m_children;
</span><span class="cx">     GraphicsLayer* m_parent;
</span><del>-    
-    // AnimationEntry represents an animation of a property on this layer.
-    // For transform only, there may be more than one, in which case 'index'
-    // is an index into the list of transforms. 
-    class AnimationEntry {
-    public:
-        AnimationEntry(const Animation* animation, AnimatedPropertyID property, short index, bool isTransition)
-            : m_animation(const_cast&lt;Animation*&gt;(animation))
-            , m_property(property)
-            , m_index(index)
-            , m_isCurrent(true)
-            , m_isTransition(isTransition)
-        {
-        }
-        
-        const Animation* animation() const { return m_animation.get(); }
-        AnimatedPropertyID property() const { return m_property; }
-        int index() const { return m_index; }
-        bool isCurrent() const { return m_isCurrent; }
-        void setIsCurrent(bool b = true) { m_isCurrent = b; }
-        bool isTransition() const { return m_isTransition; }
</del><span class="cx"> 
</span><del>-        bool matches(AnimatedPropertyID property, short index) const
-        {
-            return m_property == property &amp;&amp; m_index == index;
-        }
-        
-        void reset(const Animation* animation, bool isTransition)
-        {
-            m_animation = const_cast&lt;Animation*&gt;(animation);
-            m_isTransition = isTransition;
-            m_isCurrent = true;
-        }
-    
-    private:
-        RefPtr&lt;Animation&gt; m_animation;
-        AnimatedPropertyID m_property : 14;
-        short m_index : 16;
-        bool m_isCurrent : 1;
-        bool m_isTransition : 1;
-    };
-    
-    Vector&lt;AnimationEntry&gt; m_animations;      // running animations/transitions
-    
</del><ins>+    IntRect m_contentsRect;
+
</ins><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     int m_repaintCount;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkWebCoreplatformgraphicsGraphicsLayerClienth"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/platform/graphics/GraphicsLayerClient.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/graphics/GraphicsLayerClient.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/platform/graphics/GraphicsLayerClient.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -53,13 +53,14 @@
</span><span class="cx"> public:
</span><span class="cx">     virtual ~GraphicsLayerClient() {}
</span><span class="cx"> 
</span><del>-    // Callbacks for when hardware-accelerated transitions and animation started
</del><ins>+    // Callback for when hardware-accelerated animation started.
</ins><span class="cx">     virtual void notifyAnimationStarted(const GraphicsLayer*, double time) = 0;
</span><ins>+
+    // Notification that a layer property changed that requires a subsequent call to syncCompositingState()
+    // to appear on the screen.
+    virtual void notifySyncRequired(const GraphicsLayer*) = 0;
</ins><span class="cx">     
</span><span class="cx">     virtual void paintContents(const GraphicsLayer*, GraphicsContext&amp;, GraphicsLayerPaintingPhase, const IntRect&amp; inClip) = 0;
</span><del>-
-    // Return a rect for the &quot;contents&quot; of the graphics layer, i.e. video or image content, in GraphicsLayer coordinates.
-    virtual IntRect contentsBox(const GraphicsLayer*) = 0;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkWebCoreplatformgraphicsmacGraphicsLayerCAh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -29,8 +29,15 @@
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;GraphicsLayer.h&quot;
</span><ins>+#include &quot;StringHash.h&quot;
+#include &lt;wtf/HashSet.h&gt;
</ins><span class="cx"> #include &lt;wtf/RetainPtr.h&gt;
</span><span class="cx"> 
</span><ins>+@class CABasicAnimation;
+@class CAKeyframeAnimation;
+@class CALayer;
+@class CAMediaTimingFunction;
+@class CAPropertyAnimation;
</ins><span class="cx"> @class WebAnimationDelegate;
</span><span class="cx"> @class WebLayer;
</span><span class="cx"> 
</span><span class="lines">@@ -67,77 +74,192 @@
</span><span class="cx">     virtual void setMasksToBounds(bool);
</span><span class="cx">     virtual void setDrawsContent(bool);
</span><span class="cx"> 
</span><del>-    virtual void setBackgroundColor(const Color&amp;, const Animation* anim = 0, double beginTime = 0);
</del><ins>+    virtual void setBackgroundColor(const Color&amp;);
</ins><span class="cx">     virtual void clearBackgroundColor();
</span><span class="cx"> 
</span><span class="cx">     virtual void setContentsOpaque(bool);
</span><span class="cx">     virtual void setBackfaceVisibility(bool);
</span><span class="cx"> 
</span><span class="cx">     // return true if we started an animation
</span><del>-    virtual bool setOpacity(float, const Animation* anim = 0, double beginTime = 0);
</del><ins>+    virtual void setOpacity(float);
</ins><span class="cx"> 
</span><span class="cx">     virtual void setNeedsDisplay();
</span><span class="cx">     virtual void setNeedsDisplayInRect(const FloatRect&amp;);
</span><span class="cx"> 
</span><ins>+    virtual void setContentsRect(const IntRect&amp;);
+    
</ins><span class="cx">     virtual void suspendAnimations();
</span><span class="cx">     virtual void resumeAnimations();
</span><span class="cx"> 
</span><del>-    virtual bool animateTransform(const TransformValueList&amp;, const IntSize&amp;, const Animation*, double beginTime, bool isTransition);
-    virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&amp;, const Animation*, double beginTime);
-
</del><ins>+    virtual bool addAnimation(const KeyframeValueList&amp;, const IntSize&amp; boxSize, const Animation*, const String&amp; keyframesName, double beginTime);
+    virtual void removeAnimationsForProperty(AnimatedPropertyID);
+    virtual void removeAnimationsForKeyframes(const String&amp; keyframesName);
+    virtual void pauseAnimation(const String&amp; keyframesName);
+    
</ins><span class="cx">     virtual void setContentsToImage(Image*);
</span><span class="cx">     virtual void setContentsToVideo(PlatformLayer*);
</span><del>-    virtual void clearContents();
</del><span class="cx">     
</span><del>-    virtual void updateContentsRect();
-
</del><span class="cx">     virtual PlatformLayer* platformLayer() const;
</span><span class="cx"> 
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     virtual void setDebugBackgroundColor(const Color&amp;);
</span><span class="cx">     virtual void setDebugBorder(const Color&amp;, float borderWidth);
</span><del>-    virtual void setZPosition(float);
</del><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     virtual void setGeometryOrientation(CompositingCoordinatesOrientation);
</span><del>-    virtual CompositingCoordinatesOrientation geometryOrientation() const;
</del><span class="cx"> 
</span><ins>+    void recursiveCommitChanges();
+    void commitLayerChanges();
+
+    virtual void syncCompositingState();
+
</ins><span class="cx"> protected:
</span><span class="cx">     virtual void setOpacityInternal(float);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     void updateOpacityOnLayer();
</span><span class="cx"> 
</span><del>-    WebLayer* primaryLayer() const  { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
</del><ins>+    WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
</ins><span class="cx">     WebLayer* hostLayerForSublayers() const;
</span><span class="cx">     WebLayer* layerForSuperlayer() const;
</span><ins>+    CALayer* animatedLayer(AnimatedPropertyID property) const;
</ins><span class="cx"> 
</span><del>-    WebLayer* animatedLayer(AnimatedPropertyID property) const
</del><ins>+    bool createAnimationFromKeyframes(const KeyframeValueList&amp;, const Animation*, const String&amp; keyframesName, double beginTime);
+    bool createTransformAnimationsFromKeyframes(const KeyframeValueList&amp;, const Animation*, const String&amp; keyframesName, double beginTime, const IntSize&amp; boxSize);
+
+    // Return autoreleased animation (use RetainPtr?)
+    CABasicAnimation* createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive);
+    CAKeyframeAnimation* createKeyframeAnimation(const Animation*, AnimatedPropertyID, bool additive);
+    void setupAnimation(CAPropertyAnimation*, const Animation*, bool additive);
+    
+    CAMediaTimingFunction* timingFunctionForAnimationValue(const AnimationValue*, const Animation*);
+    
+    bool setAnimationEndpoints(const KeyframeValueList&amp;, const Animation*, CABasicAnimation*);
+    bool setAnimationKeyframes(const KeyframeValueList&amp;, const Animation*, CAKeyframeAnimation*);
+
+    bool setTransformAnimationEndpoints(const KeyframeValueList&amp;, const Animation*, CABasicAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize&amp; boxSize);
+    bool setTransformAnimationKeyframes(const KeyframeValueList&amp;, const Animation*, CAKeyframeAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize&amp; boxSize);
+    
+    bool animationIsRunning(const String&amp; keyframesName) const
</ins><span class="cx">     {
</span><del>-        return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
</del><ins>+        return m_runningKeyframeAnimations.find(keyframesName) != m_runningKeyframeAnimations.end();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void setBasicAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation*, double time);
-    void setKeyframeAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* keys, void* values, void* timingFunctions, bool isTransition, const Animation*, double time);
-
-    virtual void removeAnimation(int index, bool reset);
-
</del><span class="cx">     bool requiresTiledLayer(const FloatSize&amp;) const;
</span><span class="cx">     void swapFromOrToTiledLayer(bool useTiledLayer);
</span><span class="cx"> 
</span><span class="cx">     CompositingCoordinatesOrientation defaultContentsOrientation() const;
</span><span class="cx">     void updateContentsTransform();
</span><span class="cx">     
</span><del>-    void setContentsLayer(WebLayer*);
-    WebLayer* contentsLayer() const { return m_contentsLayer.get(); }
</del><ins>+    void setupContentsLayer(CALayer*);
+    CALayer* contentsLayer() const { return m_contentsLayer.get(); }
</ins><span class="cx">     
</span><ins>+    // All these &quot;update&quot; methods will be called inside a BEGIN_BLOCK_OBJC_EXCEPTIONS/END_BLOCK_OBJC_EXCEPTIONS block.
+    void updateSublayerList();
+    void updateLayerPosition();
+    void updateLayerSize();
+    void updateAnchorPoint();
+    void updateTransform();
+    void updateChildrenTransform();
+    void updateMasksToBounds();
+    void updateContentsOpaque();
+    void updateBackfaceVisibility();
+    void updateLayerPreserves3D();
+    void updateLayerDrawsContent();
+    void updateLayerBackgroundColor();
+
+    void updateContentsImage();
+    void updateContentsVideo();
+    void updateContentsRect();
+    void updateGeometryOrientation();
+
+    void updateLayerAnimations();
+
+    void setAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, int index, double beginTime);
+    bool removeAnimationFromLayer(AnimatedPropertyID, int index);
+    void pauseAnimationOnLayer(AnimatedPropertyID, int index);
+
+    enum LayerChange {
+        NoChange = 0,
+        NameChanged = 1 &lt;&lt; 1,
+        ChildrenChanged = 1 &lt;&lt; 2,   // also used for content layer, and preserves-3d, and size if tiling changes?
+        PositionChanged = 1 &lt;&lt; 3,
+        AnchorPointChanged = 1 &lt;&lt; 4,
+        SizeChanged = 1 &lt;&lt; 5,
+        TransformChanged = 1 &lt;&lt; 6,
+        ChildrenTransformChanged = 1 &lt;&lt; 7,
+        Preserves3DChanged = 1 &lt;&lt; 8,
+        MasksToBoundsChanged = 1 &lt;&lt; 9,
+        DrawsContentChanged = 1 &lt;&lt; 10,  // need this?
+        BackgroundColorChanged = 1 &lt;&lt; 11,
+        ContentsOpaqueChanged = 1 &lt;&lt; 12,
+        BackfaceVisibilityChanged = 1 &lt;&lt; 13,
+        OpacityChanged = 1 &lt;&lt; 14,
+        AnimationChanged = 1 &lt;&lt; 15,
+        DirtyRectsChanged = 1 &lt;&lt; 16,
+        ContentsImageChanged = 1 &lt;&lt; 17,
+        ContentsVideoChanged = 1 &lt;&lt; 18,
+        ContentsRectChanged = 1 &lt;&lt; 19,
+        GeometryOrientationChanged = 1 &lt;&lt; 20
+    };
+    typedef unsigned LayerChangeFlags;
+    void noteLayerPropertyChanged(LayerChangeFlags flags);
+
+    void repaintLayerDirtyRects();
+
</ins><span class="cx">     RetainPtr&lt;WebLayer&gt; m_layer;
</span><span class="cx">     RetainPtr&lt;WebLayer&gt; m_transformLayer;
</span><del>-    RetainPtr&lt;WebLayer&gt; m_contentsLayer;
</del><ins>+    RetainPtr&lt;CALayer&gt; m_contentsLayer;
+    
+    enum ContentsLayerPurpose {
+        NoContentsLayer = 0,
+        ContentsLayerForImage,
+        ContentsLayerForVideo
+    };
+    
+    ContentsLayerPurpose m_contentsLayerPurpose;
+    bool m_contentsLayerHasBackgroundColor : 1;
</ins><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;WebAnimationDelegate&gt; m_animationDelegate;
</span><span class="cx"> 
</span><del>-    bool m_contentLayerForImageOrVideo;
</del><ins>+    RetainPtr&lt;CGImageRef&gt; m_pendingContentsImage;
+    
+    struct LayerAnimation {
+        LayerAnimation(CAPropertyAnimation* caAnim, const String&amp; keyframesName, AnimatedPropertyID property, int index, double beginTime)
+        : m_animation(caAnim)
+        , m_keyframesName(keyframesName)
+        , m_property(property)
+        , m_index(index)
+        , m_beginTime(beginTime)
+        { }
+
+        RetainPtr&lt;CAPropertyAnimation*&gt; m_animation;
+        String m_keyframesName;
+        AnimatedPropertyID m_property;
+        int m_index;
+        double m_beginTime;
+    };
+    
+    Vector&lt;LayerAnimation&gt; m_uncomittedAnimations;
+    
+    // Animations on the layer are identified by property + index.
+    typedef int AnimatedProperty;   // std containers choke on the AnimatedPropertyID enum
+    typedef pair&lt;AnimatedProperty, int&gt; AnimationPair;
+
+    HashSet&lt;AnimatedProperty&gt; m_transitionPropertiesToRemove;
+    
+    enum { Remove, Pause };
+    typedef int AnimationProcessingAction;
+    typedef HashMap&lt;String, AnimationProcessingAction&gt; AnimationsToProcessMap;
+    AnimationsToProcessMap m_keyframeAnimationsToProcess;
+
+    // Map of keyframe names to their associated lists of animations for running animations, so we can remove/pause them.
+    typedef HashMap&lt;String, Vector&lt;AnimationPair&gt; &gt; KeyframeAnimationsMap;
+    KeyframeAnimationsMap m_runningKeyframeAnimations;
+    
+    Vector&lt;FloatRect&gt; m_dirtyRects;
+    
+    LayerChangeFlags m_uncommittedChanges;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkWebCoreplatformgraphicsmacGraphicsLayerCAmm"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.mm (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.mm        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/platform/graphics/mac/GraphicsLayerCA.mm        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> #import &quot;TranslateTransformOperation.h&quot;
</span><span class="cx"> #import &quot;WebLayer.h&quot;
</span><span class="cx"> #import &quot;WebTiledLayer.h&quot;
</span><ins>+#import &lt;limits.h&gt;
</ins><span class="cx"> #import &lt;wtf/CurrentTime.h&gt;
</span><span class="cx"> #import &lt;wtf/UnusedParam.h&gt;
</span><span class="cx"> #import &lt;wtf/RetainPtr.h&gt;
</span><span class="lines">@@ -81,8 +82,6 @@
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><del>-static NSString* const WebAnimationCSSPropertyKey = @&quot;GraphicsLayerCA_property&quot;;
-
</del><span class="cx"> @interface WebAnimationDelegate : NSObject {
</span><span class="cx">     WebCore::GraphicsLayerCA* m_graphicsLayer;
</span><span class="cx"> }
</span><span class="lines">@@ -138,27 +137,25 @@
</span><span class="cx">     toT3D.m44 = narrowPrecisionToFloat(t.m44());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue&amp; transformValue, size_t index, const IntSize&amp; size, TransformOperation::OperationType transformType)
</del><ins>+static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize&amp; size)
</ins><span class="cx"> {
</span><del>-    TransformOperation* op = (index &gt;= transformValue.value()-&gt;operations().size()) ? 0 : transformValue.value()-&gt;operations()[index].get();
-    
</del><span class="cx">     switch (transformType) {
</span><span class="cx">         case TransformOperation::ROTATE:
</span><span class="cx">         case TransformOperation::ROTATE_X:
</span><span class="cx">         case TransformOperation::ROTATE_Y:
</span><del>-            return [NSNumber numberWithDouble:op ? deg2rad(static_cast&lt;RotateTransformOperation*&gt;(op)-&gt;angle()) : 0];
</del><ins>+            return [NSNumber numberWithDouble:transformOp ? deg2rad(static_cast&lt;const RotateTransformOperation*&gt;(transformOp)-&gt;angle()) : 0];
</ins><span class="cx">         case TransformOperation::SCALE_X:
</span><del>-            return [NSNumber numberWithDouble:op ? static_cast&lt;ScaleTransformOperation*&gt;(op)-&gt;x() : 0];
</del><ins>+            return [NSNumber numberWithDouble:transformOp ? static_cast&lt;const ScaleTransformOperation*&gt;(transformOp)-&gt;x() : 0];
</ins><span class="cx">         case TransformOperation::SCALE_Y:
</span><del>-            return [NSNumber numberWithDouble:op ? static_cast&lt;ScaleTransformOperation*&gt;(op)-&gt;y() : 0];
</del><ins>+            return [NSNumber numberWithDouble:transformOp ? static_cast&lt;const ScaleTransformOperation*&gt;(transformOp)-&gt;y() : 0];
</ins><span class="cx">         case TransformOperation::SCALE_Z:
</span><del>-            return [NSNumber numberWithDouble:op ? static_cast&lt;ScaleTransformOperation*&gt;(op)-&gt;z() : 0];
</del><ins>+            return [NSNumber numberWithDouble:transformOp ? static_cast&lt;const ScaleTransformOperation*&gt;(transformOp)-&gt;z() : 0];
</ins><span class="cx">         case TransformOperation::TRANSLATE_X:
</span><del>-            return [NSNumber numberWithDouble:op ? static_cast&lt;TranslateTransformOperation*&gt;(op)-&gt;x(size) : 0];
</del><ins>+            return [NSNumber numberWithDouble:transformOp ? static_cast&lt;const TranslateTransformOperation*&gt;(transformOp)-&gt;x(size) : 0];
</ins><span class="cx">         case TransformOperation::TRANSLATE_Y:
</span><del>-            return [NSNumber numberWithDouble:op ? static_cast&lt;TranslateTransformOperation*&gt;(op)-&gt;y(size) : 0];
</del><ins>+            return [NSNumber numberWithDouble:transformOp ? static_cast&lt;const TranslateTransformOperation*&gt;(transformOp)-&gt;y(size) : 0];
</ins><span class="cx">         case TransformOperation::TRANSLATE_Z:
</span><del>-            return [NSNumber numberWithDouble:op ? static_cast&lt;TranslateTransformOperation*&gt;(op)-&gt;z(size) : 0];
</del><ins>+            return [NSNumber numberWithDouble:transformOp ? static_cast&lt;const TranslateTransformOperation*&gt;(transformOp)-&gt;z(size) : 0];
</ins><span class="cx">         case TransformOperation::SCALE:
</span><span class="cx">         case TransformOperation::TRANSLATE:
</span><span class="cx">         case TransformOperation::SKEW_X:
</span><span class="lines">@@ -172,12 +169,12 @@
</span><span class="cx">         case TransformOperation::PERSPECTIVE:
</span><span class="cx">         case TransformOperation::IDENTITY:
</span><span class="cx">         case TransformOperation::NONE: {
</span><del>-            TransformationMatrix t;
-            if (op)
-                op-&gt;apply(t, size);
-            CATransform3D cat;
-            copyTransform(cat, t);
-            return [NSValue valueWithCATransform3D:cat];
</del><ins>+            TransformationMatrix transform;
+            if (transformOp)
+                transformOp-&gt;apply(transform, size);
+            CATransform3D caTransform;
+            copyTransform(caTransform, transform);
+            return [NSValue valueWithCATransform3D:caTransform];
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -213,6 +210,30 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+static String propertyIdToString(AnimatedPropertyID property)
+{
+    switch (property) {
+        case AnimatedPropertyWebkitTransform:
+            return &quot;transform&quot;;
+        case AnimatedPropertyOpacity:
+            return &quot;opacity&quot;;
+        case AnimatedPropertyBackgroundColor:
+            return &quot;backgroundColor&quot;;
+        case AnimatedPropertyInvalid:
+            ASSERT_NOT_REACHED();
+    }
+    ASSERT_NOT_REACHED();
+    return &quot;&quot;;
+}
+
+static String animationIdentifier(AnimatedPropertyID property, int index)
+{
+    String animationId = propertyIdToString(property);
+    animationId.append(&quot;_&quot;);
+    animationId.append(String::number(index));
+    return animationId;
+}
+
</ins><span class="cx"> #if !HAVE_MODERN_QUARTZCORE
</span><span class="cx"> static TransformationMatrix flipTransform()
</span><span class="cx"> {
</span><span class="lines">@@ -260,15 +281,6 @@
</span><span class="cx">     [layer setBackgroundColor:0];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static CALayer* getPresentationLayer(CALayer* layer)
-{
-    CALayer*  presLayer = [layer presentationLayer];
-    if (!presLayer)
-        presLayer = layer;
-
-    return presLayer;
-}
-
</del><span class="cx"> static bool caValueFunctionSupported()
</span><span class="cx"> {
</span><span class="cx">     static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
</span><span class="lines">@@ -314,9 +326,7 @@
</span><span class="cx">                              nullValue, @&quot;sublayerTransform&quot;,
</span><span class="cx">                              nullValue, @&quot;sublayers&quot;,
</span><span class="cx">                              nullValue, @&quot;transform&quot;,
</span><del>-#ifndef NDEBUG
</del><span class="cx">                              nullValue, @&quot;zPosition&quot;,
</span><del>-#endif
</del><span class="cx">                              nil];
</span><span class="cx">     return actions;
</span><span class="cx"> }
</span><span class="lines">@@ -328,7 +338,9 @@
</span><span class="cx"> 
</span><span class="cx"> GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
</span><span class="cx"> : GraphicsLayer(client)
</span><del>-, m_contentLayerForImageOrVideo(false)
</del><ins>+, m_contentsLayerPurpose(NoContentsLayer)
+, m_contentsLayerHasBackgroundColor(false)
+, m_uncommittedChanges(NoChange)
</ins><span class="cx"> {
</span><span class="cx">     BEGIN_BLOCK_OBJC_EXCEPTIONS
</span><span class="cx">     m_layer.adoptNS([[WebLayer alloc] init]);
</span><span class="lines">@@ -350,21 +362,18 @@
</span><span class="cx"> 
</span><span class="cx"> GraphicsLayerCA::~GraphicsLayerCA()
</span><span class="cx"> {
</span><del>-    // Remove a inner layer if there is one.
-    clearContents();
-
</del><ins>+    // We release our references to the CALayers here, but do not actively unparent them,
+    // since that will cause a commit and break our batched commit model. The layers will
+    // get released when the rootmost modified GraphicsLayerCA rebuilds its child layers.
+    
</ins><span class="cx">     BEGIN_BLOCK_OBJC_EXCEPTIONS
</span><span class="cx"> 
</span><span class="cx">     // Clean up the WK layer.
</span><span class="cx">     if (m_layer) {
</span><span class="cx">         WebLayer* layer = m_layer.get();
</span><span class="cx">         [layer setLayerOwner:nil];
</span><del>-        [layer removeFromSuperlayer];
</del><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (m_transformLayer)
-        [m_transformLayer.get() removeFromSuperlayer];
-
</del><span class="cx">     // animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
</span><span class="cx">     [m_animationDelegate.get() setLayer:0];
</span><span class="cx"> 
</span><span class="lines">@@ -375,10 +384,7 @@
</span><span class="cx"> {
</span><span class="cx">     String longName = String::format(&quot;CALayer(%p) GraphicsLayer(%p) &quot;, m_layer.get(), this) + name;
</span><span class="cx">     GraphicsLayer::setName(longName);
</span><del>-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [m_layer.get() setName:name];
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    noteLayerPropertyChanged(NameChanged);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> NativeLayer GraphicsLayerCA::nativeLayer() const
</span><span class="lines">@@ -389,175 +395,485 @@
</span><span class="cx"> void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
</span><span class="cx"> {
</span><span class="cx">     GraphicsLayer::addChild(childLayer);
</span><del>-
-    GraphicsLayerCA* childLayerCA = static_cast&lt;GraphicsLayerCA*&gt;(childLayer);
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [hostLayerForSublayers() addSublayer:childLayerCA-&gt;layerForSuperlayer()];
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    noteLayerPropertyChanged(ChildrenChanged);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
</span><span class="cx"> {
</span><span class="cx">     GraphicsLayer::addChildAtIndex(childLayer, index);
</span><del>-
-    GraphicsLayerCA* childLayerCA = static_cast&lt;GraphicsLayerCA*&gt;(childLayer);
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [hostLayerForSublayers() insertSublayer:childLayerCA-&gt;layerForSuperlayer() atIndex:index];
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    noteLayerPropertyChanged(ChildrenChanged);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
</span><span class="cx"> {
</span><del>-    // FIXME: share code with base class
-    ASSERT(childLayer != this);
-    childLayer-&gt;removeFromParent();
</del><ins>+    GraphicsLayer::addChildBelow(childLayer, sibling);
+    noteLayerPropertyChanged(ChildrenChanged);
+}
</ins><span class="cx"> 
</span><del>-    bool found = false;
-    for (unsigned i = 0; i &lt; m_children.size(); i++) {
-        if (sibling == m_children[i]) {
-            m_children.insert(i, childLayer);
-            found = true;
-            break;
-        }
</del><ins>+void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+    GraphicsLayer::addChildAbove(childLayer, sibling);
+    noteLayerPropertyChanged(ChildrenChanged);
+}
+
+bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+    if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+        noteLayerPropertyChanged(ChildrenChanged);
+        return true;
</ins><span class="cx">     }
</span><del>-    childLayer-&gt;setParent(this);
</del><ins>+    return false;
+}
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
</del><ins>+void GraphicsLayerCA::removeFromParent()
+{
+    if (m_parent)
+        static_cast&lt;GraphicsLayerCA*&gt;(m_parent)-&gt;noteLayerPropertyChanged(ChildrenChanged);
+    GraphicsLayer::removeFromParent();
+}
</ins><span class="cx"> 
</span><del>-    GraphicsLayerCA* childLayerCA = static_cast&lt;GraphicsLayerCA*&gt;(childLayer);
-    GraphicsLayerCA* siblingLayerCA = static_cast&lt;GraphicsLayerCA*&gt;(sibling);
-    if (found)
-        [hostLayerForSublayers() insertSublayer:childLayerCA-&gt;layerForSuperlayer() below:siblingLayerCA-&gt;layerForSuperlayer()];
-    else {
-        m_children.append(childLayer);
-        [hostLayerForSublayers() addSublayer:childLayerCA-&gt;layerForSuperlayer()];
-    }
</del><ins>+void GraphicsLayerCA::setPosition(const FloatPoint&amp; point)
+{
+    if (point == m_position)
+        return;
</ins><span class="cx"> 
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    GraphicsLayer::setPosition(point);
+    noteLayerPropertyChanged(PositionChanged);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
</del><ins>+void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D&amp; point)
</ins><span class="cx"> {
</span><del>-    // FIXME: share code with base class
-    ASSERT(childLayer != this);
-    childLayer-&gt;removeFromParent();
</del><ins>+    if (point == m_anchorPoint)
+        return;
</ins><span class="cx"> 
</span><del>-    unsigned i;
-    bool found = false;
-    for (i = 0; i &lt; m_children.size(); i++) {
-        if (sibling == m_children[i]) {
-            m_children.insert(i+1, childLayer);
-            found = true;
</del><ins>+    GraphicsLayer::setAnchorPoint(point);
+    noteLayerPropertyChanged(AnchorPointChanged);
+}
+
+void GraphicsLayerCA::setSize(const FloatSize&amp; size)
+{
+    if (size == m_size)
+        return;
+
+    GraphicsLayer::setSize(size);
+    noteLayerPropertyChanged(SizeChanged);
+}
+
+void GraphicsLayerCA::setTransform(const TransformationMatrix&amp; t)
+{
+    if (t == m_transform)
+        return;
+
+    GraphicsLayer::setTransform(t);
+    noteLayerPropertyChanged(TransformChanged);
+}
+
+void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix&amp; t)
+{
+    if (t == m_childrenTransform)
+        return;
+
+    GraphicsLayer::setChildrenTransform(t);
+    noteLayerPropertyChanged(ChildrenTransformChanged);
+}
+
+static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
+{
+    for (int index = 0; ; ++index) {
+        String animName = animationIdentifier(property, index);
+
+        CAAnimation* anim = [fromLayer animationForKey:animName];
+        if (!anim)
</ins><span class="cx">             break;
</span><del>-        }
</del><ins>+
+        [anim retain];
+        [fromLayer removeAnimationForKey:animName];
+        [toLayer addAnimation:anim forKey:animName];
+        [anim release];
</ins><span class="cx">     }
</span><del>-    childLayer-&gt;setParent(this);
</del><ins>+}
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
</del><ins>+void GraphicsLayerCA::setPreserves3D(bool preserves3D)
+{
+    if (preserves3D == m_preserves3D)
+        return;
</ins><span class="cx"> 
</span><del>-    GraphicsLayerCA* childLayerCA = static_cast&lt;GraphicsLayerCA*&gt;(childLayer);
-    GraphicsLayerCA* siblingLayerCA = static_cast&lt;GraphicsLayerCA*&gt;(sibling);
-    if (found) {
-        [hostLayerForSublayers() insertSublayer:childLayerCA-&gt;layerForSuperlayer() above:siblingLayerCA-&gt;layerForSuperlayer()];
-    } else {
-        m_children.append(childLayer);
-        [hostLayerForSublayers() addSublayer:childLayerCA-&gt;layerForSuperlayer()];
</del><ins>+    GraphicsLayer::setPreserves3D(preserves3D);
+    noteLayerPropertyChanged(Preserves3DChanged);
+}
+
+void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
+{
+    if (masksToBounds == m_masksToBounds)
+        return;
+
+    GraphicsLayer::setMasksToBounds(masksToBounds);
+    noteLayerPropertyChanged(MasksToBoundsChanged);
+}
+
+void GraphicsLayerCA::setDrawsContent(bool drawsContent)
+{
+    if (drawsContent == m_drawsContent)
+        return;
+
+    GraphicsLayer::setDrawsContent(drawsContent);
+    noteLayerPropertyChanged(DrawsContentChanged);
+}
+
+void GraphicsLayerCA::setBackgroundColor(const Color&amp; color)
+{
+    if (m_backgroundColorSet &amp;&amp; m_backgroundColor == color)
+        return;
+
+    GraphicsLayer::setBackgroundColor(color);
+
+    m_contentsLayerHasBackgroundColor = true;
+    noteLayerPropertyChanged(BackgroundColorChanged);
+}
+
+void GraphicsLayerCA::clearBackgroundColor()
+{
+    if (!m_backgroundColorSet)
+        return;
+
+    GraphicsLayer::clearBackgroundColor();
+    m_contentsLayerHasBackgroundColor = false;
+    noteLayerPropertyChanged(BackgroundColorChanged);
+}
+
+void GraphicsLayerCA::setContentsOpaque(bool opaque)
+{
+    if (m_contentsOpaque == opaque)
+        return;
+
+    GraphicsLayer::setContentsOpaque(opaque);
+    noteLayerPropertyChanged(ContentsOpaqueChanged);
+}
+
+void GraphicsLayerCA::setBackfaceVisibility(bool visible)
+{
+    if (m_backfaceVisibility == visible)
+        return;
+    
+    GraphicsLayer::setBackfaceVisibility(visible);
+    noteLayerPropertyChanged(BackfaceVisibilityChanged);
+}
+
+void GraphicsLayerCA::setOpacity(float opacity)
+{
+    float clampedOpacity = max(0.0f, min(opacity, 1.0f));
+
+    if (clampedOpacity == m_opacity)
+        return;
+
+    GraphicsLayer::setOpacity(clampedOpacity);
+    noteLayerPropertyChanged(OpacityChanged);
+}
+
+void GraphicsLayerCA::setNeedsDisplay()
+{
+    FloatRect hugeRect(-numeric_limits&lt;float&gt;::max() / 2, -numeric_limits&lt;float&gt;::max() / 2,
+                       numeric_limits&lt;float&gt;::max(), numeric_limits&lt;float&gt;::max());
+
+    setNeedsDisplayInRect(hugeRect);
+}
+
+void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect&amp; rect)
+{
+    if (!drawsContent())
+        return;
+
+    const size_t maxDirtyRects = 32;
+    
+    for (size_t i = 0; i &lt; m_dirtyRects.size(); ++i) {
+        if (m_dirtyRects[i].contains(rect))
+            return;
</ins><span class="cx">     }
</span><ins>+    
+    if (m_dirtyRects.size() &lt; maxDirtyRects)
+        m_dirtyRects.append(rect);
+    else
+        m_dirtyRects[0].unite(rect);
</ins><span class="cx"> 
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    noteLayerPropertyChanged(DirtyRectsChanged);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
</del><ins>+void GraphicsLayerCA::setContentsRect(const IntRect&amp; rect)
</ins><span class="cx"> {
</span><del>-    // FIXME: share code with base class
-    ASSERT(!newChild-&gt;parent());
</del><ins>+    if (rect == m_contentsRect)
+        return;
</ins><span class="cx"> 
</span><del>-    bool found = false;
-    for (unsigned i = 0; i &lt; m_children.size(); i++) {
-        if (oldChild == m_children[i]) {
-            m_children[i] = newChild;
-            found = true;
-            break;
</del><ins>+    GraphicsLayer::setContentsRect(rect);
+    noteLayerPropertyChanged(ContentsRectChanged);
+}
+
+bool GraphicsLayerCA::addAnimation(const KeyframeValueList&amp; valueList, const IntSize&amp; boxSize, const Animation* anim, const String&amp; keyframesName, double beginTime)
+{
+    if (forceSoftwareAnimation() || !anim || anim-&gt;isEmptyOrZeroDuration() || valueList.size() &lt; 2)
+        return false;
+
+#if !HAVE_MODERN_QUARTZCORE
+    // Older versions of QuartzCore do not handle opacity in transform layers properly, so we will
+    // always do software animation in that case.
+    if (valueList.property() == AnimatedPropertyOpacity)
+        return false;
+#endif
+
+    bool createdAnimations = false;
+    if (valueList.property() == AnimatedPropertyWebkitTransform)
+        createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, beginTime, boxSize);
+    else
+        createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, beginTime);
+
+    if (createdAnimations)
+        noteLayerPropertyChanged(AnimationChanged);
+        
+    return createdAnimations;
+}
+
+void GraphicsLayerCA::removeAnimationsForProperty(AnimatedPropertyID property)
+{
+    if (m_transitionPropertiesToRemove.find(property) != m_transitionPropertiesToRemove.end())
+        return;
+
+    m_transitionPropertiesToRemove.add(property);
+    noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::removeAnimationsForKeyframes(const String&amp; animationName)
+{
+    if (!animationIsRunning(animationName))
+        return;
+
+    m_keyframeAnimationsToProcess.add(animationName, Remove);
+    noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::pauseAnimation(const String&amp; keyframesName)
+{
+    if (!animationIsRunning(keyframesName))
+        return;
+
+    AnimationsToProcessMap::iterator it = m_keyframeAnimationsToProcess.find(keyframesName);
+    if (it != m_keyframeAnimationsToProcess.end()) {
+        // If an animation is scheduled to be removed, don't change the remove to a pause.
+        if (it-&gt;second != Remove)
+            it-&gt;second = Pause;
+    } else
+        m_keyframeAnimationsToProcess.add(keyframesName, Pause);
+
+    noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::setContentsToImage(Image* image)
+{
+    if (image) {
+        m_pendingContentsImage = image-&gt;nativeImageForCurrentFrame();
+        CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get());
+
+        static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+        if (CFEqual(colorSpace, deviceRGB)) {
+            // CoreGraphics renders images tagged with DeviceRGB using GenericRGB. When we hand such
+            // images to CA we need to tag them similarly so CA rendering matches CG rendering.
+            static CGColorSpaceRef genericRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+            m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB));
</ins><span class="cx">         }
</span><ins>+        m_contentsLayerPurpose = ContentsLayerForImage;
+        if (!m_contentsLayer)
+            noteLayerPropertyChanged(ChildrenChanged);
+    } else {
+        m_pendingContentsImage = 0;
+        m_contentsLayerPurpose = NoContentsLayer;
+        if (m_contentsLayer)
+            noteLayerPropertyChanged(ChildrenChanged);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (found) {
-        oldChild-&gt;setParent(0);
</del><ins>+    noteLayerPropertyChanged(ContentsImageChanged);
+}
</ins><span class="cx"> 
</span><del>-        newChild-&gt;removeFromParent();
-        newChild-&gt;setParent(this);
</del><ins>+void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
+{
+    if (videoLayer != m_contentsLayer.get())
+        noteLayerPropertyChanged(ChildrenChanged);
</ins><span class="cx"> 
</span><del>-        BEGIN_BLOCK_OBJC_EXCEPTIONS
-        GraphicsLayerCA* oldChildCA = static_cast&lt;GraphicsLayerCA*&gt;(oldChild);
-        GraphicsLayerCA* newChildCA = static_cast&lt;GraphicsLayerCA*&gt;(newChild);
-        [hostLayerForSublayers() replaceSublayer:oldChildCA-&gt;layerForSuperlayer() with:newChildCA-&gt;layerForSuperlayer()];
-        END_BLOCK_OBJC_EXCEPTIONS
-        return true;
-    }
-    return false;
</del><ins>+    m_contentsLayer = videoLayer;
+    noteLayerPropertyChanged(ContentsVideoChanged);
+
+    m_contentsLayerPurpose = videoLayer ? ContentsLayerForVideo : NoContentsLayer;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::removeFromParent()
</del><ins>+void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
</ins><span class="cx"> {
</span><del>-    GraphicsLayer::removeFromParent();
</del><ins>+    if (orientation == m_geometryOrientation)
+        return;
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [layerForSuperlayer() removeFromSuperlayer];            
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    GraphicsLayer::setGeometryOrientation(orientation);
+    noteLayerPropertyChanged(GeometryOrientationChanged);
+
+#if !HAVE_MODERN_QUARTZCORE
+    // Geometry orientation is mapped onto children transform in older QuartzCores.
+    switch (m_geometryOrientation) {
+        case CompositingCoordinatesTopDown:
+            setChildrenTransform(TransformationMatrix());
+            break;
+        
+        case CompositingCoordinatesBottomUp:
+            setChildrenTransform(flipTransform());
+            break;
+    }
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setPosition(const FloatPoint&amp; point)
</del><ins>+void GraphicsLayerCA::syncCompositingState()
</ins><span class="cx"> {
</span><del>-    // Don't short-circuit here, because position and anchor point are inter-dependent.
-    GraphicsLayer::setPosition(point);
</del><ins>+    recursiveCommitChanges();
+}
</ins><span class="cx"> 
</span><del>-    // Position is offset on the layer by the layer anchor point.
-    CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
-                                   m_position.y() + m_anchorPoint.y() * m_size.height());
-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [primaryLayer() setPosition:posPoint];
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+void GraphicsLayerCA::recursiveCommitChanges()
+{
+    commitLayerChanges();
+
+    const Vector&lt;GraphicsLayer*&gt;&amp; childLayers = children();
+    size_t numChildren = childLayers.size();
+    for (size_t i = 0; i &lt; numChildren; ++i) {
+        GraphicsLayerCA* curChild = static_cast&lt;GraphicsLayerCA*&gt;(childLayers[i]);
+        curChild-&gt;recursiveCommitChanges();
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D&amp; point)
</del><ins>+void GraphicsLayerCA::commitLayerChanges()
</ins><span class="cx"> {
</span><del>-    // Don't short-circuit here, because position and anchor point are inter-dependent.
-    bool zChanged = (point.z() != m_anchorPoint.z());
-    GraphicsLayer::setAnchorPoint(point);
</del><ins>+    if (!m_uncommittedChanges)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     BEGIN_BLOCK_OBJC_EXCEPTIONS
</span><del>-    // set the value on the layer to the new transform.
-    [primaryLayer() setAnchorPoint:FloatPoint(point.x(), point.y())];
</del><span class="cx"> 
</span><del>-    if (zChanged) {
-#if HAVE_MODERN_QUARTZCORE
-        [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
-#endif
</del><ins>+    // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to
+    if (m_uncommittedChanges &amp; Preserves3DChanged)
+        updateLayerPreserves3D();
+
+    if (m_uncommittedChanges &amp; NameChanged) {
+        if (m_transformLayer)
+            [m_transformLayer.get() setName:(&quot;Transform layer &quot; + name())];
+        [m_layer.get() setName:name()];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Position depends on anchor point, so update it now.
-    setPosition(m_position);
</del><ins>+    if (m_uncommittedChanges &amp; ContentsImageChanged) // Needs to happen before ChildrenChanged
+        updateContentsImage();
+        
+    if (m_uncommittedChanges &amp; ContentsVideoChanged) // Needs to happen before ChildrenChanged
+        updateContentsVideo();
+
+    if (m_uncommittedChanges &amp; BackgroundColorChanged)  // Needs to happen before ChildrenChanged, and after updating image or video
+        updateLayerBackgroundColor();
+
+    if (m_uncommittedChanges &amp; ChildrenChanged)
+        updateSublayerList();
+
+    if (m_uncommittedChanges &amp; PositionChanged)
+        updateLayerPosition();
+    
+    if (m_uncommittedChanges &amp; AnchorPointChanged)
+        updateAnchorPoint();
+    
+    if (m_uncommittedChanges &amp; SizeChanged)
+        updateLayerSize();
+
+    if (m_uncommittedChanges &amp; TransformChanged)
+        updateTransform();
+
+    if (m_uncommittedChanges &amp; ChildrenTransformChanged)
+        updateChildrenTransform();
+    
+    if (m_uncommittedChanges &amp; MasksToBoundsChanged)
+        updateMasksToBounds();
+    
+    if (m_uncommittedChanges &amp; DrawsContentChanged)
+        updateLayerDrawsContent();
+
+    if (m_uncommittedChanges &amp; ContentsOpaqueChanged)
+        updateContentsOpaque();
+
+    if (m_uncommittedChanges &amp; BackfaceVisibilityChanged)
+        updateBackfaceVisibility();
+
+    if (m_uncommittedChanges &amp; OpacityChanged)
+        updateOpacityOnLayer();
+    
+    if (m_uncommittedChanges &amp; AnimationChanged)
+        updateLayerAnimations();
+    
+    if (m_uncommittedChanges &amp; DirtyRectsChanged)
+        repaintLayerDirtyRects();
+    
+    if (m_uncommittedChanges &amp; ContentsRectChanged)
+        updateContentsRect();
+
+    if (m_uncommittedChanges &amp; GeometryOrientationChanged)
+        updateGeometryOrientation();
+
+    m_uncommittedChanges = NoChange;
</ins><span class="cx">     END_BLOCK_OBJC_EXCEPTIONS
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setSize(const FloatSize&amp; size)
</del><ins>+void GraphicsLayerCA::updateSublayerList()
</ins><span class="cx"> {
</span><del>-    GraphicsLayer::setSize(size);
</del><ins>+    NSMutableArray* newSublayers = nil;
</ins><span class="cx"> 
</span><del>-    CGRect rect = CGRectMake(0.0f,
-                             0.0f,
-                             m_size.width(),
-                             m_size.height());
</del><ins>+    if (m_transformLayer) {
+        // FIXME: add the primary layer in the correct order with negative z-order children.
+        newSublayers = [[NSMutableArray alloc] initWithObjects:m_layer.get(), nil];
+    } else if (m_contentsLayer) {
+        // FIXME: add the contents layer in the correct order with negative z-order children.
+        newSublayers = [[NSMutableArray alloc] initWithObjects:m_contentsLayer.get(), nil];
+    }
</ins><span class="cx">     
</span><del>-    CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
</del><ins>+    const Vector&lt;GraphicsLayer*&gt;&amp; childLayers = children();
+    size_t numChildren = childLayers.size();
+    for (size_t i = 0; i &lt; numChildren; ++i) {
+        GraphicsLayerCA* curChild = static_cast&lt;GraphicsLayerCA*&gt;(childLayers[i]);
+     
+        CALayer* childLayer = curChild-&gt;layerForSuperlayer();
+        if (!newSublayers)
+            newSublayers = [[NSMutableArray alloc] initWithObjects:childLayer, nil];
+        else
+            [newSublayers addObject:childLayer];
+    }
+
+    [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
+
+    if (m_transformLayer) {
+        [m_transformLayer.get() setSublayers:newSublayers];
+
+        if (m_contentsLayer) {
+            // If we have a transform layer, then the contents layer is parented in the 
+            // primary layer (which is itself a child of the transform layer).
+            [m_layer.get() setSublayers:nil];
+            [m_layer.get() addSublayer:m_contentsLayer.get()];
+        }
+    } else {
+        [m_layer.get() setSublayers:newSublayers];
+    }
+
+    [newSublayers release];
+}
+
+void GraphicsLayerCA::updateLayerPosition()
+{
+    // Position is offset on the layer by the layer anchor point.
+    CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
+                                   m_position.y() + m_anchorPoint.y() * m_size.height());
</ins><span class="cx">     
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    [primaryLayer() setPosition:posPoint];
+}
</ins><span class="cx"> 
</span><ins>+void GraphicsLayerCA::updateLayerSize()
+{
+    CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height());
</ins><span class="cx">     if (m_transformLayer) {
</span><span class="cx">         [m_transformLayer.get() setBounds:rect];
</span><del>-        // The anchor of the contents layer is always at 0.5, 0.5, so the position
-        // is center-relative.
</del><ins>+        // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
+        CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
</ins><span class="cx">         [m_layer.get() setPosition:centerPoint];
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -566,133 +882,85 @@
</span><span class="cx">         swapFromOrToTiledLayer(needTiledLayer);
</span><span class="cx">     
</span><span class="cx">     [m_layer.get() setBounds:rect];
</span><ins>+    
+    // Contents transform may depend on height.
</ins><span class="cx">     updateContentsTransform();
</span><span class="cx"> 
</span><span class="cx">     // Note that we don't resize m_contentsLayer. It's up the caller to do that.
</span><span class="cx"> 
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
-
</del><span class="cx">     // if we've changed the bounds, we need to recalculate the position
</span><del>-    // of the layer, taking anchor point into account
-    setPosition(m_position);
</del><ins>+    // of the layer, taking anchor point into account.
+    updateLayerPosition();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setTransform(const TransformationMatrix&amp; t)
</del><ins>+void GraphicsLayerCA::updateAnchorPoint()
</ins><span class="cx"> {
</span><del>-    GraphicsLayer::setTransform(t);
-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    [primaryLayer() setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())];
+#if HAVE_MODERN_QUARTZCORE
+    [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
+#endif
+    updateLayerPosition();
+}
+
+void GraphicsLayerCA::updateTransform()
+{
</ins><span class="cx">     CATransform3D transform;
</span><del>-    copyTransform(transform, t);
</del><ins>+    copyTransform(transform, m_transform);
</ins><span class="cx">     [primaryLayer() setTransform:transform];
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
-    
-    // Remove any old transition entries for transform.
-    removeAllAnimationsForProperty(AnimatedPropertyWebkitTransform);
-
-    // Even if we don't have a transition in the list, the layer may still have one.
-    // This happens when we are setting the final transform value after an animation or
-    // transition has ended. In removeAnimation we toss the entry from the list but don't
-    // remove it from the list. That way we aren't in danger of displaying a stale transform
-    // in the time between removing the animation and setting the new unanimated value. We 
-    // can't do this in removeAnimation because we don't know the new transform value there.
-    String keyPath = propertyIdToString(AnimatedPropertyWebkitTransform);
-    CALayer* layer = animatedLayer(AnimatedPropertyWebkitTransform);
-    
-    for (int i = 0; ; ++i) {
-        String animName = keyPath + &quot;_&quot; + String::number(i);
-        if (![layer animationForKey: animName])
-            break;
-        [layer removeAnimationForKey:animName];
-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix&amp; t)
</del><ins>+void GraphicsLayerCA::updateChildrenTransform()
</ins><span class="cx"> {
</span><del>-    if (t == m_childrenTransform)
-        return;
-
-    GraphicsLayer::setChildrenTransform(t);
-
</del><span class="cx">     CATransform3D transform;
</span><del>-    copyTransform(transform, t);
-
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    // Set the value on the layer to the new transform.
</del><ins>+    copyTransform(transform, m_childrenTransform);
</ins><span class="cx">     [primaryLayer() setSublayerTransform:transform];
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
</del><ins>+void GraphicsLayerCA::updateMasksToBounds()
</ins><span class="cx"> {
</span><del>-    String keyPath = GraphicsLayer::propertyIdToString(property);
-    for (short index = 0; ; ++index) {
-        String animName = keyPath + &quot;_&quot; + String::number(index);
-        CAAnimation* anim = [fromLayer animationForKey:animName];
-        if (!anim)
-            break;
</del><ins>+    [m_layer.get() setMasksToBounds:m_masksToBounds];
+#ifndef NDEBUG
+    updateDebugIndicators();
+#endif
+}
</ins><span class="cx"> 
</span><del>-        [anim retain];
-        [fromLayer removeAnimationForKey:animName];
-        [toLayer addAnimation:anim forKey:animName];
-        [anim release];
-    }
</del><ins>+void GraphicsLayerCA::updateContentsOpaque()
+{
+    [m_layer.get() setOpaque:m_contentsOpaque];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void moveSublayers(CALayer* fromLayer, CALayer* toLayer)
</del><ins>+void GraphicsLayerCA::updateBackfaceVisibility()
</ins><span class="cx"> {
</span><del>-    NSArray* sublayersCopy = [[fromLayer sublayers] copy]; // Avoid mutation while enumerating, and keep the sublayers alive.
-    NSEnumerator* childrenEnumerator = [sublayersCopy objectEnumerator];
-
-    CALayer* layer;
-    while ((layer = [childrenEnumerator nextObject]) != nil) {
-        [layer removeFromSuperlayer];
-        [toLayer addSublayer:layer];
-    }
-    [sublayersCopy release];
</del><ins>+    [m_layer.get() setDoubleSided:m_backfaceVisibility];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setPreserves3D(bool preserves3D)
</del><ins>+void GraphicsLayerCA::updateLayerPreserves3D()
</ins><span class="cx"> {
</span><del>-    GraphicsLayer::setPreserves3D(preserves3D);
</del><ins>+    Class transformLayerClass = NSClassFromString(@&quot;CATransformLayer&quot;);
+    if (!transformLayerClass)
+        return;
</ins><span class="cx"> 
</span><del>-    CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
-    CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-
-    Class transformLayerClass = NSClassFromString(@&quot;CATransformLayer&quot;);
-    if (preserves3D &amp;&amp; !m_transformLayer &amp;&amp; transformLayerClass) {
</del><ins>+    if (m_preserves3D &amp;&amp; !m_transformLayer) {
</ins><span class="cx">         // Create the transform layer.
</span><span class="cx">         m_transformLayer.adoptNS([[transformLayerClass alloc] init]);
</span><span class="cx"> 
</span><span class="cx">         // Turn off default animations.
</span><span class="cx">         [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@&quot;actions&quot;]];
</span><del>-        
</del><ins>+
</ins><span class="cx"> #ifndef NDEBUG
</span><span class="cx">         [m_transformLayer.get() setName:[NSString stringWithFormat:@&quot;Transform Layer CATransformLayer(%p) GraphicsLayer(%p)&quot;, m_transformLayer.get(), this]];
</span><span class="cx"> #endif
</span><span class="cx">         // Copy the position from this layer.
</span><del>-        [m_transformLayer.get() setBounds:[m_layer.get() bounds]];
-        [m_transformLayer.get() setPosition:[m_layer.get() position]];
-        [m_transformLayer.get() setAnchorPoint:[m_layer.get() anchorPoint]];
-#if HAVE_MODERN_QUARTZCORE
-        [m_transformLayer.get() setAnchorPointZ:[m_layer.get() anchorPointZ]];
-#endif
-        [m_transformLayer.get() setContentsRect:[m_layer.get() contentsRect]];
-#ifndef NDEBUG
-        [m_transformLayer.get() setZPosition:[m_layer.get() zPosition]];
-#endif
</del><ins>+        updateLayerPosition();
+        updateLayerSize();
+        updateAnchorPoint();
+        updateTransform();
+        updateChildrenTransform();
</ins><span class="cx">         
</span><del>-        // The contents layer is positioned at (0,0) relative to the transformLayer.
</del><ins>+        CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
</ins><span class="cx">         [m_layer.get() setPosition:point];
</span><del>-        [m_layer.get() setAnchorPoint:centerPoint];
-#ifndef NDEBUG
-        [m_layer.get() setZPosition:0.0f];
-#endif
-        
-        // Transfer the transform over.
-        [m_transformLayer.get() setTransform:[m_layer.get() transform]];
</del><ins>+
+        [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)];
</ins><span class="cx">         [m_layer.get() setTransform:CATransform3DIdentity];
</span><span class="cx">         
</span><span class="cx">         // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
</span><span class="lines">@@ -703,657 +971,579 @@
</span><span class="cx">         [m_transformLayer.get() addSublayer:m_layer.get()];
</span><span class="cx"> 
</span><span class="cx">         moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get());
</span><del>-        moveSublayers(m_layer.get(), m_transformLayer.get());
-
-    } else if (!preserves3D &amp;&amp; m_transformLayer) {
</del><ins>+        
+        updateSublayerList();
+    } else if (!m_preserves3D &amp;&amp; m_transformLayer) {
</ins><span class="cx">         // Relace the transformLayer in the parent with this layer.
</span><span class="cx">         [m_layer.get() removeFromSuperlayer];
</span><span class="cx">         [[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()];
</span><span class="cx"> 
</span><span class="cx">         moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get());
</span><del>-        moveSublayers(m_transformLayer.get(), m_layer.get());
</del><span class="cx"> 
</span><del>-        // Reset the layer position and transform.
-        [m_layer.get() setPosition:[m_transformLayer.get() position]];
-        [m_layer.get() setAnchorPoint:[m_transformLayer.get() anchorPoint]];
-#if HAVE_MODERN_QUARTZCORE
-        [m_layer.get() setAnchorPointZ:[m_transformLayer.get() anchorPointZ]];
-#endif
-        [m_layer.get() setContentsRect:[m_transformLayer.get() contentsRect]];
-        [m_layer.get() setTransform:[m_transformLayer.get() transform]];
-#ifndef NDEBUG
-        [m_layer.get() setZPosition:[m_transformLayer.get() zPosition]];
-#endif
-
</del><span class="cx">         // Release the transform layer.
</span><span class="cx">         m_transformLayer = 0;
</span><ins>+
+        updateLayerPosition();
+        updateLayerSize();
+        updateAnchorPoint();
+        updateTransform();
+        updateChildrenTransform();
+
+        updateSublayerList();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     updateOpacityOnLayer();
</span><del>-
-    END_BLOCK_OBJC_EXCEPTIONS
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
</del><ins>+void GraphicsLayerCA::updateLayerDrawsContent()
</ins><span class="cx"> {
</span><del>-    if (masksToBounds == m_masksToBounds)
-        return;
</del><ins>+    bool needTiledLayer = requiresTiledLayer(m_size);
+    if (needTiledLayer != m_usingTiledLayer)
+        swapFromOrToTiledLayer(needTiledLayer);
</ins><span class="cx"> 
</span><del>-    GraphicsLayer::setMasksToBounds(masksToBounds);
</del><ins>+    if (m_drawsContent)
+        [m_layer.get() setNeedsDisplay];
+    else
+        [m_layer.get() setContents:nil];
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [m_layer.get() setMasksToBounds:masksToBounds];
-    END_BLOCK_OBJC_EXCEPTIONS
-
</del><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     updateDebugIndicators();
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setDrawsContent(bool drawsContent)
</del><ins>+void GraphicsLayerCA::updateLayerBackgroundColor()
</ins><span class="cx"> {
</span><del>-    if (drawsContent != m_drawsContent) {
-        GraphicsLayer::setDrawsContent(drawsContent);
</del><ins>+    if (!m_contentsLayer)
+        return;
</ins><span class="cx"> 
</span><del>-        bool needTiledLayer = requiresTiledLayer(m_size);
-        if (needTiledLayer != m_usingTiledLayer)
-            swapFromOrToTiledLayer(needTiledLayer);
</del><ins>+    // We never create the contents layer just for background color yet.
+    if (m_backgroundColorSet)
+        setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
+    else
+        clearLayerBackgroundColor(m_contentsLayer.get());
+}
</ins><span class="cx"> 
</span><del>-        BEGIN_BLOCK_OBJC_EXCEPTIONS
-        if (m_drawsContent)
-            [m_layer.get() setNeedsDisplay];
-        else
-            [m_layer.get() setContents:nil];
-        
</del><ins>+void GraphicsLayerCA::updateContentsImage()
+{
+    if (m_pendingContentsImage) {
+        if (!m_contentsLayer.get()) {
+            WebLayer* imageLayer = [WebLayer layer];
</ins><span class="cx"> #ifndef NDEBUG
</span><del>-        updateDebugIndicators();
</del><ins>+            [imageLayer setName:@&quot;Image Layer&quot;];
</ins><span class="cx"> #endif
</span><del>-        END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+            setupContentsLayer(imageLayer);
+            m_contentsLayer.adoptNS([imageLayer retain]);
+            // m_contentsLayer will be parented by updateSublayerList
+        }
+
+        // FIXME: maybe only do trilinear if the image is being scaled down,
+        // but then what if the layer size changes?
+#if !defined(BUILDING_ON_TIGER) &amp;&amp; !defined(BUILDING_ON_LEOPARD)
+        [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
+#endif
+        [m_contentsLayer.get() setContents:(id)m_pendingContentsImage.get()];
+        m_pendingContentsImage = 0;
+        
+        updateContentsRect();
+    } else {
+        // No image.
+        // m_contentsLayer will be removed via updateSublayerList.
+        m_contentsLayer = 0;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setBackgroundColor(const Color&amp; color, const Animation* transition, double beginTime)
</del><ins>+void GraphicsLayerCA::updateContentsVideo()
</ins><span class="cx"> {
</span><del>-    GraphicsLayer::setBackgroundColor(color, transition, beginTime);
</del><ins>+    // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList().
+    if (m_contentsLayer) {
+        setupContentsLayer(m_contentsLayer.get());
+        updateContentsRect();
+    }
+}
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    
-    if (!m_contentsLayer.get()) {
-        WebLayer* colorLayer = [WebLayer layer];
-#ifndef NDEBUG
-        [colorLayer setName:@&quot;Color Layer&quot;];
</del><ins>+void GraphicsLayerCA::updateContentsRect()
+{
+    if (!m_contentsLayer)
+        return;
+
+    CGPoint point = CGPointMake(m_contentsRect.x(),
+                                m_contentsRect.y());
+    CGRect rect = CGRectMake(0.0f,
+                             0.0f,
+                             m_contentsRect.width(),
+                             m_contentsRect.height());
+
+    [m_contentsLayer.get() setPosition:point];
+    [m_contentsLayer.get() setBounds:rect];
+}
+
+void GraphicsLayerCA::updateGeometryOrientation()
+{
+#if HAVE_MODERN_QUARTZCORE
+    switch (geometryOrientation()) {
+        case CompositingCoordinatesTopDown:
+            [m_layer.get() setGeometryFlipped:NO];
+            break;
+        
+        case CompositingCoordinatesBottomUp:
+            [m_layer.get() setGeometryFlipped:YES];
+            break;
+    }
+    // Geometry orientation is mapped onto children transform in older QuartzCores,
+    // so is handled via setGeometryOrientation().
</ins><span class="cx"> #endif
</span><del>-        setContentsLayer(colorLayer);
</del><ins>+}
+
+void GraphicsLayerCA::updateLayerAnimations()
+{
+    if (m_transitionPropertiesToRemove.size()) {
+        HashSet&lt;int&gt;::const_iterator end = m_transitionPropertiesToRemove.end();
+        for (HashSet&lt;AnimatedProperty&gt;::const_iterator it = m_transitionPropertiesToRemove.begin(); it != end; ++it) {
+            AnimatedPropertyID currProperty = static_cast&lt;AnimatedPropertyID&gt;(*it);
+            // Remove all animations with this property in the key.
+            // We can't tell if this property is animating via a transition or animation here, but
+            // that's OK because the style system never sends both transitions and animations for the same property.
+            for (int index = 0; ; ++index) {
+                if (!removeAnimationFromLayer(currProperty, index))
+                    break;
+            }
+        }
+
+        m_transitionPropertiesToRemove.clear();
</ins><span class="cx">     }
</span><ins>+
+    if (m_keyframeAnimationsToProcess.size()) {
+        AnimationsToProcessMap::const_iterator end = m_keyframeAnimationsToProcess.end();
+        for (AnimationsToProcessMap::const_iterator it = m_keyframeAnimationsToProcess.begin(); it != end; ++it) {
+            const String&amp; currKeyframeName = it-&gt;first;
+            KeyframeAnimationsMap::iterator animationIt = m_runningKeyframeAnimations.find(currKeyframeName);
+            if (animationIt == m_runningKeyframeAnimations.end())
+                continue;
+
+            AnimationProcessingAction action = it-&gt;second;
+            const Vector&lt;AnimationPair&gt;&amp; animations = animationIt-&gt;second;
+            for (size_t i = 0; i &lt; animations.size(); ++i) {
+                const AnimationPair&amp; currPair = animations[i];
+                switch (action) {
+                    case Remove:
+                        removeAnimationFromLayer(static_cast&lt;AnimatedPropertyID&gt;(currPair.first), currPair.second);
+                        break;
+                    case Pause:
+                        pauseAnimationOnLayer(static_cast&lt;AnimatedPropertyID&gt;(currPair.first), currPair.second);
+                        break;
+                }
+            }
+
+            if (action == Remove)
+                m_runningKeyframeAnimations.remove(currKeyframeName);
+        }
</ins><span class="cx">     
</span><del>-    if (transition &amp;&amp; !transition-&gt;isEmptyOrZeroDuration()) {
-        CALayer* presLayer = [m_contentsLayer.get() presentationLayer];
-        // If we don't have a presentationLayer, just use the CALayer
-        if (!presLayer)
-            presLayer = m_contentsLayer.get();
</del><ins>+        m_keyframeAnimationsToProcess.clear();
+    }
+    
+    size_t numAnimations;
+    if ((numAnimations = m_uncomittedAnimations.size())) {
+        for (size_t i = 0; i &lt; numAnimations; ++i) {
+            const LayerAnimation&amp; pendingAnimation = m_uncomittedAnimations[i];
+            setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_index, pendingAnimation.m_beginTime);
+            
+            if (!pendingAnimation.m_keyframesName.isEmpty()) {
+                // If this is a keyframe anim, we have to remember the association of keyframes name to property/index pairs,
+                // so we can remove the animations later if needed.
+                // For transitions, we can just generate animation names with property and index.
+                KeyframeAnimationsMap::iterator it = m_runningKeyframeAnimations.find(pendingAnimation.m_keyframesName);
+                if (it == m_runningKeyframeAnimations.end()) {
+                    Vector&lt;AnimationPair&gt; firstPair;
+                    firstPair.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index));
+                    m_runningKeyframeAnimations.add(pendingAnimation.m_keyframesName, firstPair);
+                } else {
+                    Vector&lt;AnimationPair&gt;&amp; animPairs = it-&gt;second;
+                    animPairs.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index));
+                }
+            }
+        }
+        
+        m_uncomittedAnimations.clear();
+    }
+}
</ins><span class="cx"> 
</span><del>-        // Get the current value of the background color from the layer
-        CGColorRef fromBackgroundColor = [presLayer backgroundColor];
</del><ins>+void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, int index, double beginTime)
+{
+    PlatformLayer* layer = animatedLayer(property);
</ins><span class="cx"> 
</span><del>-        CGColorRef bgColor = createCGColor(color);
-        setBasicAnimation(AnimatedPropertyBackgroundColor, TransformOperation::NONE, 0, fromBackgroundColor, bgColor, true, transition, beginTime);
-        CGColorRelease(bgColor);
-    } else {
-        removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor);    
-        setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
</del><ins>+    if (beginTime) {
+        NSTimeInterval time = [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil];
+        [caAnim setBeginTime:time];
</ins><span class="cx">     }
</span><ins>+    
+    String animationName = animationIdentifier(property, index);
+    
+    [layer removeAnimationForKey:animationName];
+    [layer addAnimation:caAnim forKey:animationName];
+}
</ins><span class="cx"> 
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int index)
+{
+    PlatformLayer* layer = animatedLayer(property);
+
+    String animationName = animationIdentifier(property, index);
+
+    if (![layer animationForKey:animationName])
+        return false;
+    
+    [layer removeAnimationForKey:animationName];
+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::clearBackgroundColor()
</del><ins>+
+static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimation* to)
</ins><span class="cx"> {
</span><del>-    if (!m_contentLayerForImageOrVideo)
-        setContentsLayer(0);
-    else
-        clearLayerBackgroundColor(m_contentsLayer.get());
</del><ins>+    [to setBeginTime:[from beginTime]];
+    [to setDuration:[from duration]];
+    [to setRepeatCount:[from repeatCount]];
+    [to setAutoreverses:[from autoreverses]];
+    [to setFillMode:[from fillMode]];
+    [to setRemovedOnCompletion:[from isRemovedOnCompletion]];
+    [to setAdditive:[from isAdditive]];
+    [to setTimingFunction:[from timingFunction]];
+
+#if HAVE_MODERN_QUARTZCORE
+    [to setValueFunction:[from valueFunction]];
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setContentsOpaque(bool opaque)
</del><ins>+void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int index)
</ins><span class="cx"> {
</span><del>-    GraphicsLayer::setContentsOpaque(opaque);
</del><ins>+    PlatformLayer* layer = animatedLayer(property);
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [m_layer.get() setOpaque:m_contentsOpaque];
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    String animationName = animationIdentifier(property, index);
+
+    CAAnimation* caAnim = [layer animationForKey:animationName];
+    if (!caAnim)
+        return;
+
+    // Animations on the layer are immutable, so we have to clone and modify.
+    CAPropertyAnimation* pausedAnim = nil;
+    if ([caAnim isKindOfClass:[CAKeyframeAnimation class]]) {
+        CAKeyframeAnimation* existingKeyframeAnim = static_cast&lt;CAKeyframeAnimation*&gt;(caAnim);
+        CAKeyframeAnimation* newAnim = [CAKeyframeAnimation animationWithKeyPath:[existingKeyframeAnim keyPath]];
+        copyAnimationProperties(existingKeyframeAnim, newAnim);
+        [newAnim setValues:[existingKeyframeAnim values]];
+        [newAnim setKeyTimes:[existingKeyframeAnim keyTimes]];
+        [newAnim setTimingFunctions:[existingKeyframeAnim timingFunctions]];
+        pausedAnim = newAnim;
+    } else if ([caAnim isKindOfClass:[CABasicAnimation class]]) {
+        CABasicAnimation* existingPropertyAnim = static_cast&lt;CABasicAnimation*&gt;(caAnim);
+        CABasicAnimation* newAnim = [CABasicAnimation animationWithKeyPath:[existingPropertyAnim keyPath]];
+        copyAnimationProperties(existingPropertyAnim, newAnim);
+        [newAnim setFromValue:[existingPropertyAnim fromValue]];
+        [newAnim setToValue:[existingPropertyAnim toValue]];
+        pausedAnim = newAnim;
+    }
+
+    double t = [layer convertTime:currentTimeToMediaTime(currentTime()) fromLayer:nil];
+    [pausedAnim setSpeed:0];
+    [pausedAnim setTimeOffset:t - [caAnim beginTime]];
+    [layer addAnimation:pausedAnim forKey:animationName];  // This will replace the running animation.
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setBackfaceVisibility(bool visible)
</del><ins>+void GraphicsLayerCA::repaintLayerDirtyRects()
</ins><span class="cx"> {
</span><del>-    if (m_backfaceVisibility == visible)
</del><ins>+    if (!m_dirtyRects.size())
</ins><span class="cx">         return;
</span><ins>+
+    for (size_t i = 0; i &lt; m_dirtyRects.size(); ++i)
+        [m_layer.get() setNeedsDisplayInRect:m_dirtyRects[i]];
</ins><span class="cx">     
</span><del>-    GraphicsLayer::setBackfaceVisibility(visible);
-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [m_layer.get() setDoubleSided:visible];
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    m_dirtyRects.clear();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool GraphicsLayerCA::setOpacity(float opacity, const Animation* transition, double beginTime)
</del><ins>+bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList&amp; valueList, const Animation* animation, const String&amp; keyframesName, double beginTime)
</ins><span class="cx"> {
</span><del>-    if (forceSoftwareAnimation() &amp;&amp; transition)
-        return false;
-        
-    float clampedOpacity = max(0.0f, min(opacity, 1.0f));
</del><ins>+    ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
</ins><span class="cx">     
</span><del>-    bool opacitiesDiffer = (m_opacity != clampedOpacity);
</del><ins>+    bool isKeyframe = valueList.size() &gt; 2;
+    bool valuesOK;
</ins><span class="cx">     
</span><del>-    GraphicsLayer::setOpacity(clampedOpacity, transition, beginTime);
</del><ins>+    bool additive = false;
+    int animationIndex = 0;
</ins><span class="cx">     
</span><del>-    int animIndex = findAnimationEntry(AnimatedPropertyOpacity, 0);
-        
-    // If we don't have a transition just set the opacity
-    if (!transition || transition-&gt;isEmptyOrZeroDuration()) {
-        // Three cases:
-        //  1) no existing animation or transition: just set opacity
-        //  2) existing transition: clear it and set opacity
-        //  3) existing animation: just return
-        //
-        if (animIndex &lt; 0 || m_animations[animIndex].isTransition()) {
-            BEGIN_BLOCK_OBJC_EXCEPTIONS
-            updateOpacityOnLayer();
-            if (animIndex &gt;= 0) {
-                removeAllAnimationsForProperty(AnimatedPropertyOpacity);
-                animIndex = -1;
-            } else {
-                String keyPath = propertyIdToString(AnimatedPropertyOpacity);
-                
-                // FIXME: using hardcoded '0' here. We should be clearing all animations. For now there is only 1.
-                String animName = keyPath + &quot;_0&quot;;
-                [animatedLayer(AnimatedPropertyOpacity) removeAnimationForKey:animName];
-            }
-            END_BLOCK_OBJC_EXCEPTIONS
-        } else {
-            // We have an animation, so don't set the opacity directly.
-            return false;
-        }
</del><ins>+    CAPropertyAnimation* caAnimation;
+    if (isKeyframe) {
+        CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive);
+        valuesOK = setAnimationKeyframes(valueList, animation, keyframeAnim);
+        caAnimation = keyframeAnim;
</ins><span class="cx">     } else {
</span><del>-        // At this point, we know we have a transition. But if it is the same and
-        // the opacity value has not changed, don't do anything.
-        if (!opacitiesDiffer &amp;&amp;
-                ((animIndex == -1) ||    
-                 (m_animations[animIndex].isTransition() &amp;&amp; *(m_animations[animIndex].animation()) == *transition))) {
-            return false;
-        }
</del><ins>+        CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive);
+        valuesOK = setAnimationEndpoints(valueList, animation, basicAnim);
+        caAnimation = basicAnim;
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-#if !HAVE_MODERN_QUARTZCORE
-    // Older versions of QuartzCore do not handle opacity in transform layers properly. So we will
-    // always do software animation in that case
-    return false;
-#endif
-    
-    // If an animation is running, ignore this transition, but still save the value.
-    if (animIndex &gt;= 0 &amp;&amp; !m_animations[animIndex].isTransition())
</del><ins>+    if (!valuesOK)
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    bool didAnimate = false;
</del><ins>+    m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime));
</ins><span class="cx">     
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    
-    NSNumber* fromOpacityValue = nil;
-    NSNumber* toOpacityValue = [NSNumber numberWithFloat:opacity];
-    
-    if (transition &amp;&amp; !transition-&gt;isEmptyOrZeroDuration()) {
-        CALayer* presLayer = getPresentationLayer(primaryLayer());
-        float fromOpacity = [presLayer opacity];
-        fromOpacityValue = [NSNumber numberWithFloat:fromOpacity];
-        setBasicAnimation(AnimatedPropertyOpacity, TransformOperation::NONE, 0, fromOpacityValue, toOpacityValue, true, transition, beginTime);
-        didAnimate = true;
-    }
</del><ins>+    END_BLOCK_OBJC_EXCEPTIONS;
</ins><span class="cx"> 
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
-    
-    return didAnimate;
</del><ins>+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setNeedsDisplay()
</del><ins>+bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList&amp; valueList, const Animation* animation, const String&amp; keyframesName, double beginTime, const IntSize&amp; boxSize)
</ins><span class="cx"> {
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    
-    if (drawsContent())
-        [m_layer.get() setNeedsDisplay];
</del><ins>+    ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
</ins><span class="cx"> 
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
-}
</del><ins>+    TransformOperationList functionList;
+    bool listsMatch, hasBigRotation;
+    fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation);
</ins><span class="cx"> 
</span><del>-void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect&amp; rect)
-{
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    
-    if (drawsContent())
-        [m_layer.get() setNeedsDisplayInRect:rect];
-
-    END_BLOCK_OBJC_EXCEPTIONS
-}
-
-
-bool GraphicsLayerCA::animateTransform(const TransformValueList&amp; valueList, const IntSize&amp; size, const Animation* anim, double beginTime, bool isTransition)
-{
-    if (forceSoftwareAnimation() || !anim || anim-&gt;isEmptyOrZeroDuration() || valueList.size() &lt; 2)
-        return false;
-        
-    TransformValueList::FunctionList functionList;
-    bool isValid, hasBigRotation;
-    valueList.makeFunctionList(functionList, isValid, hasBigRotation);
-
</del><span class="cx">     // We need to fall back to software animation if we don't have setValueFunction:, and
</span><span class="cx">     // we would need to animate each incoming transform function separately. This is the
</span><span class="cx">     // case if we have a rotation &gt;= 180 or we have more than one transform function.
</span><span class="cx">     if ((hasBigRotation || functionList.size() &gt; 1) &amp;&amp; !caValueFunctionSupported())
</span><span class="cx">         return false;
</span><del>-    
-    bool success = true;
-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    
</del><ins>+
+    bool validMatrices = true;
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
</ins><span class="cx">     // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation.
</span><span class="cx">     // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation
</span><span class="cx">     // if that's not true as well.
</span><del>-    bool isMatrixAnimation = !isValid || !caValueFunctionSupported();
-        
-    // Set transform to identity since we are animating components and we need the base
-    // to be the identity transform.
-    TransformationMatrix t;
-    CATransform3D toT3D;
-    copyTransform(toT3D, t);
-    [primaryLayer() setTransform:toT3D];
-        
</del><ins>+    bool isMatrixAnimation = !listsMatch || !caValueFunctionSupported();
+    
+    size_t numAnimations = isMatrixAnimation ? 1 : functionList.size();
</ins><span class="cx">     bool isKeyframe = valueList.size() &gt; 2;
</span><del>-        
</del><ins>+    
</ins><span class="cx">     // Iterate through the transform functions, sending an animation for each one.
</span><del>-    for (int functionIndex = 0; ; ++functionIndex) {
-        if (functionIndex &gt;= static_cast&lt;int&gt;(functionList.size()) &amp;&amp; !isMatrixAnimation)
-            break;
-            
-        TransformOperation::OperationType opType = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[functionIndex];
</del><ins>+    for (size_t animationIndex = 0; animationIndex &lt; numAnimations; ++animationIndex) {
+        TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex];
+        CAPropertyAnimation* caAnimation;
</ins><span class="cx"> 
</span><ins>+        // CA applies animations in reverse order (&lt;rdar://problem/7095638&gt;) so we need the last one we add (per property)
+        // to be non-additive.
+        bool additive = animationIndex &lt; (numAnimations - 1);
</ins><span class="cx">         if (isKeyframe) {
</span><del>-            RetainPtr&lt;NSMutableArray&gt; timesArray(AdoptNS, [[NSMutableArray alloc] init]);
-            RetainPtr&lt;NSMutableArray&gt; valArray(AdoptNS, [[NSMutableArray alloc] init]);
-            RetainPtr&lt;NSMutableArray&gt; tfArray(AdoptNS, [[NSMutableArray alloc] init]);
-            
-            // Iterate through the keyframes, building arrays for the animation.
-            for (Vector&lt;TransformValue&gt;::const_iterator it = valueList.values().begin(); it != valueList.values().end(); ++it) {
-                const TransformValue&amp; curValue = (*it);
-                
-                // fill in the key time and timing function
-                [timesArray.get() addObject:[NSNumber numberWithFloat:curValue.key()]];
-                
-                const TimingFunction* tf = 0;
-                if (curValue.timingFunction())
-                    tf = curValue.timingFunction();
-                else if (anim-&gt;isTimingFunctionSet())
-                    tf = &amp;anim-&gt;timingFunction();
-                
-                CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction(LinearTimingFunction));
-                [tfArray.get() addObject:timingFunction];
-                
-                // fill in the function
-                if (isMatrixAnimation) {
-                    TransformationMatrix t;
-                    curValue.value()-&gt;apply(size, t);
-                    
-                    // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
-                    if (!t.isInvertible()) {
-                        success = false;
-                        break;
-                    }
-                    
-                    CATransform3D cat;
-                    copyTransform(cat, t);
-                    [valArray.get() addObject:[NSValue valueWithCATransform3D:cat]];
-                } else
-                    [valArray.get() addObject:getTransformFunctionValue(curValue, functionIndex, size, opType)];
-            }
-            
-            if (success) {
-                // We toss the last tfArray value because it has to be one shorter than the others.
-                [tfArray.get() removeLastObject];
-            
-                setKeyframeAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, timesArray.get(), valArray.get(), tfArray.get(), isTransition, anim, beginTime);
-            }
</del><ins>+            CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive);
+            validMatrices = setTransformAnimationKeyframes(valueList, animation, keyframeAnim, animationIndex, transformOp, isMatrixAnimation, boxSize);
+            caAnimation = keyframeAnim;
</ins><span class="cx">         } else {
</span><del>-            // Is a transition
-            id fromValue = 0;
-            id toValue = 0;
-            
-            if (isMatrixAnimation) {
-                TransformationMatrix fromt, tot;
-                valueList.at(0).value()-&gt;apply(size, fromt);
-                valueList.at(1).value()-&gt;apply(size, tot);
-
-                // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
-                if (!fromt.isInvertible() || !tot.isInvertible())
-                    success = false;
-                else {
-                    CATransform3D cat;
-                    copyTransform(cat, fromt);
-                    fromValue = [NSValue valueWithCATransform3D:cat];
-                    copyTransform(cat, tot);
-                    toValue = [NSValue valueWithCATransform3D:cat];
-                }
-            } else {
-                fromValue = getTransformFunctionValue(valueList.at(0), functionIndex, size, opType);
-                toValue = getTransformFunctionValue(valueList.at(1), functionIndex, size, opType);
-            }
-            
-            if (success)
-                setBasicAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, fromValue, toValue, isTransition, anim, beginTime);
</del><ins>+            CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive);
+            validMatrices = setTransformAnimationEndpoints(valueList, animation, basicAnim, animationIndex, transformOp, isMatrixAnimation, boxSize);
+            caAnimation = basicAnim;
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        if (isMatrixAnimation)
</del><ins>+        if (!validMatrices)
</ins><span class="cx">             break;
</span><ins>+    
+        m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
-    return success;
</del><ins>+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    return validMatrices;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValueList&amp; valueList, const Animation* animation, double beginTime)
</del><ins>+CABasicAnimation* GraphicsLayerCA::createBasicAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
</ins><span class="cx"> {
</span><del>-    if (forceSoftwareAnimation() || valueList.size() &lt; 2
-#if !HAVE_MODERN_QUARTZCORE
-        // Older versions of QuartzCore do not handle opacity in transform layers properly. So we will
-        // always do software animation in that case
-        || property == AnimatedPropertyOpacity
-#endif
-    )
-        return false;
-        
-    // if there is already is an animation for this property and it hasn't changed, ignore it.
-    int i = findAnimationEntry(property, 0);
-    if (i &gt;= 0 &amp;&amp; *m_animations[i].animation() == *animation) {
-        m_animations[i].setIsCurrent();
-        return false;
-    }
</del><ins>+    CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:propertyIdToString(property)];
+    setupAnimation(basicAnim, anim, additive);
+    return basicAnim;
+}
</ins><span class="cx"> 
</span><del>-    if (valueList.size() == 2) {
-        float fromVal = valueList.at(0).value();
-        float toVal   = valueList.at(1).value();
-        if (isnan(toVal) &amp;&amp; isnan(fromVal))
-            return false;
-    
-        // initialize the property to 0
-        [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
-        setBasicAnimation(property, TransformOperation::NONE, 0, isnan(fromVal) ? nil : [NSNumber numberWithFloat:fromVal], isnan(toVal) ? nil : [NSNumber numberWithFloat:toVal], false, animation, beginTime);
-        return true;
-    }
</del><ins>+CAKeyframeAnimation* GraphicsLayerCA::createKeyframeAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
+{
+    CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:propertyIdToString(property)];
+    setupAnimation(keyframeAnim, anim, additive);
+    return keyframeAnim;
+}
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    
-    RetainPtr&lt;NSMutableArray&gt; timesArray(AdoptNS, [[NSMutableArray alloc] init]);
-    RetainPtr&lt;NSMutableArray&gt; valArray(AdoptNS, [[NSMutableArray alloc] init]);
-    RetainPtr&lt;NSMutableArray&gt; tfArray(AdoptNS, [[NSMutableArray alloc] init]);
</del><ins>+void GraphicsLayerCA::setupAnimation(CAPropertyAnimation* propertyAnim, const Animation* anim, bool additive)
+{
+    double duration = anim-&gt;duration();
+    if (duration &lt;= 0)
+        duration = cAnimationAlmostZeroDuration;
</ins><span class="cx"> 
</span><del>-    for (unsigned i = 0; i &lt; valueList.values().size(); ++i) {
-        const FloatValue&amp; curValue = valueList.values()[i];
-        [timesArray.get() addObject:[NSNumber numberWithFloat:curValue.key()]];
-        [valArray.get() addObject:[NSNumber numberWithFloat:curValue.value()]];
</del><ins>+    float repeatCount = anim-&gt;iterationCount();
+    if (repeatCount == Animation::IterationCountInfinite)
+        repeatCount = FLT_MAX;
+    else if (anim-&gt;direction() == Animation::AnimationDirectionAlternate)
+        repeatCount /= 2;
</ins><span class="cx"> 
</span><del>-        const TimingFunction* tf = 0;
-        if (curValue.timingFunction())
-            tf = curValue.timingFunction();
-        else if (animation-&gt;isTimingFunctionSet())
-            tf = &amp;animation-&gt;timingFunction();
</del><ins>+    [propertyAnim setDuration:duration];
+    [propertyAnim setRepeatCount:repeatCount];
+    [propertyAnim setAutoreverses:anim-&gt;direction()];
+    [propertyAnim setRemovedOnCompletion:NO];
+    [propertyAnim setAdditive:additive];
+    [propertyAnim setFillMode:@&quot;extended&quot;];
</ins><span class="cx"> 
</span><del>-        CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
-        [tfArray.get() addObject:timingFunction];
-    }
-    
-    // We toss the last tfArray value because it has to one shorter than the others.
-    [tfArray.get() removeLastObject];
-    
-    // Initialize the property to 0.
-    [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
-    // Then set the animation.
-    setKeyframeAnimation(property, TransformOperation::NONE, 0, timesArray.get(), valArray.get(), tfArray.get(), false, animation, beginTime);
-
-    END_BLOCK_OBJC_EXCEPTIONS
-    return true;
</del><ins>+    [propertyAnim setDelegate:m_animationDelegate.get()];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setContentsToImage(Image* image)
</del><ins>+CAMediaTimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim)
</ins><span class="cx"> {
</span><del>-    if (image) {
-        BEGIN_BLOCK_OBJC_EXCEPTIONS
-        {
-            if (!m_contentsLayer.get()) {
-                WebLayer* imageLayer = [WebLayer layer];
-#ifndef NDEBUG
-                [imageLayer setName:@&quot;Image Layer&quot;];
-#endif
-                setContentsLayer(imageLayer);
-            }
</del><ins>+    const TimingFunction* tf = 0;
+    if (animValue-&gt;timingFunction())
+        tf = animValue-&gt;timingFunction();
+    else if (anim-&gt;isTimingFunctionSet())
+        tf = &amp;anim-&gt;timingFunction();
</ins><span class="cx"> 
</span><del>-            // FIXME: maybe only do trilinear if the image is being scaled down,
-            // but then what if the layer size changes?
-#if !defined(BUILDING_ON_TIGER) &amp;&amp; !defined(BUILDING_ON_LEOPARD)
-            [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
-#endif
-            RetainPtr&lt;CGImageRef&gt; theImage(image-&gt;nativeImageForCurrentFrame());
-            CGColorSpaceRef colorSpace = CGImageGetColorSpace(theImage.get());
</del><ins>+    return getCAMediaTimingFunction(tf ? *tf : TimingFunction());
+}
</ins><span class="cx"> 
</span><del>-            static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
-            if (CFEqual(colorSpace, deviceRGB)) {
-                // CoreGraphics renders images tagged with DeviceRGB using GenericRGB. When we hand such
-                // images to CA we need to tag them similarly so CA rendering matches CG rendering.
-                static CGColorSpaceRef genericRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
-                theImage.adoptCF(CGImageCreateCopyWithColorSpace(theImage.get(), genericRGB));
-            }
</del><ins>+bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList&amp; valueList, const Animation* anim, CABasicAnimation* basicAnim)
+{
+    id fromValue = nil;
+    id toValue = nil;
</ins><span class="cx"> 
</span><del>-            [m_contentsLayer.get() setContents:(id)theImage.get()];
</del><ins>+    switch (valueList.property()) {
+        case AnimatedPropertyOpacity: {
+            const FloatAnimationValue* startVal = static_cast&lt;const FloatAnimationValue*&gt;(valueList.at(0));
+            const FloatAnimationValue* endVal = static_cast&lt;const FloatAnimationValue*&gt;(valueList.at(1));
+            fromValue = [NSNumber numberWithFloat:startVal-&gt;value()];
+            toValue = [NSNumber numberWithFloat:endVal-&gt;value()];
+            break;
</ins><span class="cx">         }
</span><del>-        END_BLOCK_OBJC_EXCEPTIONS
-    } else
-        setContentsLayer(0);
</del><ins>+        default:
+            ASSERT_NOT_REACHED();     // we don't animate color yet
+            break;
+    }
</ins><span class="cx"> 
</span><del>-    m_contentLayerForImageOrVideo = (image != 0);
-}
</del><ins>+    // This codepath is used for 2-keyframe animations, so we still need to look in the start
+    // for a timing function.
+    CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
+    [basicAnim setTimingFunction:timingFunction];
</ins><span class="cx"> 
</span><del>-void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
-{
-    setContentsLayer(videoLayer);
-    m_contentLayerForImageOrVideo = (videoLayer != 0);
-}
</del><ins>+    [basicAnim setFromValue:fromValue];
+    [basicAnim setToValue:toValue];
</ins><span class="cx"> 
</span><del>-void GraphicsLayerCA::clearContents()
-{
-    if (m_contentLayerForImageOrVideo) {
-        setContentsLayer(0);
-        m_contentLayerForImageOrVideo = false;
-    }
</del><ins>+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::updateContentsRect()
</del><ins>+bool GraphicsLayerCA::setAnimationKeyframes(const KeyframeValueList&amp; valueList, const Animation* anim, CAKeyframeAnimation* keyframeAnim)
</ins><span class="cx"> {
</span><del>-    if (m_client &amp;&amp; m_contentsLayer) {
-        IntRect contentRect = m_client-&gt;contentsBox(this);
-        
-        CGPoint point = CGPointMake(contentRect.x(),
-                                    contentRect.y());
-        CGRect rect = CGRectMake(0.0f,
-                                 0.0f,
-                                 contentRect.width(),
-                                 contentRect.height());
</del><ins>+    RetainPtr&lt;NSMutableArray&gt; keyTimes(AdoptNS, [[NSMutableArray alloc] init]);
+    RetainPtr&lt;NSMutableArray&gt; values(AdoptNS, [[NSMutableArray alloc] init]);
+    RetainPtr&lt;NSMutableArray&gt; timingFunctions(AdoptNS, [[NSMutableArray alloc] init]);
</ins><span class="cx"> 
</span><del>-        BEGIN_BLOCK_OBJC_EXCEPTIONS
-        [m_contentsLayer.get() setPosition:point];
-        [m_contentsLayer.get() setBounds:rect];
-        END_BLOCK_OBJC_EXCEPTIONS
-    }
-}
</del><ins>+    for (unsigned i = 0; i &lt; valueList.size(); ++i) {
+        const AnimationValue* curValue = valueList.at(i);
+        [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue-&gt;keyTime()]];
</ins><span class="cx"> 
</span><del>-void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
-{
-    switch (orientation) {
-    case CompositingCoordinatesTopDown:
-#if HAVE_MODERN_QUARTZCORE
-        [m_layer.get() setGeometryFlipped:NO];
-#else
-        setChildrenTransform(TransformationMatrix());
-#endif
-        break;
-        
-    case CompositingCoordinatesBottomUp:
-#if HAVE_MODERN_QUARTZCORE
-        [m_layer.get() setGeometryFlipped:YES];
-#else
-        setChildrenTransform(flipTransform());
-#endif
-        break;
</del><ins>+        switch (valueList.property()) {
+            case AnimatedPropertyOpacity: {
+                const FloatAnimationValue* floatValue = static_cast&lt;const FloatAnimationValue*&gt;(curValue);
+                [values.get() addObject:[NSNumber numberWithFloat:floatValue-&gt;value()]];
+                break;
+            }
+            default:
+                ASSERT_NOT_REACHED();     // we don't animate color yet
+                break;
+        }
+
+        CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, anim);
+        [timingFunctions.get() addObject:timingFunction];
</ins><span class="cx">     }
</span><del>-}
</del><ins>+    
+    // We toss the last tfArray value because it has to one shorter than the others.
+    [timingFunctions.get() removeLastObject];
</ins><span class="cx"> 
</span><del>-GraphicsLayerCA::CompositingCoordinatesOrientation GraphicsLayerCA::geometryOrientation() const
-{
-    // CoreAnimation defaults to bottom-up
-    bool layerFlipped;
-#if HAVE_MODERN_QUARTZCORE
-    layerFlipped = [m_layer.get() isGeometryFlipped];
-#else
-    layerFlipped = childrenTransform().m22() == -1;
-#endif
-    return layerFlipped ? CompositingCoordinatesBottomUp : CompositingCoordinatesTopDown;
</del><ins>+    [keyframeAnim setKeyTimes:keyTimes.get()];
+    [keyframeAnim setValues:values.get()];
+    [keyframeAnim setTimingFunctions:timingFunctions.get()];
+    
+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setBasicAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation* transition, double beginTime)
</del><ins>+bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList&amp; valueList, const Animation* anim, CABasicAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOp, bool isMatrixAnimation, const IntSize&amp; boxSize)
</ins><span class="cx"> {
</span><del>-    ASSERT(fromVal || toVal);
-
-    WebLayer* layer = animatedLayer(property);
</del><ins>+    id fromValue;
+    id toValue;
</ins><span class="cx">     
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    ASSERT(valueList.size() == 2);
+    const TransformAnimationValue* startValue = static_cast&lt;const TransformAnimationValue*&gt;(valueList.at(0));
+    const TransformAnimationValue* endValue = static_cast&lt;const TransformAnimationValue*&gt;(valueList.at(1));
+    
+    if (isMatrixAnimation) {
+        TransformationMatrix fromTransform, toTransform;
+        startValue-&gt;value()-&gt;apply(boxSize, fromTransform);
+        endValue-&gt;value()-&gt;apply(boxSize, toTransform);
</ins><span class="cx"> 
</span><del>-    // add an entry for this animation
-    addAnimationEntry(property, index, isTransition, transition);
</del><ins>+        // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
+        if (!fromTransform.isInvertible() || !toTransform.isInvertible())
+            return false;
</ins><span class="cx"> 
</span><del>-    String keyPath = propertyIdToString(property);
-    String animName = keyPath + &quot;_&quot; + String::number(index);
</del><ins>+        CATransform3D caTransform;
+        copyTransform(caTransform, fromTransform);
+        fromValue = [NSValue valueWithCATransform3D:caTransform];
</ins><span class="cx"> 
</span><del>-    CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:keyPath];
-    
-    double duration = transition-&gt;duration();
-    if (duration &lt;= 0)
-        duration = cAnimationAlmostZeroDuration;
-        
-    float repeatCount = transition-&gt;iterationCount();
-    if (repeatCount == Animation::IterationCountInfinite)
-        repeatCount = FLT_MAX;
-    else if (transition-&gt;direction() == Animation::AnimationDirectionAlternate)
-        repeatCount /= 2;
-        
-    [basicAnim setDuration:duration];
-    [basicAnim setRepeatCount:repeatCount];
-    [basicAnim setAutoreverses:transition-&gt;direction()];
-    [basicAnim setRemovedOnCompletion:NO];
</del><ins>+        copyTransform(caTransform, toTransform);
+        toValue = [NSValue valueWithCATransform3D:caTransform];
+    } else {
+        fromValue = getTransformFunctionValue(startValue-&gt;value()-&gt;at(functionIndex), transformOp, boxSize);
+        toValue = getTransformFunctionValue(endValue-&gt;value()-&gt;at(functionIndex), transformOp, boxSize);
+    }
</ins><span class="cx"> 
</span><del>-    // Note that currently transform is the only property which has animations
-    // with an index &gt; 0.
-    [basicAnim setAdditive:property == AnimatedPropertyWebkitTransform];
-    [basicAnim setFillMode:@&quot;extended&quot;];
</del><ins>+    // This codepath is used for 2-keyframe animations, so we still need to look in the start
+    // for a timing function.
+    CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
+    [basicAnim setTimingFunction:timingFunction];
+
+    [basicAnim setFromValue:fromValue];
+    [basicAnim setToValue:toValue];
+
</ins><span class="cx"> #if HAVE_MODERN_QUARTZCORE
</span><del>-    if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
</del><ins>+    if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOp))
</ins><span class="cx">         [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
</span><del>-#else
-    UNUSED_PARAM(operationType);
</del><span class="cx"> #endif
</span><del>-    
-    // Set the delegate (and property value).
-    int prop = isTransition ? property : AnimatedPropertyInvalid;
-    [basicAnim setValue:[NSNumber numberWithInt:prop] forKey:WebAnimationCSSPropertyKey];
-    [basicAnim setDelegate:m_animationDelegate.get()];
</del><span class="cx"> 
</span><del>-    NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
-    [basicAnim setBeginTime:bt];
-    
-    if (fromVal)
-        [basicAnim setFromValue:reinterpret_cast&lt;id&gt;(fromVal)];
-    if (toVal)
-        [basicAnim setToValue:reinterpret_cast&lt;id&gt;(toVal)];
-
-    const TimingFunction* tf = 0;
-    if (transition-&gt;isTimingFunctionSet())
-        tf = &amp;transition-&gt;timingFunction();
-
-    CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
-    [basicAnim setTimingFunction:timingFunction];
-
-    // Send over the animation.
-    [layer removeAnimationForKey:animName];
-    [layer addAnimation:basicAnim forKey:animName];
-    
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setKeyframeAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* keys, void* values, void* timingFunctions, 
-                                    bool isTransition, const Animation* anim, double beginTime)
</del><ins>+bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList&amp; valueList, const Animation* animation, CAKeyframeAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize&amp; boxSize)
</ins><span class="cx"> {
</span><del>-    PlatformLayer* layer = animatedLayer(property);
</del><ins>+    RetainPtr&lt;NSMutableArray&gt; keyTimes(AdoptNS, [[NSMutableArray alloc] init]);
+    RetainPtr&lt;NSMutableArray&gt; values(AdoptNS, [[NSMutableArray alloc] init]);
+    RetainPtr&lt;NSMutableArray&gt; timingFunctions(AdoptNS, [[NSMutableArray alloc] init]);
</ins><span class="cx"> 
</span><del>-    // Add an entry for this animation (which may change beginTime).
-    addAnimationEntry(property, index, isTransition, anim);
</del><ins>+    for (unsigned i = 0; i &lt; valueList.size(); ++i) {
+        const TransformAnimationValue* curValue = static_cast&lt;const TransformAnimationValue*&gt;(valueList.at(i));
+        [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue-&gt;keyTime()]];
</ins><span class="cx"> 
</span><del>-    String keyPath = propertyIdToString(property);
-    String animName = keyPath + &quot;_&quot; + String::number(index);
</del><ins>+        if (isMatrixAnimation) {
+            TransformationMatrix transform;
+            curValue-&gt;value()-&gt;apply(boxSize, transform);
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
</del><ins>+            // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
+            if (!transform.isInvertible())
+                return false;
</ins><span class="cx"> 
</span><del>-    CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:keyPath];
</del><ins>+            CATransform3D caTransform;
+            copyTransform(caTransform, transform);
+            [values.get() addObject:[NSValue valueWithCATransform3D:caTransform]];
+        } else {
+            const TransformOperation* transformOp = curValue-&gt;value()-&gt;at(functionIndex);
+            [values.get() addObject:getTransformFunctionValue(transformOp, transformOpType, boxSize)];
+        }
</ins><span class="cx"> 
</span><del>-    double duration = anim-&gt;duration();
-    if (duration &lt;= 0)
-        duration = cAnimationAlmostZeroDuration;
</del><ins>+        CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, animation);
+        [timingFunctions.get() addObject:timingFunction];
+    }
+    
+    // We toss the last tfArray value because it has to one shorter than the others.
+    [timingFunctions.get() removeLastObject];
</ins><span class="cx"> 
</span><del>-    float repeatCount = anim-&gt;iterationCount();
-    if (repeatCount == Animation::IterationCountInfinite)
-        repeatCount = FLT_MAX;
-    else if (anim-&gt;direction() == Animation::AnimationDirectionAlternate)
-        repeatCount /= 2;
</del><ins>+    [keyframeAnim setKeyTimes:keyTimes.get()];
+    [keyframeAnim setValues:values.get()];
+    [keyframeAnim setTimingFunctions:timingFunctions.get()];
</ins><span class="cx"> 
</span><del>-    [keyframeAnim setDuration:duration];
-    [keyframeAnim setRepeatCount:repeatCount];
-    [keyframeAnim setAutoreverses:anim-&gt;direction()];
-    [keyframeAnim setRemovedOnCompletion:NO];
-
-    // The first animation is non-additive, all the rest are additive.
-    // Note that currently transform is the only property which has animations
-    // with an index &gt; 0.
-    [keyframeAnim setAdditive:(property == AnimatedPropertyWebkitTransform) ? YES : NO];
-    [keyframeAnim setFillMode:@&quot;extended&quot;];
</del><span class="cx"> #if HAVE_MODERN_QUARTZCORE
</span><del>-    if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
</del><ins>+    if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType))
</ins><span class="cx">         [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
</span><del>-#else
-    UNUSED_PARAM(operationType);
</del><span class="cx"> #endif
</span><del>-
-    [keyframeAnim setKeyTimes:reinterpret_cast&lt;id&gt;(keys)];
-    [keyframeAnim setValues:reinterpret_cast&lt;id&gt;(values)];
-    
-    // Set the delegate (and property value).
-    int prop = isTransition ? property : AnimatedPropertyInvalid;
-    [keyframeAnim setValue:[NSNumber numberWithInt: prop] forKey:WebAnimationCSSPropertyKey];
-    [keyframeAnim setDelegate:m_animationDelegate.get()];
-
-    NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
-    [keyframeAnim setBeginTime:bt];
-    
-    // Set the timing functions, if any.
-    if (timingFunctions != nil)
-        [keyframeAnim setTimingFunctions:(id)timingFunctions];
-        
-    // Send over the animation.
-    [layer removeAnimationForKey:animName];
-    [layer addAnimation:keyframeAnim forKey:animName];
-        
-    END_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void GraphicsLayerCA::suspendAnimations()
</span><span class="lines">@@ -1369,64 +1559,12 @@
</span><span class="cx">     [primaryLayer() setTimeOffset:0];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::removeAnimation(int index, bool reset)
</del><ins>+WebLayer* GraphicsLayerCA::hostLayerForSublayers() const
</ins><span class="cx"> {
</span><del>-    ASSERT(index &gt;= 0);
-
-    AnimatedPropertyID property = m_animations[index].property();
-    
-    // Set the value of the property and remove the animation.
-    String keyPath = propertyIdToString(property);
-    String animName = keyPath + &quot;_&quot; + String::number(m_animations[index].index());
-    CALayer* layer = animatedLayer(property);
-
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-
-    // If we are not resetting, it means we are pausing. So we need to get the current presentation
-    // value into the property before we remove the animation.
-    if (!reset) {
-        // Put the current value into the property.
-        CALayer* presLayer = [layer presentationLayer];
-        if (presLayer)
-            [layer setValue:[presLayer valueForKeyPath:keyPath] forKeyPath:keyPath];
-
-        // Make sure the saved values accurately reflect the value in the layer.
-        id val = [layer valueForKeyPath:keyPath];
-        switch (property) {
-            case AnimatedPropertyWebkitTransform:
-                // FIXME: needs comment explaining why the m_transform is not obtained from the layer
-                break;
-            case AnimatedPropertyBackgroundColor:
-                m_backgroundColor = Color(reinterpret_cast&lt;CGColorRef&gt;(val));
-                break;
-            case AnimatedPropertyOpacity:
-                m_opacity = [val floatValue];
-                break;
-            case AnimatedPropertyInvalid:
-                ASSERT_NOT_REACHED();
-                break;
-        }
-    }
-    
-    // If we have reached the end of an animation, we don't want to actually remove the 
-    // animation from the CALayer. At some point we will be setting the property to its
-    // unanimated value and at that point we will remove the animation. That will avoid
-    // any flashing between the time the animation is removed and the property is set.
-    if (!reset || m_animations[index].isTransition())
-        [layer removeAnimationForKey:animName];
-
-    END_BLOCK_OBJC_EXCEPTIONS
-
-    // Remove the animation entry.
-    m_animations.remove(index);
-}
-
-PlatformLayer* GraphicsLayerCA::hostLayerForSublayers() const
-{
</del><span class="cx">     return m_transformLayer ? m_transformLayer.get() : m_layer.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const
</del><ins>+WebLayer* GraphicsLayerCA::layerForSuperlayer() const
</ins><span class="cx"> {
</span><span class="cx">     if (m_transformLayer)
</span><span class="cx">         return m_transformLayer.get();
</span><span class="lines">@@ -1434,6 +1572,11 @@
</span><span class="cx">     return m_layer.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
+{
+    return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
+}
+
</ins><span class="cx"> PlatformLayer* GraphicsLayerCA::platformLayer() const
</span><span class="cx"> {
</span><span class="cx">     return primaryLayer();
</span><span class="lines">@@ -1466,17 +1609,8 @@
</span><span class="cx">     
</span><span class="cx">     END_BLOCK_OBJC_EXCEPTIONS
</span><span class="cx"> }
</span><ins>+#endif // NDEBUG
</ins><span class="cx"> 
</span><del>-void GraphicsLayerCA::setZPosition(float position)
-{
-    GraphicsLayer::setZPosition(position);
-    
-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    [primaryLayer() setZPosition:position];
-    END_BLOCK_OBJC_EXCEPTIONS
-}
-#endif
-
</del><span class="cx"> bool GraphicsLayerCA::requiresTiledLayer(const FloatSize&amp; size) const
</span><span class="cx"> {
</span><span class="cx">     if (!m_drawsContent)
</span><span class="lines">@@ -1486,21 +1620,21 @@
</span><span class="cx">     return size.width() &gt; cMaxPixelDimension || size.height() &gt; cMaxPixelDimension;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
</del><ins>+void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
</ins><span class="cx"> {
</span><del>-    if (userTiledLayer == m_usingTiledLayer)
</del><ins>+    if (useTiledLayer == m_usingTiledLayer)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
</span><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
-    
</del><span class="cx">     RetainPtr&lt;CALayer&gt; oldLayer = m_layer.get();
</span><span class="cx">     
</span><del>-    Class layerClass = userTiledLayer ? [WebTiledLayer self] : [WebLayer self];
</del><ins>+    Class layerClass = useTiledLayer ? [WebTiledLayer self] : [WebLayer self];
</ins><span class="cx">     m_layer.adoptNS([[layerClass alloc] init]);
</span><span class="cx"> 
</span><del>-    if (userTiledLayer) {
</del><ins>+    m_usingTiledLayer = useTiledLayer;
+
+    if (useTiledLayer) {
</ins><span class="cx">         WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get();
</span><span class="cx">         [tiledLayer setTileSize:tileSize];
</span><span class="cx">         [tiledLayer setLevelsOfDetail:1];
</span><span class="lines">@@ -1525,19 +1659,20 @@
</span><span class="cx">     [m_layer.get() setSublayers:[oldLayer.get() sublayers]];
</span><span class="cx">     
</span><span class="cx">     [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
</span><ins>+
+    updateContentsTransform();
+
+    updateLayerPosition();
+    updateLayerSize();
+    updateAnchorPoint();
+    updateTransform();
+    updateChildrenTransform();
+    updateMasksToBounds();
+    updateContentsOpaque();
+    updateBackfaceVisibility();
+    updateLayerBackgroundColor();
</ins><span class="cx">     
</span><del>-    [m_layer.get() setBounds:[oldLayer.get() bounds]];
-    [m_layer.get() setPosition:[oldLayer.get() position]];
-    [m_layer.get() setAnchorPoint:[oldLayer.get() anchorPoint]];
-    [m_layer.get() setOpaque:[oldLayer.get() isOpaque]];
</del><span class="cx">     updateOpacityOnLayer();
</span><del>-    [m_layer.get() setTransform:[oldLayer.get() transform]];
-    [m_layer.get() setSublayerTransform:[oldLayer.get() sublayerTransform]];
-    [m_layer.get() setDoubleSided:[oldLayer.get() isDoubleSided]];
-#ifndef NDEBUG
-    [m_layer.get() setZPosition:[oldLayer.get() zPosition]];
-#endif
-    updateContentsTransform();
</del><span class="cx">     
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     String name = String::format(&quot;CALayer(%p) GraphicsLayer(%p) &quot;, m_layer.get(), this) + m_name;
</span><span class="lines">@@ -1552,10 +1687,6 @@
</span><span class="cx">     // need to tell new layer to draw itself
</span><span class="cx">     setNeedsDisplay();
</span><span class="cx">     
</span><del>-    END_BLOCK_OBJC_EXCEPTIONS
-    
-    m_usingTiledLayer = userTiledLayer;
-    
</del><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     updateDebugIndicators();
</span><span class="cx"> #endif
</span><span class="lines">@@ -1586,52 +1717,28 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer)
</del><ins>+void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer)
</ins><span class="cx"> {
</span><del>-    if (contentsLayer == m_contentsLayer)
-        return;
</del><ins>+    // Turn off implicit animations on the inner layer.
+    [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@&quot;actions&quot;]];
</ins><span class="cx"> 
</span><del>-    BEGIN_BLOCK_OBJC_EXCEPTIONS
</del><ins>+    if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
+        CATransform3D flipper = {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, -1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f};
+        [contentsLayer setTransform:flipper];
+        [contentsLayer setAnchorPoint:CGPointMake(0.0f, 1.0f)];
+    } else
+        [contentsLayer setAnchorPoint:CGPointZero];
</ins><span class="cx"> 
</span><del>-    if (m_contentsLayer) {
-        [m_contentsLayer.get() removeFromSuperlayer];
-        m_contentsLayer = 0;
-    }
-    
-    if (contentsLayer) {
-        // Turn off implicit animations on the inner layer.
-        [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@&quot;actions&quot;]];
-        m_contentsLayer.adoptNS([contentsLayer retain]);
-
-        if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
-            CATransform3D flipper = {
-                1.0f, 0.0f, 0.0f, 0.0f,
-                0.0f, -1.0f, 0.0f, 0.0f,
-                0.0f, 0.0f, 1.0f, 0.0f,
-                0.0f, 0.0f, 0.0f, 1.0f};
-            [m_contentsLayer.get() setTransform:flipper];
-            [m_contentsLayer.get() setAnchorPoint:CGPointMake(0.0f, 1.0f)];
-        } else
-            [m_contentsLayer.get() setAnchorPoint:CGPointZero];
-
-        // Insert the content layer first. Video elements require this, because they have
-        // shadow content that must display in front of the video.
-        [m_layer.get() insertSublayer:m_contentsLayer.get() atIndex:0];
-
-        updateContentsRect();
-
</del><span class="cx"> #ifndef NDEBUG
</span><del>-        if (showDebugBorders()) {
-            setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
-            [m_contentsLayer.get() setBorderWidth:1.0f];
-        }
-#endif
</del><ins>+    if (showDebugBorders()) {
+        setLayerBorderColor(contentsLayer, Color(0, 0, 128, 180));
+        [contentsLayer setBorderWidth:1.0f];
</ins><span class="cx">     }
</span><del>-#ifndef NDEBUG
-    updateDebugIndicators();
</del><span class="cx"> #endif
</span><del>-
-    END_BLOCK_OBJC_EXCEPTIONS
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
</span><span class="lines">@@ -1650,7 +1757,14 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
+{
+    if (!m_uncommittedChanges &amp;&amp; m_client)
+        m_client-&gt;notifySyncRequired(this);
+
+    m_uncommittedChanges |= flags;
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> #endif // USE(ACCELERATED_COMPOSITING)
</span></span></pre></div>
<a id="trunkWebCoreplatformgraphicstransformsTransformOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/platform/graphics/transforms/TransformOperations.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/graphics/transforms/TransformOperations.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/platform/graphics/transforms/TransformOperations.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -60,6 +60,9 @@
</span><span class="cx">     Vector&lt;RefPtr&lt;TransformOperation&gt; &gt;&amp; operations() { return m_operations; }
</span><span class="cx">     const Vector&lt;RefPtr&lt;TransformOperation&gt; &gt;&amp; operations() const { return m_operations; }
</span><span class="cx"> 
</span><ins>+    size_t size() const { return m_operations.size(); }
+    const TransformOperation* at(size_t index) const { return index &lt; m_operations.size() ? m_operations.at(index).get() : 0; }
+
</ins><span class="cx"> private:
</span><span class="cx">     Vector&lt;RefPtr&lt;TransformOperation&gt; &gt; m_operations;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkWebCorerenderingRenderLayerBackingcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/rendering/RenderLayerBacking.cpp (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/rendering/RenderLayerBacking.cpp        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/rendering/RenderLayerBacking.cpp        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -55,7 +55,7 @@
</span><span class="cx">     : m_owningLayer(layer)
</span><span class="cx">     , m_ancestorClippingLayer(0)
</span><span class="cx">     , m_graphicsLayer(0)
</span><del>-    , m_contentsLayer(0)
</del><ins>+    , m_foregroundLayer(0)
</ins><span class="cx">     , m_clippingLayer(0)
</span><span class="cx">     , m_hasDirectlyCompositedContent(false)
</span><span class="cx"> {
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx"> RenderLayerBacking::~RenderLayerBacking()
</span><span class="cx"> {
</span><span class="cx">     updateClippingLayers(false, false);
</span><del>-    updateContentsLayer(false);
</del><ins>+    updateForegroundLayer(false);
</ins><span class="cx">     destroyGraphicsLayer();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -99,8 +99,8 @@
</span><span class="cx">     delete m_graphicsLayer;
</span><span class="cx">     m_graphicsLayer = 0;
</span><span class="cx"> 
</span><del>-    delete m_contentsLayer;
-    m_contentsLayer = 0;
</del><ins>+    delete m_foregroundLayer;
+    m_foregroundLayer = 0;
</ins><span class="cx"> 
</span><span class="cx">     delete m_clippingLayer;
</span><span class="cx">     m_clippingLayer = 0;
</span><span class="lines">@@ -108,7 +108,7 @@
</span><span class="cx"> 
</span><span class="cx"> void RenderLayerBacking::updateLayerOpacity()
</span><span class="cx"> {
</span><del>-    m_graphicsLayer-&gt;setOpacity(compositingOpacity(renderer()-&gt;opacity()), 0, 0);
</del><ins>+    m_graphicsLayer-&gt;setOpacity(compositingOpacity(renderer()-&gt;opacity()));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderLayerBacking::updateLayerTransform()
</span><span class="lines">@@ -152,7 +152,7 @@
</span><span class="cx">     RenderLayerCompositor* compositor = this-&gt;compositor();
</span><span class="cx"> 
</span><span class="cx">     bool layerConfigChanged = false;
</span><del>-    if (updateContentsLayer(compositor-&gt;needsContentsCompositingLayer(m_owningLayer)))
</del><ins>+    if (updateForegroundLayer(compositor-&gt;needsContentsCompositingLayer(m_owningLayer)))
</ins><span class="cx">         layerConfigChanged = true;
</span><span class="cx">     
</span><span class="cx">     if (updateClippingLayers(compositor-&gt;clippedByAncestor(m_owningLayer), compositor-&gt;clipsCompositingDescendants(m_owningLayer)))
</span><span class="lines">@@ -292,21 +292,21 @@
</span><span class="cx">         m_graphicsLayer-&gt;setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_contentsLayer) {
</del><ins>+    if (m_foregroundLayer) {
</ins><span class="cx">         // The contents layer is always coincidental with the graphicsLayer for now.
</span><del>-        m_contentsLayer-&gt;setPosition(IntPoint(0, 0));
-        m_contentsLayer-&gt;setSize(newSize);
-        m_contentsLayer-&gt;setOffsetFromRenderer(m_graphicsLayer-&gt;offsetFromRenderer());
</del><ins>+        m_foregroundLayer-&gt;setPosition(IntPoint(0, 0));
+        m_foregroundLayer-&gt;setSize(newSize);
+        m_foregroundLayer-&gt;setOffsetFromRenderer(m_graphicsLayer-&gt;offsetFromRenderer());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_graphicsLayer-&gt;updateContentsRect();
</del><ins>+    m_graphicsLayer-&gt;setContentsRect(contentsBox());
</ins><span class="cx">     if (!m_hasDirectlyCompositedContent)
</span><span class="cx">         m_graphicsLayer-&gt;setDrawsContent(!isSimpleContainerCompositingLayer() &amp;&amp; !paintingGoesToWindow());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderLayerBacking::updateInternalHierarchy()
</span><span class="cx"> {
</span><del>-    // m_contentsLayer has to be inserted in the correct order with child layers,
</del><ins>+    // m_foregroundLayer has to be inserted in the correct order with child layers,
</ins><span class="cx">     // so it's not inserted here.
</span><span class="cx">     if (m_ancestorClippingLayer) {
</span><span class="cx">         m_ancestorClippingLayer-&gt;removeAllChildren();
</span><span class="lines">@@ -363,24 +363,24 @@
</span><span class="cx">     return layersChanged;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool RenderLayerBacking::updateContentsLayer(bool needsContentsLayer)
</del><ins>+bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
</ins><span class="cx"> {
</span><span class="cx">     bool layerChanged = false;
</span><del>-    if (needsContentsLayer) {
-        if (!m_contentsLayer) {
-            m_contentsLayer = GraphicsLayer::createGraphicsLayer(this);
</del><ins>+    if (needsForegroundLayer) {
+        if (!m_foregroundLayer) {
+            m_foregroundLayer = GraphicsLayer::createGraphicsLayer(this);
</ins><span class="cx"> #ifndef NDEBUG
</span><del>-            m_contentsLayer-&gt;setName(&quot;Contents&quot;);
</del><ins>+            m_foregroundLayer-&gt;setName(&quot;Contents&quot;);
</ins><span class="cx"> #endif
</span><del>-            m_contentsLayer-&gt;setDrawsContent(true);
-            m_contentsLayer-&gt;setDrawingPhase(GraphicsLayerPaintForegroundMask);
</del><ins>+            m_foregroundLayer-&gt;setDrawsContent(true);
+            m_foregroundLayer-&gt;setDrawingPhase(GraphicsLayerPaintForegroundMask);
</ins><span class="cx">             m_graphicsLayer-&gt;setDrawingPhase(GraphicsLayerPaintBackgroundMask);
</span><span class="cx">             layerChanged = true;
</span><span class="cx">         }
</span><del>-    } else if (m_contentsLayer) {
-        m_contentsLayer-&gt;removeFromParent();
-        delete m_contentsLayer;
-        m_contentsLayer = 0;
</del><ins>+    } else if (m_foregroundLayer) {
+        m_foregroundLayer-&gt;removeFromParent();
+        delete m_foregroundLayer;
+        m_foregroundLayer = 0;
</ins><span class="cx">         m_graphicsLayer-&gt;setDrawingPhase(GraphicsLayerPaintAllMask);
</span><span class="cx">         layerChanged = true;
</span><span class="cx">     }
</span><span class="lines">@@ -657,12 +657,12 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Return the offset from the top-left of this compositing layer at which the renderer's contents are painted.
</span><del>-IntSize RenderLayerBacking::contentOffsetInCompostingLayer()
</del><ins>+IntSize RenderLayerBacking::contentOffsetInCompostingLayer() const
</ins><span class="cx"> {
</span><span class="cx">     return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-IntRect RenderLayerBacking::contentsBox(const GraphicsLayer*)
</del><ins>+IntRect RenderLayerBacking::contentsBox() const
</ins><span class="cx"> {
</span><span class="cx">     if (!renderer()-&gt;isBox())
</span><span class="cx">         return IntRect();
</span><span class="lines">@@ -700,47 +700,28 @@
</span><span class="cx"> 
</span><span class="cx"> void RenderLayerBacking::setContentsNeedDisplay()
</span><span class="cx"> {
</span><del>-    bool needViewUpdate = false;
-
-    if (m_graphicsLayer &amp;&amp; m_graphicsLayer-&gt;drawsContent()) {
</del><ins>+    if (m_graphicsLayer &amp;&amp; m_graphicsLayer-&gt;drawsContent())
</ins><span class="cx">         m_graphicsLayer-&gt;setNeedsDisplay();
</span><del>-        needViewUpdate = true;
-    }
</del><span class="cx">     
</span><del>-    if (m_contentsLayer &amp;&amp; m_contentsLayer-&gt;drawsContent()) {
-        m_contentsLayer-&gt;setNeedsDisplay();
-        needViewUpdate = true;
-    }
-    
-    // Make sure layout happens before we get rendered again.
-    if (needViewUpdate)
-        compositor()-&gt;scheduleViewUpdate();
</del><ins>+    if (m_foregroundLayer &amp;&amp; m_foregroundLayer-&gt;drawsContent())
+        m_foregroundLayer-&gt;setNeedsDisplay();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // r is in the coordinate space of the layer's render object
</span><span class="cx"> void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect&amp; r)
</span><span class="cx"> {
</span><del>-    bool needViewUpdate = false;
-
</del><span class="cx">     if (m_graphicsLayer &amp;&amp; m_graphicsLayer-&gt;drawsContent()) {
</span><span class="cx">         FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer, FloatPoint(r.x(), r.y()));
</span><span class="cx">         FloatRect dirtyRect(dirtyOrigin, r.size());
</span><span class="cx">         FloatRect bounds(FloatPoint(), m_graphicsLayer-&gt;size());
</span><del>-        if (bounds.intersects(dirtyRect)) {
</del><ins>+        if (bounds.intersects(dirtyRect))
</ins><span class="cx">             m_graphicsLayer-&gt;setNeedsDisplayInRect(dirtyRect);
</span><del>-            needViewUpdate = true;
-        }
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_contentsLayer &amp;&amp; m_contentsLayer-&gt;drawsContent()) {
</del><ins>+    if (m_foregroundLayer &amp;&amp; m_foregroundLayer-&gt;drawsContent()) {
</ins><span class="cx">         // FIXME: do incremental repaint
</span><del>-        m_contentsLayer-&gt;setNeedsDisplay();
-        needViewUpdate = true;
</del><ins>+        m_foregroundLayer-&gt;setNeedsDisplay();
</ins><span class="cx">     }
</span><del>-
-    // Make sure layout happens before we get rendered again.
-    if (needViewUpdate)
-        compositor()-&gt;scheduleViewUpdate();
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void setClip(GraphicsContext* p, const IntRect&amp; paintDirtyRect, const IntRect&amp; clipRect)
</span><span class="lines">@@ -942,8 +923,8 @@
</span><span class="cx">     if (!hasOpacity &amp;&amp; !hasTransform)
</span><span class="cx">         return false;
</span><span class="cx">     
</span><del>-    GraphicsLayer::TransformValueList transformVector;
-    GraphicsLayer::FloatValueList opacityVector;
</del><ins>+    KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
+    KeyframeValueList opacityVector(AnimatedPropertyOpacity);
</ins><span class="cx"> 
</span><span class="cx">     for (Vector&lt;KeyframeValue&gt;::const_iterator it = keyframes.beginKeyframes(); it != keyframes.endKeyframes(); ++it) {
</span><span class="cx">         const RenderStyle* keyframeStyle = it-&gt;style();
</span><span class="lines">@@ -956,19 +937,19 @@
</span><span class="cx">         const TimingFunction* tf = keyframeStyle-&gt;hasAnimations() ? &amp;((*keyframeStyle-&gt;animations()).animation(0)-&gt;timingFunction()) : 0;
</span><span class="cx">         
</span><span class="cx">         if (hasTransform)
</span><del>-            transformVector.insert(key, &amp;(keyframeStyle-&gt;transform()), tf);
-
</del><ins>+            transformVector.insert(new TransformAnimationValue(key, &amp;(keyframeStyle-&gt;transform()), tf));
+        
</ins><span class="cx">         if (hasOpacity)
</span><del>-            opacityVector.insert(key, keyframeStyle-&gt;opacity(), tf);
</del><ins>+            opacityVector.insert(new FloatAnimationValue(key, keyframeStyle-&gt;opacity(), tf));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool didAnimateTransform = !hasTransform;
</span><span class="cx">     bool didAnimateOpacity = !hasOpacity;
</span><span class="cx">     
</span><del>-    if (hasTransform &amp;&amp; m_graphicsLayer-&gt;animateTransform(transformVector, toRenderBox(renderer())-&gt;borderBoxRect().size(), anim, beginTime, false))
</del><ins>+    if (hasTransform &amp;&amp; m_graphicsLayer-&gt;addAnimation(transformVector, toRenderBox(renderer())-&gt;borderBoxRect().size(), anim, keyframes.animationName(), beginTime))
</ins><span class="cx">         didAnimateTransform = true;
</span><span class="cx"> 
</span><del>-    if (hasOpacity &amp;&amp; m_graphicsLayer-&gt;animateFloat(AnimatedPropertyOpacity, opacityVector, anim, beginTime))
</del><ins>+    if (hasOpacity &amp;&amp; m_graphicsLayer-&gt;addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), beginTime))
</ins><span class="cx">         didAnimateOpacity = true;
</span><span class="cx">     
</span><span class="cx">     bool runningAcceleratedAnimation = didAnimateTransform &amp;&amp; didAnimateOpacity;
</span><span class="lines">@@ -986,26 +967,21 @@
</span><span class="cx">     if (property == (int)CSSPropertyOpacity) {
</span><span class="cx">         const Animation* opacityAnim = toStyle-&gt;transitionForProperty(CSSPropertyOpacity);
</span><span class="cx">         if (opacityAnim &amp;&amp; !opacityAnim-&gt;isEmptyOrZeroDuration()) {
</span><del>-            // If beginTime is not 0, we are restarting this transition, so first set the from value
-            // in case it was smashed by a previous animation.
-            if (beginTime &gt; 0)
-                m_graphicsLayer-&gt;setOpacity(compositingOpacity(fromStyle-&gt;opacity()), 0, 0);
-
-            if (m_graphicsLayer-&gt;setOpacity(compositingOpacity(toStyle-&gt;opacity()), opacityAnim, beginTime))
</del><ins>+            KeyframeValueList opacityVector(AnimatedPropertyOpacity);
+            opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle-&gt;opacity())));
+            opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle-&gt;opacity())));
+            if (m_graphicsLayer-&gt;addAnimation(opacityVector, toRenderBox(renderer())-&gt;borderBoxRect().size(), opacityAnim, String(), beginTime))
</ins><span class="cx">                 didAnimate = true;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (property == (int)CSSPropertyWebkitTransform &amp;&amp; m_owningLayer-&gt;hasTransform()) {
</span><del>-        // We get a TransformOperation, which is a linked list of primitive operations and their arguments.
-        // Arguments can be floats or Length values, which need to be converted to numbers using
-        // val.calcFloatValue(renderer()-&gt;width()) (or height()).
</del><span class="cx">         const Animation* transformAnim = toStyle-&gt;transitionForProperty(CSSPropertyWebkitTransform);
</span><span class="cx">         if (transformAnim &amp;&amp; !transformAnim-&gt;isEmptyOrZeroDuration()) {
</span><del>-            GraphicsLayer::TransformValueList transformVector;
-            transformVector.insert(0, &amp;fromStyle-&gt;transform(), 0);        
-            transformVector.insert(1, &amp;toStyle-&gt;transform(), 0);        
-            if (m_graphicsLayer-&gt;animateTransform(transformVector, toRenderBox(renderer())-&gt;borderBoxRect().size(), transformAnim, beginTime, true))
</del><ins>+            KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
+            transformVector.insert(new TransformAnimationValue(0, &amp;fromStyle-&gt;transform()));
+            transformVector.insert(new TransformAnimationValue(1, &amp;toStyle-&gt;transform()));
+            if (m_graphicsLayer-&gt;addAnimation(transformVector, toRenderBox(renderer())-&gt;borderBoxRect().size(), transformAnim, String(), beginTime))
</ins><span class="cx">                 didAnimate = true;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1021,16 +997,27 @@
</span><span class="cx">     renderer()-&gt;animation()-&gt;notifyAnimationStarted(renderer(), time);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderLayerBacking::animationFinished(const String&amp; name, int index, bool reset)
</del><ins>+void RenderLayerBacking::notifySyncRequired(const GraphicsLayer*)
</ins><span class="cx"> {
</span><del>-    m_graphicsLayer-&gt;removeFinishedAnimations(name, index, reset);
</del><ins>+    if (!renderer()-&gt;documentBeingDestroyed())
+        compositor()-&gt;scheduleSync();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void RenderLayerBacking::animationFinished(const String&amp; animationName)
+{
+    m_graphicsLayer-&gt;removeAnimationsForKeyframes(animationName);
+}
+
+void RenderLayerBacking::animationPaused(const String&amp; animationName)
+{
+    m_graphicsLayer-&gt;pauseAnimation(animationName);
+}
+
</ins><span class="cx"> void RenderLayerBacking::transitionFinished(int property)
</span><span class="cx"> {
</span><span class="cx">     AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property);
</span><span class="cx">     if (animatedProperty != AnimatedPropertyInvalid)
</span><del>-        m_graphicsLayer-&gt;removeFinishedTransitions(animatedProperty);
</del><ins>+        m_graphicsLayer-&gt;removeAnimationsForProperty(animatedProperty);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderLayerBacking::suspendAnimations()
</span></span></pre></div>
<a id="trunkWebCorerenderingRenderLayerBackingh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/rendering/RenderLayerBacking.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/rendering/RenderLayerBacking.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/rendering/RenderLayerBacking.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -73,8 +73,8 @@
</span><span class="cx">     bool hasAncestorClippingLayer() const { return m_ancestorClippingLayer != 0; }
</span><span class="cx">     GraphicsLayer* ancestorClippingLayer() const { return m_ancestorClippingLayer; }
</span><span class="cx"> 
</span><del>-    bool hasContentsLayer() const { return m_contentsLayer != 0; }
-    GraphicsLayer* contentsLayer() const { return m_contentsLayer; }
</del><ins>+    bool hasContentsLayer() const { return m_foregroundLayer != 0; }
+    GraphicsLayer* foregroundLayer() const { return m_foregroundLayer; }
</ins><span class="cx">     
</span><span class="cx">     GraphicsLayer* parentForSublayers() const { return m_clippingLayer ? m_clippingLayer : m_graphicsLayer; }
</span><span class="cx">     GraphicsLayer* childForSuperlayers() const { return m_ancestorClippingLayer ? m_ancestorClippingLayer : m_graphicsLayer; }
</span><span class="lines">@@ -97,7 +97,8 @@
</span><span class="cx">     // Interface to start, finish, suspend and resume animations and transitions
</span><span class="cx">     bool startAnimation(double beginTime, const Animation* anim, const KeyframeList&amp; keyframes);
</span><span class="cx">     bool startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle);
</span><del>-    void animationFinished(const String&amp; name, int index, bool reset);
</del><ins>+    void animationFinished(const String&amp; name);
+    void animationPaused(const String&amp; name);
</ins><span class="cx">     void transitionFinished(int property);
</span><span class="cx"> 
</span><span class="cx">     void suspendAnimations();
</span><span class="lines">@@ -111,10 +112,11 @@
</span><span class="cx"> 
</span><span class="cx">     // GraphicsLayerClient interface
</span><span class="cx">     virtual void notifyAnimationStarted(const GraphicsLayer*, double startTime);
</span><ins>+    virtual void notifySyncRequired(const GraphicsLayer*);
</ins><span class="cx"> 
</span><span class="cx">     virtual void paintContents(const GraphicsLayer*, GraphicsContext&amp;, GraphicsLayerPaintingPhase, const IntRect&amp; clip);
</span><span class="cx"> 
</span><del>-    virtual IntRect contentsBox(const GraphicsLayer*);
</del><ins>+    IntRect contentsBox() const;
</ins><span class="cx">     
</span><span class="cx"> private:
</span><span class="cx">     void createGraphicsLayer();
</span><span class="lines">@@ -124,9 +126,9 @@
</span><span class="cx">     RenderLayerCompositor* compositor() const { return m_owningLayer-&gt;compositor(); }
</span><span class="cx"> 
</span><span class="cx">     bool updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip);
</span><del>-    bool updateContentsLayer(bool needsContentsLayer);
</del><ins>+    bool updateForegroundLayer(bool needsForegroundLayer);
</ins><span class="cx"> 
</span><del>-    IntSize contentOffsetInCompostingLayer();
</del><ins>+    IntSize contentOffsetInCompostingLayer() const;
</ins><span class="cx">     // Result is transform origin in pixels.
</span><span class="cx">     FloatPoint3D computeTransformOrigin(const IntRect&amp; borderBox) const;
</span><span class="cx">     // Result is perspective origin in pixels.
</span><span class="lines">@@ -162,7 +164,7 @@
</span><span class="cx"> 
</span><span class="cx">     GraphicsLayer* m_ancestorClippingLayer; // only used if we are clipped by an ancestor which is not a stacking context
</span><span class="cx">     GraphicsLayer* m_graphicsLayer;
</span><del>-    GraphicsLayer* m_contentsLayer;         // only used in cases where we need to draw the foreground separately
</del><ins>+    GraphicsLayer* m_foregroundLayer;       // only used in cases where we need to draw the foreground separately
</ins><span class="cx">     GraphicsLayer* m_clippingLayer;         // only used if we have clipping on a stacking context, with compositing children
</span><span class="cx"> 
</span><span class="cx">     IntRect m_compositedBounds;
</span></span></pre></div>
<a id="trunkWebCorerenderingRenderLayerCompositorcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/rendering/RenderLayerCompositor.cpp (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/rendering/RenderLayerCompositor.cpp        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/rendering/RenderLayerCompositor.cpp        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -124,22 +124,18 @@
</span><span class="cx"> 
</span><span class="cx"> void RenderLayerCompositor::setCompositingLayersNeedRebuild(bool needRebuild)
</span><span class="cx"> {
</span><del>-    if (inCompositingMode()) {
-        if (!m_compositingLayersNeedRebuild &amp;&amp; needRebuild)
-            scheduleViewUpdate();
-
</del><ins>+    if (inCompositingMode())
</ins><span class="cx">         m_compositingLayersNeedRebuild = needRebuild;
</span><del>-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderLayerCompositor::scheduleViewUpdate()
</del><ins>+void RenderLayerCompositor::scheduleSync()
</ins><span class="cx"> {
</span><span class="cx">     Frame* frame = m_renderView-&gt;frameView()-&gt;frame();
</span><span class="cx">     Page* page = frame ? frame-&gt;page() : 0;
</span><span class="cx">     if (!page)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    page-&gt;chrome()-&gt;client()-&gt;scheduleViewUpdate();
</del><ins>+    page-&gt;chrome()-&gt;client()-&gt;scheduleCompositingLayerSync();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot)
</span><span class="lines">@@ -635,12 +631,12 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (updateHierarchy &amp;&amp; layerBacking &amp;&amp; layerBacking-&gt;contentsLayer()) {
</del><ins>+        if (updateHierarchy &amp;&amp; layerBacking &amp;&amp; layerBacking-&gt;foregroundLayer()) {
</ins><span class="cx">             // we only have a contents layer if we have an m_layer
</span><del>-            layerBacking-&gt;contentsLayer()-&gt;removeFromParent();
</del><ins>+            layerBacking-&gt;foregroundLayer()-&gt;removeFromParent();
</ins><span class="cx"> 
</span><span class="cx">             GraphicsLayer* hostingLayer = layerBacking-&gt;clippingLayer() ? layerBacking-&gt;clippingLayer() : layerBacking-&gt;graphicsLayer();
</span><del>-            hostingLayer-&gt;addChild(layerBacking-&gt;contentsLayer());
</del><ins>+            hostingLayer-&gt;addChild(layerBacking-&gt;foregroundLayer());
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebCorerenderingRenderLayerCompositorh"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/rendering/RenderLayerCompositor.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/rendering/RenderLayerCompositor.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebCore/rendering/RenderLayerCompositor.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -64,7 +64,7 @@
</span><span class="cx">     // Copy the acceleratedCompositingEnabledFlag from Settings
</span><span class="cx">     void cacheAcceleratedCompositingEnabledFlag();
</span><span class="cx"> 
</span><del>-    // Called when the layer hierarchy needs to be udpated (compositing layers have been
</del><ins>+    // Called when the layer hierarchy needs to be updated (compositing layers have been
</ins><span class="cx">     // created, destroyed or re-parented).
</span><span class="cx">     void setCompositingLayersNeedRebuild(bool needRebuild = true);
</span><span class="cx">     bool compositingLayersNeedRebuild() const { return m_compositingLayersNeedRebuild; }
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx">     void setCompositingConsultsOverlap(bool b) { m_compositingConsultsOverlap = b; }
</span><span class="cx">     bool compositingConsultsOverlap() const { return m_compositingConsultsOverlap; }
</span><span class="cx">     
</span><del>-    void scheduleViewUpdate();
</del><ins>+    void scheduleSync();
</ins><span class="cx">     
</span><span class="cx">     // Rebuild the tree of compositing layers
</span><span class="cx">     void updateCompositingLayers(RenderLayer* updateRoot = 0);
</span></span></pre></div>
<a id="trunkWebKitmacChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/ChangeLog (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/ChangeLog        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebKit/mac/ChangeLog        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2009-07-31  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Reviewed by Anders Carlsson.
+        
+        Accelerated animations stutter on pages with lots of animations and 3d transforms
+        https://bugs.webkit.org/show_bug.cgi?id=27884
+        
+        This patch changes the strategy for synchronizing painting view the view,
+        and compositing layer updates. Previously the strategy was to disable screen
+        updates between the time we updated the layer tree, and painted the view. That
+        left screen updates disabled for too long (hundreds of milliseconds) in some
+        cases, causing animation stutter.
+        
+        The new strategy is to batch up changes to the CA layer tree, and commit them
+        all at once just before painting happens (referred to as a &quot;sync&quot; in the code).
+        GraphicsLayerCA now keeps a bitmask of changed properties, and then migrates
+        the values stored in GraphicsLayer into the CA layer tree at commit time.
+        
+        Compositing layers are then synced in FrameView::paintContents(). However, not
+        all style/layout changes will result in painting; to deal with style changes that
+        touch only compositing properties, we set up a runloop observer that takes care
+        of comitting layer changes when no painting happens.
+
+        * WebCoreSupport/WebChromeClient.h:
+        * WebCoreSupport/WebChromeClient.mm:
+        (WebChromeClient::scheduleCompositingLayerSync):
+        scheduleViewUpdate() renamed to syncCompositingStateRecursive()
+        
+        * WebView/WebView.mm:
+        (-[WebView _close]):
+        (-[WebView _clearLayerSyncLoopObserver]):
+        &quot;viewUpdateRunLoopObserver&quot; is now &quot;layerSyncLoopObserver&quot;.
+
+        (-[WebView _syncCompositingChanges]):
+        Helper method that calls syncCompositingStateRecursive() on the FrameView.
+        
+        (layerSyncRunLoopObserverCallBack):
+        (-[WebView _scheduleCompositingLayerSync]):
+        This is all about layer sycning now. Also, the run loop observer is repeating,
+        because it has to keep firing until syncCompositingStateRecursive() says that it
+        has completed.
+        
+        * WebView/WebViewData.h:
+        &quot;viewUpdateRunLoopObserver&quot; is now &quot;layerSyncLoopObserver&quot;.
+
+        * WebView/WebViewInternal.h:
+        _scheduleViewUpdate is now _scheduleCompositingLayerSync
+
</ins><span class="cx"> 2009-07-30  Michael Nordman  &lt;michaeln@google.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Darin Fisher.
</span></span></pre></div>
<a id="trunkWebKitmacWebCoreSupportWebChromeClienth"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/WebCoreSupport/WebChromeClient.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/WebCoreSupport/WebChromeClient.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebKit/mac/WebCoreSupport/WebChromeClient.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -146,7 +146,7 @@
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><span class="cx">     virtual void attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer*);
</span><span class="cx">     virtual void setNeedsOneShotDrawingSynchronization();
</span><del>-    virtual void scheduleViewUpdate();
</del><ins>+    virtual void scheduleCompositingLayerSync();
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     virtual void requestGeolocationPermissionForFrame(WebCore::Frame*, WebCore::Geolocation*);
</span></span></pre></div>
<a id="trunkWebKitmacWebCoreSupportWebChromeClientmm"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/WebCoreSupport/WebChromeClient.mm (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/WebCoreSupport/WebChromeClient.mm        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebKit/mac/WebCoreSupport/WebChromeClient.mm        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -706,10 +706,10 @@
</span><span class="cx">     END_BLOCK_OBJC_EXCEPTIONS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebChromeClient::scheduleViewUpdate()
</del><ins>+void WebChromeClient::scheduleCompositingLayerSync()
</ins><span class="cx"> {
</span><span class="cx">     BEGIN_BLOCK_OBJC_EXCEPTIONS;
</span><del>-    [m_webView _scheduleViewUpdate];
</del><ins>+    [m_webView _scheduleCompositingLayerSync];
</ins><span class="cx">     END_BLOCK_OBJC_EXCEPTIONS;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebKitmacWebViewWebViewmm"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/WebView/WebView.mm (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/WebView/WebView.mm        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebKit/mac/WebView/WebView.mm        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -363,7 +363,7 @@
</span><span class="cx"> - (BOOL)_continuousCheckingAllowed;
</span><span class="cx"> - (NSResponder *)_responderForResponderOperations;
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><del>-- (void)_clearViewUpdateRunLoopObserver;
</del><ins>+- (void)_clearLayerSyncLoopObserver;
</ins><span class="cx"> #endif
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="lines">@@ -1031,7 +1031,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><del>-    [self _clearViewUpdateRunLoopObserver];
</del><ins>+    [self _clearLayerSyncLoopObserver];
</ins><span class="cx"> #endif
</span><span class="cx">     
</span><span class="cx">     [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
</span><span class="lines">@@ -5101,14 +5101,14 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if USE(ACCELERATED_COMPOSITING)
</span><del>-- (void)_clearViewUpdateRunLoopObserver
</del><ins>+- (void)_clearLayerSyncLoopObserver
</ins><span class="cx"> {
</span><del>-    if (!_private-&gt;viewUpdateRunLoopObserver)
</del><ins>+    if (!_private-&gt;layerSyncRunLoopObserver)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    CFRunLoopObserverInvalidate(_private-&gt;viewUpdateRunLoopObserver);
-    CFRelease(_private-&gt;viewUpdateRunLoopObserver);
-    _private-&gt;viewUpdateRunLoopObserver = 0;
</del><ins>+    CFRunLoopObserverInvalidate(_private-&gt;layerSyncRunLoopObserver);
+    CFRelease(_private-&gt;layerSyncRunLoopObserver);
+    _private-&gt;layerSyncRunLoopObserver = 0;
</ins><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> @end
</span><span class="lines">@@ -5396,59 +5396,75 @@
</span><span class="cx">         [self didChangeValueForKey:UsingAcceleratedCompositingProperty];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (BOOL)_syncCompositingChanges
+{
+    Frame* frame = [self _mainCoreFrame];
+    if (frame &amp;&amp; frame-&gt;view())
+        return frame-&gt;view()-&gt;syncCompositingStateRecursive();
+
+    return YES;
+}
+
</ins><span class="cx"> /*
</span><span class="cx">     The order of events with compositing updates is this:
</span><span class="cx">     
</span><span class="cx">    Start of runloop                                        End of runloop
</span><span class="cx">         |                                                       |
</span><span class="cx">       --|-------------------------------------------------------|--
</span><del>-           ^                                           ^     ^
-           |                                           |     |
-    NSWindow update,                                   |  CA commit
-     NSView drawing                                    |
-        flush                                          |
-                                      viewUpdateRunLoopObserverCallBack
</del><ins>+           ^         ^                                        ^
+           |         |                                        |
+    NSWindow update, |                                     CA commit
+     NSView drawing  |                                  
+        flush        |                                  
+                layerSyncRunLoopObserverCallBack
</ins><span class="cx"> 
</span><del>-    The viewUpdateRunLoopObserverCallBack is required to ensure that
-    layout has happened before CA commits layer changes (it's analagous to
-    -viewWillDraw for NSViews).
</del><ins>+    To avoid flashing, we have to ensure that compositing changes (rendered via
+    the CoreAnimation rendering display link) appear on screen at the same time
+    as content painted into the window via the normal WebCore rendering path.
+
+    CoreAnimation will commit any layer changes at the end of the runloop via
+    its &quot;CA commit&quot; observer. Those changes can then appear onscreen at any time
+    when the display link fires, which can result in unsynchronized rendering.
</ins><span class="cx">     
</span><del>-    CA commits on a run loop observer at the end of the cycle.
-    It is also rendering via a CV display link continuously. So we have to
-    ensure that layer updates committed at the end of the runloop cycle don't get
-    to the screen via the display link until the window flush at the start
-    of the next cycle. Thus, viewUpdateRunLoopObserverCallBack has to
-    call -disableScreenUpdatesUntilFlush to stop screen updates until the flush
-    at the start of the next runloop cycle.
</del><ins>+    To fix this, the GraphicsLayerCA code in WebCore does not change the CA
+    layer tree during style changes and layout; it stores up all changes and
+    commits them via syncCompositingState(). There are then two situations in
+    which we can call syncCompositingState():
</ins><span class="cx">     
</span><del>-    See also -[WebView drawRect:], where we also do a -disableScreenUpdatesUntilFlush.
</del><ins>+    1. When painting. FrameView::paintContents() makes a call to syncCompositingState().
+    
+    2. When style changes/layout have made changes to the layer tree which do not
+       result in painting. In this case we need a run loop observer to do a
+       syncCompositingState() at an appropriate time. The observer will keep firing
+       until the time is right (essentially when there are no more pending layouts).
+    
</ins><span class="cx"> */
</span><span class="cx"> 
</span><del>-static void viewUpdateRunLoopObserverCallBack(CFRunLoopObserverRef, CFRunLoopActivity, void* info)
</del><ins>+static void layerSyncRunLoopObserverCallBack(CFRunLoopObserverRef, CFRunLoopActivity, void* info)
</ins><span class="cx"> {
</span><span class="cx">     WebView* webView = reinterpret_cast&lt;WebView*&gt;(info);
</span><del>-    [webView _viewWillDrawInternal];
-    [webView _clearViewUpdateRunLoopObserver];
-    if ([webView _needsOneShotDrawingSynchronization])
-        [[webView window] disableScreenUpdatesUntilFlush];
</del><ins>+    if ([webView _syncCompositingChanges])
+        [webView _clearLayerSyncLoopObserver];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)_scheduleViewUpdate
</del><ins>+- (void)_scheduleCompositingLayerSync
</ins><span class="cx"> {
</span><del>-    if (_private-&gt;viewUpdateRunLoopObserver)
</del><ins>+    if (_private-&gt;layerSyncRunLoopObserver)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    // Run before AppKit does its window update.
-    const CFIndex runLoopOrder = NSDisplayWindowRunLoopOrdering - 1;
</del><ins>+    // Run after AppKit does its window update. If we do any painting, we'll commit
+    // layer changes from FrameView::paintContents(), otherwise we'll commit via
+    // _syncCompositingChanges when this observer fires.
+    const CFIndex runLoopOrder = NSDisplayWindowRunLoopOrdering + 1;
</ins><span class="cx"> 
</span><span class="cx">     // The WebView always outlives the observer, so no need to retain/release.
</span><span class="cx">     CFRunLoopObserverContext context = { 0, self, 0, 0, 0 };
</span><span class="cx"> 
</span><del>-    _private-&gt;viewUpdateRunLoopObserver = CFRunLoopObserverCreate(NULL,
-        kCFRunLoopBeforeWaiting | kCFRunLoopExit, FALSE /* one shot */,
-        runLoopOrder, viewUpdateRunLoopObserverCallBack, &amp;context);
</del><ins>+    _private-&gt;layerSyncRunLoopObserver = CFRunLoopObserverCreate(NULL,
+        kCFRunLoopBeforeWaiting | kCFRunLoopExit, true /* repeats */,
+        runLoopOrder, layerSyncRunLoopObserverCallBack, &amp;context);
</ins><span class="cx"> 
</span><del>-    CFRunLoopAddObserver(CFRunLoopGetCurrent(), _private-&gt;viewUpdateRunLoopObserver, kCFRunLoopCommonModes);
</del><ins>+    CFRunLoopAddObserver(CFRunLoopGetCurrent(), _private-&gt;layerSyncRunLoopObserver, kCFRunLoopCommonModes);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkWebKitmacWebViewWebViewDatah"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/WebView/WebViewData.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/WebView/WebViewData.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebKit/mac/WebView/WebViewData.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -138,7 +138,7 @@
</span><span class="cx">     // Number of WebHTMLViews using accelerated compositing. Used to implement _isUsingAcceleratedCompositing.
</span><span class="cx">     int acceleratedFramesCount;
</span><span class="cx">     // Run loop observer used to implement the compositing equivalent of -viewWillDraw
</span><del>-    CFRunLoopObserverRef viewUpdateRunLoopObserver;
</del><ins>+    CFRunLoopObserverRef layerSyncRunLoopObserver;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     NSPasteboard *insertionPasteboard;
</span></span></pre></div>
<a id="trunkWebKitmacWebViewWebViewInternalh"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/WebView/WebViewInternal.h (46644 => 46645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/WebView/WebViewInternal.h        2009-07-31 22:46:25 UTC (rev 46644)
+++ trunk/WebKit/mac/WebView/WebViewInternal.h        2009-07-31 23:03:25 UTC (rev 46645)
</span><span class="lines">@@ -87,7 +87,7 @@
</span><span class="cx"> - (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization;
</span><span class="cx"> - (void)_startedAcceleratedCompositingForFrame:(WebFrame*)webFrame;
</span><span class="cx"> - (void)_stoppedAcceleratedCompositingForFrame:(WebFrame*)webFrame;
</span><del>-- (void)_scheduleViewUpdate;
</del><ins>+- (void)_scheduleCompositingLayerSync;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> @end
</span></span></pre>
</div>
</div>

</body>
</html>