[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

simon.fraser at apple.com simon.fraser at apple.com
Thu Apr 8 01:10:30 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 823f73c8b85c68b577cc5d1dd5b4182ff4458f35
Author: simon.fraser at apple.com <simon.fraser at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Sat Jan 16 05:07:42 2010 +0000

    2010-01-15  Simon Fraser  <simon.fraser at apple.com>
    
            Reviewed by Dan Bernstein and Adele Peterson.
    
            Support reflections on composited layers
            https://bugs.webkit.org/show_bug.cgi?id=31885
    
            Implement reflections (via -webkit-box-reflect:) on compositing layers.
    
            We add to the GraphicsLayer the notion of having a replica, and being a replicated layer.
            The replica layer is not parented in the tree, but referenced by another layer.
            RenderLayerBacking sets this up when it finds RenderLayers for reflections.
    
            GraphicsLayerCA implements rendering of replica layers by cloning CA layers,
            and copying their properties, including animations and contents. Deep reflections
            are supported by a hash of clone layers on each GraphicsLayerCA, indexed by
            the path down the tree to each replica instance.
    
            When GraphicsLayerCA properties are changed, in most cases the clones must also
            be updated.
    
            Tests: compositing/masks/direct-image-mask.html
                   compositing/reflections/animation-inside-reflection.html
                   compositing/reflections/compositing-change-inside-reflection.html
                   compositing/reflections/deeply-nested-reflections.html
                   compositing/reflections/masked-reflection-on-composited.html
                   compositing/reflections/nested-reflection-anchor-point.html
                   compositing/reflections/nested-reflection-animated.html
                   compositing/reflections/nested-reflection-mask-change.html
                   compositing/reflections/nested-reflection-on-overflow.html
                   compositing/reflections/nested-reflection-opacity.html
                   compositing/reflections/nested-reflection-size-change.html
                   compositing/reflections/nested-reflection-transformed.html
                   compositing/reflections/nested-reflection-transition.html
                   compositing/reflections/nested-reflection.html
                   compositing/reflections/reflection-opacity.html
                   compositing/reflections/reflection-ordering.html
                   compositing/reflections/reflection-positioning.html
                   compositing/reflections/transform-inside-reflection.html
    
            * platform/graphics/GraphicsLayer.h:
            (WebCore::GraphicsLayer::isReplicated): Returns true when this layer has a replicated layer.
            (WebCore::GraphicsLayer::replicatedLayerPosition):
            (WebCore::GraphicsLayer::setReplicatedLayerPosition): The position of the replica layer must be
            special-cased; we cannot just copy the position of the original.
            (WebCore::GraphicsLayer::didDisplay): Method that indicates that the contents of the layer changed,
            which gives us a chance to update clone layers.
            (WebCore::GraphicsLayer::replicaLayer): reference to the replica layer.
            (WebCore::GraphicsLayer::replicatedLayer): reference to the layer that this (replica) layer is replicating.
            (WebCore::GraphicsLayer::setReplicatedLayer):
    
            * platform/graphics/GraphicsLayer.cpp:
            (WebCore::GraphicsLayer::GraphicsLayer):
            (WebCore::GraphicsLayer::setReplicatedByLayer): Hook up a replica with its replicated layer.
            (WebCore::GraphicsLayer::dumpProperties):
    
            * platform/graphics/mac/GraphicsLayerCA.h:
            (WebCore::GraphicsLayerCA::primaryLayer): Returns a CALayer, since structural layers may not be WebLayers.
            (WebCore::GraphicsLayerCA::isReplicatedRootClone): Given a cloneID (string representation of the path to a clone
            down the tree, which is a bitstring of 1 (replica), or 0 (non-replica)), returns true if this ID represents the
            root of a replica tree.
            (WebCore::GraphicsLayerCA::primaryLayerClones): Returns a pointer to the hash map of clones of the primary layers.
    
            (WebCore::GraphicsLayerCA::ReplicaState::ReplicaState): Small struct used to track original/clone branching
            down the tree during recursion, to build cloneID paths.
    
            (WebCore::GraphicsLayerCA::hasCloneLayers): returns true if this layer has clone layers.
    
            * platform/graphics/mac/GraphicsLayerCA.mm:
            (WebCore::GraphicsLayerCA::~GraphicsLayerCA): remove the clone layers.
            (WebCore::GraphicsLayerCA::setChildren): call noteSublayersChanged() since we may have to update replicas too.
            (WebCore::GraphicsLayerCA::addChild): ditto
            (WebCore::GraphicsLayerCA::addChildAtIndex): ditto
            (WebCore::GraphicsLayerCA::addChildBelow): ditto
            (WebCore::GraphicsLayerCA::addChildAbove): ditto
            (WebCore::GraphicsLayerCA::replaceChild): ditto
            (WebCore::GraphicsLayerCA::removeFromParent): ditto
            (WebCore::GraphicsLayerCA::setMaskLayer): call propagateLayerChangeToReplicas()
            (WebCore::GraphicsLayerCA::setReplicatedLayer): note replica changed.
            (WebCore::GraphicsLayerCA::setReplicatedByLayer): ditto
            (WebCore::GraphicsLayerCA::moveOrCopyAllAnimationsForProperty): Enhanced to allow moving or copying animations.
            (WebCore::GraphicsLayerCA::moveOrCopyAnimationsForProperty): Ditto.
            (WebCore::GraphicsLayerCA::setContentsToImage): call noteSublayersChanged()
            (WebCore::GraphicsLayerCA::setContentsToVideo): call noteSublayersChanged()
            (WebCore::GraphicsLayerCA::didDisplay): here is our chance to copy updated contents to clone layers.
            (WebCore::GraphicsLayerCA::recursiveCommitChanges):
            (WebCore::GraphicsLayerCA::commitLayerChangesBeforeSublayers): pre-order commit, for things that need to be
                committed before we recurse on children.
            (WebCore::GraphicsLayerCA::commitLayerChangesAfterSublayers): post-order commit, for things that need to be
                committed after we recurse on children, like clones.
            (WebCore::GraphicsLayerCA::updateLayerNames): New method to match the other 'update' methods.
            (WebCore::GraphicsLayerCA::updateSublayerList): Insert replica layers into the hierarchy.
            (WebCore::GraphicsLayerCA::updateLayerPosition): update clones.
            (WebCore::GraphicsLayerCA::updateLayerSize): ditto
            (WebCore::GraphicsLayerCA::updateAnchorPoint): ditto
            (WebCore::GraphicsLayerCA::updateTransform): ditto
            (WebCore::GraphicsLayerCA::updateChildrenTransform): ditto
            (WebCore::GraphicsLayerCA::updateMasksToBounds): ditto
            (WebCore::GraphicsLayerCA::updateContentsOpaque): ditto
            (WebCore::GraphicsLayerCA::updateBackfaceVisibility): ditto
            (WebCore::GraphicsLayerCA::updateStructuralLayer): call ensureStructuralLayer()
            (WebCore::moveAnimation): utility to move a CAAnimation from one layer to another.
            (WebCore::GraphicsLayerCA::ensureStructuralLayer): refactored code which creates enclosing CALayers for reflection
            flattening, or CATransformLayers for preserve-3d.
            (WebCore::GraphicsLayerCA::structuralLayerPurpose): indicates why we need a structural layer.
            (WebCore::GraphicsLayerCA::updateLayerDrawsContent): update clones
            (WebCore::GraphicsLayerCA::updateContentsImage): ditto
            (WebCore::GraphicsLayerCA::updateContentsRect): ditto
            (WebCore::GraphicsLayerCA::updateMaskLayer): ditto
            (WebCore::GraphicsLayerCA::updateReplicatedLayers): This is where we ask for the tree of layers for the replica
            and its children, and attach them as sublayers.
            (WebCore::GraphicsLayerCA::ReplicaState::cloneID): Build a bitstring from the array of original/clone values; this
            string serves to identify clones in the hash map.
            (WebCore::GraphicsLayerCA::replicatedLayerRoot): Request the tree of clone layers, set its position and transform,
            and return it.
            (WebCore::GraphicsLayerCA::setAnimationOnLayer): update clones
            (WebCore::GraphicsLayerCA::removeAnimationFromLayer): ditto
            (WebCore::GraphicsLayerCA::pauseAnimationOnLayer): ditto
            (WebCore::GraphicsLayerCA::setContentsToGraphicsContext3D): udpate sublayers.
            (WebCore::GraphicsLayerCA::suspendAnimations): update clones.
            (WebCore::GraphicsLayerCA::resumeAnimations): ditto
            (WebCore::GraphicsLayerCA::animatedLayerClones): return the hash map for clones of the appropriate layer for the given property.
            (WebCore::GraphicsLayerCA::ensureCloneLayers): create and return clones for the CALayers for this layer.
            (WebCore::GraphicsLayerCA::removeCloneLayers): clear out the clone layers.
            (WebCore::GraphicsLayerCA::positionForCloneRootLayer): the root of a clonal subtree needs its position and transform to be special-cased,
            since it doesn't just copy those properties from the original.
            (WebCore::GraphicsLayerCA::propagateLayerChangeToReplicas): push the change flags onto the replica.
            (WebCore::GraphicsLayerCA::fetchCloneLayers): recurse down sublayers, creating clones of the CALayers along the way, and returning
            the root of the clone tree.
            (WebCore::copyAnimation): utility to copy an animation from one layer to another. Animations can be shared between layers.
            (WebCore::GraphicsLayerCA::cloneLayer): utility to clone a CALayer, copying those properties which GraphicsLayerCA makes use of
            (WebCore::GraphicsLayerCA::setOpacityInternal): push opacity changes to clones.
            (WebCore::GraphicsLayerCA::updateOpacityOnLayer): ditto
            (WebCore::GraphicsLayerCA::noteSublayersChanged): set the ChildrenChanged flag, and proprate changes to the replica, if any.
    
            * platform/graphics/mac/WebLayer.mm:
            (-[WebLayer display]): override -display so we know when to update the contents of clone layers
    
            * platform/graphics/mac/WebTiledLayer.mm:
            (-[WebTiledLayer display]): ditto.
    
            * rendering/RenderLayer.h:
            (WebCore::RenderLayer::isReflection): New method that returns true if the renderer is a replica.
    
            * rendering/RenderLayer.cpp:
            (WebCore::RenderLayer::RenderLayer): initialize m_isReflection
            (WebCore::RenderLayer::updateReflectionStyle): call setIsReflection
    
            * rendering/RenderLayerBacking.cpp:
            (WebCore::RenderLayerBacking::createGraphicsLayer): Put a name on the reflection layer.
            (WebCore::RenderLayerBacking::updateGraphicsLayerConfiguration): Hook up the GraphicsLayers for the reflection.
            (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry): Reflection overrides preserve-3d (you have to flatten to reflect).
            Also hook up updating the reflection layer geometry, and the relica position.
    
            (WebCore::RenderLayerBacking::paintIntoLayer): We no longer paint the reflection in software.
    
            * rendering/RenderLayerCompositor.cpp:
            (WebCore::RenderLayerCompositor::computeCompositingRequirements): Hook reflection layers into the compositing logic.
            (WebCore::RenderLayerCompositor::canAccelerateVideoRendering): No longer have to push video into software if it's reflected.
            (WebCore::RenderLayerCompositor::rebuildCompositingLayerTree): Update the bounds of the reflection layer.
            (WebCore::RenderLayerCompositor::updateCompositingDescendantGeometry): ditto
            (WebCore::RenderLayerCompositor::requiresCompositingWhenDescendantsAreCompositing): a compositing descendant forces
            a reflection ancestor to composite now.
            (WebCore::RenderLayerBacking::containsPaintedContent): Reflection layers don't paint anything.
            (WebCore::RenderLayerBacking::isDirectlyCompositedImage): No need to fall out of direct compositing mode
            for masks or reflections any more.
            (WebCore::RenderLayerBacking::paintIntoLayer): No need to paint the reflection manually now.
    
            * rendering/RenderObject.h:
            (WebCore::RenderObject::isReplica):
            * rendering/RenderReplica.h:
            (WebCore::RenderReplica::isReplica):
            New method used to determine if a render is a replica.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@53357 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index a6c1598..1f4de17 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,85 @@
+2010-01-15  Simon Fraser  <simon.fraser at apple.com>
+
+        Reviewed by Dan Bernstein and Adele Peterson.
+
+        Support reflections on composited layers
+        https://bugs.webkit.org/show_bug.cgi?id=31885
+        
+        Tests for reflections on compositing layers.
+
+        * compositing/masks/direct-image-mask.html: Added.
+        * compositing/reflections/animation-inside-reflection.html: Added.
+        * compositing/reflections/compositing-change-inside-reflection.html: Added.
+        * compositing/reflections/deeply-nested-reflections.html: Added.
+        * compositing/reflections/masked-reflection-on-composited.html: Added.
+        * compositing/reflections/nested-reflection-anchor-point.html: Added.
+        * compositing/reflections/nested-reflection-animated.html: Added.
+        * compositing/reflections/nested-reflection-mask-change.html: Added.
+        * compositing/reflections/nested-reflection-on-overflow.html: Added.
+        * compositing/reflections/nested-reflection-opacity.html: Added.
+        * compositing/reflections/nested-reflection-size-change.html: Added.
+        * compositing/reflections/nested-reflection-transformed.html: Added.
+        * compositing/reflections/nested-reflection-transition.html: Added.
+        * compositing/reflections/nested-reflection.html: Added.
+        * compositing/reflections/reflection-opacity.html: Added.
+        * compositing/reflections/reflection-ordering.html: Added.
+        * compositing/reflections/reflection-positioning.html: Added.
+        * compositing/reflections/transform-inside-reflection.html: Added.
+        * platform/mac/compositing/masks/direct-image-mask-expected.checksum: Added.
+        * platform/mac/compositing/masks/direct-image-mask-expected.png: Added.
+        * platform/mac/compositing/masks/direct-image-mask-expected.txt: Copied from LayoutTests/platform/mac/compositing/reflections/simple-composited-reflections-expected.txt.
+        * platform/mac/compositing/reflections/animation-inside-reflection-expected.checksum: Added.
+        * platform/mac/compositing/reflections/animation-inside-reflection-expected.png: Added.
+        * platform/mac/compositing/reflections/animation-inside-reflection-expected.txt: Added.
+        * platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.checksum: Added.
+        * platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.png: Added.
+        * platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.txt: Added.
+        * platform/mac/compositing/reflections/deeply-nested-reflections-expected.checksum: Added.
+        * platform/mac/compositing/reflections/deeply-nested-reflections-expected.png: Added.
+        * platform/mac/compositing/reflections/deeply-nested-reflections-expected.txt: Added.
+        * platform/mac/compositing/reflections/masked-reflection-on-composited-expected.checksum: Added.
+        * platform/mac/compositing/reflections/masked-reflection-on-composited-expected.png: Added.
+        * platform/mac/compositing/reflections/masked-reflection-on-composited-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-animated-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-animated-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-animated-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-mask-change-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-mask-change-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-mask-change-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-opacity-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-opacity-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-opacity-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-size-change-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-size-change-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-size-change-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-transformed-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-transformed-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-transformed-expected.txt: Added.
+        * platform/mac/compositing/reflections/nested-reflection-transition-expected.checksum: Added.
+        * platform/mac/compositing/reflections/nested-reflection-transition-expected.png: Added.
+        * platform/mac/compositing/reflections/nested-reflection-transition-expected.txt: Added.
+        * platform/mac/compositing/reflections/reflection-opacity-expected.checksum: Added.
+        * platform/mac/compositing/reflections/reflection-opacity-expected.png: Added.
+        * platform/mac/compositing/reflections/reflection-opacity-expected.txt: Added.
+        * platform/mac/compositing/reflections/reflection-ordering-expected.checksum: Added.
+        * platform/mac/compositing/reflections/reflection-ordering-expected.png: Added.
+        * platform/mac/compositing/reflections/reflection-ordering-expected.txt: Added.
+        * platform/mac/compositing/reflections/reflection-positioning-expected.checksum: Added.
+        * platform/mac/compositing/reflections/reflection-positioning-expected.png: Added.
+        * platform/mac/compositing/reflections/reflection-positioning-expected.txt: Added.
+        * platform/mac/compositing/reflections/transform-inside-reflection-expected.checksum: Added.
+        * platform/mac/compositing/reflections/transform-inside-reflection-expected.png: Added.
+        * platform/mac/compositing/reflections/transform-inside-reflection-expected.txt: Added.
+
 2010-01-15  Doug Muir  <dmuir at google.com>
 
         Fix some Layout Test timeouts when run under valgrind.
diff --git a/LayoutTests/compositing/masks/direct-image-mask.html b/LayoutTests/compositing/masks/direct-image-mask.html
new file mode 100644
index 0000000..dbadb09
--- /dev/null
+++ b/LayoutTests/compositing/masks/direct-image-mask.html
@@ -0,0 +1,30 @@
+<!DOCTYPE>
+
+<html>
+<head>
+  <title>Simple composited reflections</title>
+  <style type="text/css" media="screen">
+
+      img {
+        margin: 20px;
+      }
+
+      .compositing {
+        -webkit-transform: translateZ(0);
+      }
+
+      .masked {
+        -webkit-mask-image: url(../resources/alpha-gradient.png);
+        -webkit-mask-repeat: repeat-y;
+      }
+
+  </style>
+</head>
+<body>
+
+  <p>Testing reflections on directly composited images. Left and right sides should look the same.</p>
+  <img class="masked" src="../resources/thiswayup.png" width="184" height="124">
+  <img class="compositing masked" src="../resources/thiswayup.png" width="184" height="124">
+
+</body>
+</html>
diff --git a/LayoutTests/compositing/reflections/animation-inside-reflection.html b/LayoutTests/compositing/reflections/animation-inside-reflection.html
new file mode 100644
index 0000000..73e9e3e
--- /dev/null
+++ b/LayoutTests/compositing/reflections/animation-inside-reflection.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 240px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    text-align: center;
+    font-size: 50pt;
+    border: 2px solid blue;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  #animated {
+    margin: 10px;
+    width: 80px;
+    height: 80px;
+    background-color: green;
+  }
+  
+  #animated.animated {
+    -webkit-animation: swing 1s linear 1;
+  }
+  
+  /* for manual testing */
+  #animated:hover {
+    -webkit-animation-play-state: paused;
+  }
+  
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  
+  @-webkit-keyframes swing {
+    from { -webkit-transform: rotate(0deg); }
+    to   { -webkit-transform: rotate(90deg); }
+  }
+  </style>
+  <script src="../../animations/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+    const expectedValues = [
+      // [animation-name, time, element-id, property, expected-value, tolerance]
+      [null, 0.5, "animated", "webkitTransform.0", 0.76, 0.1],
+    ];
+    
+    function startAnimation()
+    {
+      document.getElementById('animated').className = 'animated';
+    }
+
+    runAnimationTest(expectedValues, startAnimation, 'load', false, true /* pixel test */);
+  </script>
+  </head>
+<body>
+  <p>The top left box, and all reflections should be rotated 45deg.</p>
+  <div class="outer">
+    <div id="inner" class="inner">
+      <div id="animated"></div>
+    </div>
+  </div>
+  <div id="result"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/compositing-change-inside-reflection.html b/LayoutTests/compositing/reflections/compositing-change-inside-reflection.html
new file mode 100644
index 0000000..85dfd45
--- /dev/null
+++ b/LayoutTests/compositing/reflections/compositing-change-inside-reflection.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style type="text/css" media="screen">
+    div {
+      -webkit-box-sizing: border-box;
+    }
+    .reflected {
+      position: absolute;
+      height: 120px;
+      width: 120px;
+      margin-bottom: 120px;
+      border: 1px solid black;
+      -webkit-box-reflect: below 2px;
+    }
+
+    #inner {
+      height: 100px;
+      width: 100px;
+      margin: 10px;
+      background-color: green;
+    }
+    .composited {
+      -webkit-transform: translateZ(0);
+    }
+    
+    .container {
+      position: relative;
+    }
+    #indicator {
+      position: absolute;
+      top: 131px;
+      left: 11px;
+      height: 100px;
+      width: 100px;
+      background-color: red;
+    }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    if (window.layoutTestController)
+      layoutTestController.waitUntilDone();
+
+    function doTest()
+    {
+      window.setTimeout(function() {
+        document.getElementById('inner').className = 'composited';
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 0);
+    }
+    window.addEventListener('load', doTest, false);
+  </script>
+</head>
+<body>
+
+<p>Test dynamically created compositing layer inside reflection. You should see no red below.</p>
+<div class="container">
+  <div id="indicator"></div>
+  <div class="reflected compositing">
+    <div id="inner"></div>
+  </div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/compositing/reflections/deeply-nested-reflections.html b/LayoutTests/compositing/reflections/deeply-nested-reflections.html
new file mode 100644
index 0000000..99c3d8d
--- /dev/null
+++ b/LayoutTests/compositing/reflections/deeply-nested-reflections.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+  "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  
+  <style type="text/css" media="screen">
+    
+    div {
+      -webkit-box-sizing: border-box;
+      border: 1px solid black;
+      margin: 2px;
+    }
+
+    .level4 {
+      width: 234px;
+      height: 240px;
+      border-color: black;
+      -webkit-box-reflect: below 4px;
+    }
+
+    .level3 {
+      width: 228px;
+      height: 234px;
+      border-color: orange;
+      -webkit-box-reflect: right 4px;
+    }
+
+    .level2 {
+      width: 222px;
+      height: 112px;
+      border-color: blue;
+      -webkit-box-reflect: below 4px;
+    }
+    
+    .level1 {
+      width: 106px;
+      height: 106px;
+      border-color: red;
+      -webkit-box-reflect: right 4px;
+    }
+    
+    .box {
+      width: 100px;
+      height: 100px;
+      text-align: center;
+      font-size: 48pt;
+      background-color: green;
+    }
+    .compositing {
+      -webkit-transform: translateZ(0);
+    }
+    
+  </style>
+  
+</head>
+<body>
+  
+  <p>Deeply nested reflections.</p>
+  <div class="level4">
+    <div class="level3">
+      <div class="level2">
+        <div class="level1">
+          <div class="compositing box">C</div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+</body>
+</html>
diff --git a/LayoutTests/compositing/reflections/masked-reflection-on-composited.html b/LayoutTests/compositing/reflections/masked-reflection-on-composited.html
new file mode 100644
index 0000000..dde9fee
--- /dev/null
+++ b/LayoutTests/compositing/reflections/masked-reflection-on-composited.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style type="text/css" media="screen">
+    .box {
+      height: 100px;
+      width: 100px;
+      margin: 20px;
+      margin-bottom: 120px;
+      background-color: green;
+    }
+    
+    .reflected {
+      -webkit-box-reflect: below 2px
+          -webkit-gradient(linear, left top, left bottom, from(transparent), to(white));
+    }
+
+    .composited {
+      -webkit-transform: translateZ(0);
+    }
+  </style>
+</head>
+<body>
+
+<p>Reflection should be masked with gradient.</p>
+<div class="reflected composited box">
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/compositing/reflections/nested-reflection-anchor-point.html b/LayoutTests/compositing/reflections/nested-reflection-anchor-point.html
new file mode 100644
index 0000000..7f5a679
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-anchor-point.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px 60px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-box-reflect: below 10px;
+    -webkit-transform: rotate3d(0, 0, 1, 20deg);
+  }
+  
+  .changed {
+    -webkit-transform-origin: top left;
+  }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    if (window.layoutTestController)
+      layoutTestController.waitUntilDone();
+
+    function doTest()
+    {
+      window.setTimeout(function() {
+        document.getElementById('inner').className = 'inner composited changed';
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 0);
+    }
+    window.addEventListener('load', doTest, false);
+  </script>
+  </head>
+<body>
+  <p>Left and right sides should look symmetrical.</p>
+  <div class="outer composited">
+    <div id="inner" class="inner composited">
+      1
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/nested-reflection-animated.html b/LayoutTests/compositing/reflections/nested-reflection-animated.html
new file mode 100644
index 0000000..1a972a4
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-animated.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px 100px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-box-reflect: below 10px;
+  }
+
+  .inner.animated {
+    -webkit-animation: swing 1s linear 1 alternate;
+  }
+
+  .inner:hover {
+    -webkit-animation-play-state: paused;
+  }
+  
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  
+  @-webkit-keyframes swing {
+    from { -webkit-transform: rotate(0deg); }
+    to   { -webkit-transform: rotate(90deg); }
+  }
+  </style>
+  <script src="../../animations/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+    const expectedValues = [
+      // [animation-name, time, element-id, property, expected-value, tolerance]
+      [null, 0.5, "inner", "webkitTransform.0", 0.76, 0.1],
+    ];
+    
+    function startAnimation()
+    {
+      document.getElementById('inner').className = 'inner composited animated';
+    }
+
+    runAnimationTest(expectedValues, startAnimation, 'load', false, true /* pixel test */);
+  </script>
+  </head>
+<body>
+  <p>Animation on original and reflection should both be paused half way through, giving 45deg rotation.</p>
+  <div class="outer composited">
+    <div id="inner" class="inner composited">
+      1
+    </div>
+  </div>
+  <div id="result"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/nested-reflection-mask-change.html b/LayoutTests/compositing/reflections/nested-reflection-mask-change.html
new file mode 100644
index 0000000..1b836de
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-mask-change.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  
+  .masked {
+    -webkit-mask: -webkit-gradient(linear, left top, right top, from(transparent), to(white));
+  }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    if (window.layoutTestController)
+      layoutTestController.waitUntilDone();
+
+    function doTest()
+    {
+      window.setTimeout(function() {
+        document.getElementById('inner').className = 'inner composited masked';
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 0);
+    }
+    window.addEventListener('load', doTest, false);
+  </script>
+  </head>
+<body>
+<p>The four green squares should all have the mask applied.</p>
+  <div class="outer box composited">
+    <div id="inner" class="inner composited">
+      1
+    </div>
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/reflections/nested-reflection-on-overflow.html b/LayoutTests/compositing/reflections/nested-reflection-on-overflow.html
new file mode 100644
index 0000000..cbf67ee
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-on-overflow.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+
+  .overflow {
+    position: relative;
+    overflow: scroll;
+    width: 100%;
+    height: 100%;
+    z-index: 0;
+  }
+  .content {
+    height: 500px;
+  }
+  </style>
+  </head>
+<body>
+<p>You should see the original and three copies of the green box with text.</p>
+  <div class="outer composited">
+    <div class="inner composited">
+      <div class="overflow">
+        <div class="content composited">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div>
+      </div>
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/nested-reflection-opacity.html b/LayoutTests/compositing/reflections/nested-reflection-opacity.html
new file mode 100644
index 0000000..e37477b
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-opacity.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    if (window.layoutTestController)
+      layoutTestController.waitUntilDone();
+
+    function doTest()
+    {
+      window.setTimeout(function() {
+        document.getElementById('inner').style.opacity = '0.5';
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 0);
+    }
+    window.addEventListener('load', doTest, false);
+  </script>
+  </head>
+<body>
+<p>The four green squares should look equally transparent.</p>
+  <div class="outer box composited">
+    <div id="inner" class="inner box composited">
+      1
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/nested-reflection-size-change.html b/LayoutTests/compositing/reflections/nested-reflection-size-change.html
new file mode 100644
index 0000000..5a479d5
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-size-change.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 140px;
+    height: 270px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  .bigger {
+    width: 120px;
+    height: 120px;
+  }
+  .composited {
+    -webkit-transform: rotate3d(0, 0, 1, 0);
+  }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    if (window.layoutTestController)
+      layoutTestController.waitUntilDone();
+
+    function doTest()
+    {
+      window.setTimeout(function() {
+        document.getElementById('inner').className = 'inner composited bigger';
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 0);
+    }
+    window.addEventListener('load', doTest, false);
+  </script>
+  </head>
+<body>
+<p>The four green squares should all be lined up.</p>
+  <div class="outer box composited">
+    <div id="inner" class="inner box composited">
+      1
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/nested-reflection-transformed.html b/LayoutTests/compositing/reflections/nested-reflection-transformed.html
new file mode 100644
index 0000000..2d9af15
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-transformed.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    function doTest()
+    {
+      document.getElementById('inner').style.webkitTransform = 'rotate(10deg)';
+    }
+    window.addEventListener('load', doTest, false);
+  </script>
+  </head>
+<body>
+  <p>Test transform change on reflected elements. Left and right side should be symmetrical.</p>
+  <div class="outer composited">
+    <div id="inner" class="inner composited">
+      1
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/nested-reflection-transition.html b/LayoutTests/compositing/reflections/nested-reflection-transition.html
new file mode 100644
index 0000000..ab2c975
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection-transition.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .reflected {
+    width: 100px;
+    height: 100px;
+    -webkit-box-reflect: below 10px;
+  }
+
+  #inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-transition: -webkit-transform 1s linear;
+  }
+  
+  .rotated {
+    -webkit-transform: rotate(90deg);
+  }
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  </style>
+  <script src="../../transitions/transition-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+
+    const expectedValues = [
+      // [time, element-id, property, expected-value, tolerance]
+      [0.5, 'inner', '-webkit-transform.1', 0.76, 0.1],
+    ];
+
+    function setupTest()
+    {
+      document.getElementById('inner').className = 'rotated';
+    }
+    runTransitionTest(expectedValues, setupTest, true /* use pause API */, true /* pixel test */);
+  </script>
+  </head>
+<body>
+  <div class="outer composited">
+    <div class="reflected composited">
+      <div id="inner">
+        1
+      </div>
+    </div>
+  </div>
+  <div id="result"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/nested-reflection.html b/LayoutTests/compositing/reflections/nested-reflection.html
new file mode 100644
index 0000000..027301c
--- /dev/null
+++ b/LayoutTests/compositing/reflections/nested-reflection.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+
+  </style>
+  </head>
+<body>
+<p>You should see the original and three copies of the blue box.</p>
+  <div class="outer composited">
+    <div class="inner composited">
+      1
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/reflection-opacity.html b/LayoutTests/compositing/reflections/reflection-opacity.html
new file mode 100644
index 0000000..740c2f3
--- /dev/null
+++ b/LayoutTests/compositing/reflections/reflection-opacity.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <style type="text/css" media="screen">
+      
+      div {
+        -webkit-box-sizing: border-box;
+      }
+      .reflected {
+        position: relative;
+        width: 150px;
+        height: 100px;
+        background-color: green;
+        opacity: 0.5;
+        -webkit-box-reflect: below -50px;
+      }
+      
+      .composited {
+        -webkit-transform: translateZ(0);
+      }
+
+    </style>
+    <script type="text/javascript" charset="utf-8">
+      function doTest() {
+        document.getElementById('inner').className = 'inner moved box';
+      }
+      window.addEventListener('load', doTest, false);
+    </script>
+  </head>
+  
+  <p>Opacity should be applied after reflection, so you should see a green rectangle below. The overlap between the original and reflection should not be visible.</p>
+  <div class="reflected composited">
+  </div>
+
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/reflection-ordering.html b/LayoutTests/compositing/reflections/reflection-ordering.html
new file mode 100644
index 0000000..86cb534
--- /dev/null
+++ b/LayoutTests/compositing/reflections/reflection-ordering.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+
+<html lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <title>Reflections Ordering</title>
+  <style type="text/css" media="screen">
+    .reflected {
+      height: 100px;
+      width: 200px;
+      margin: 20px;
+      border: 10px solid black;
+      font-size: 18pt;
+      text-align: center;
+      background-color: white;
+      -webkit-transform: translateZ(0);
+      -webkit-box-reflect: below -80px;
+    }
+
+    .composited {
+      -webkit-transform: translateZ(0);
+    }
+  </style>
+</head>
+<body>
+
+<p>You should see a black rectangle divided into two parts; the top part should be taller (reflection should be behind original).</p>
+<div class="reflected composited">Contents</div>
+
+</body>
+</html>
diff --git a/LayoutTests/compositing/reflections/reflection-positioning.html b/LayoutTests/compositing/reflections/reflection-positioning.html
new file mode 100644
index 0000000..46d4a91
--- /dev/null
+++ b/LayoutTests/compositing/reflections/reflection-positioning.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <style type="text/css" media="screen">
+      
+      div {
+        -webkit-box-sizing: border-box;
+      }
+      .container {
+        position: absolute;
+        left: 20px;
+        top: 50px;
+      }
+      .reflected {
+        position: relative;
+        width: 150px;
+        height: 120px;
+        border: 1px solid black;
+        -webkit-box-reflect: below 6px;
+      }
+      
+      .box {
+        width: 100px;
+        height: 100px;
+      }
+
+      .inner {
+        position: absolute;
+        top: 10px;
+        left: 10px;
+        background-color: green;
+      }
+
+      .composited {
+        -webkit-transform: translateZ(0);
+      }
+
+      .inner.moved {
+        left: 25px;
+      }
+      
+      #indicator {
+        position: absolute;
+        top: 135px;
+        left: 26px;
+        background-color: red;
+      }
+    </style>
+    <script type="text/javascript" charset="utf-8">
+      function doTest() {
+        document.getElementById('inner').className = 'inner moved box';
+      }
+      window.addEventListener('load', doTest, false);
+    </script>
+  </head>
+  
+  <p>Position of reflected layer should update correctly. You should see no red below.</p>
+  <div class="container">
+    <div id="indicator" class="box"></div>
+    <div class="reflected composited">
+      <div id="inner" class="inner box">
+      </div>
+    </div>
+  </div>
+
+</html>
\ No newline at end of file
diff --git a/LayoutTests/compositing/reflections/transform-inside-reflection.html b/LayoutTests/compositing/reflections/transform-inside-reflection.html
new file mode 100644
index 0000000..1c627e2
--- /dev/null
+++ b/LayoutTests/compositing/reflections/transform-inside-reflection.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <style>
+  .outer {
+    width: 120px;
+    height: 230px;
+    margin: 20px;
+    border: 1px solid black;
+    -webkit-box-reflect: right 10px;
+  }
+  
+  .inner {
+    margin: 10px;
+    width: 100px;
+    height: 100px;
+    border: 1px solid black;
+    -webkit-box-reflect: below 10px;
+  }
+  
+  #transformed {
+    margin: 10px;
+    width: 80px;
+    height: 80px;
+    background-color: green;
+    text-align: center;
+    font-size: 50pt;
+  }
+  
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    function doTest()
+    {
+      document.getElementById('transformed').style.webkitTransform = 'rotate3d(0, 0, 1, 10deg)';
+    }
+    window.addEventListener('load', doTest, false);
+  </script>
+  </head>
+<body>
+  <p>Transform inside nested reflections should be applied correctly. You should see four rotated green boxes, as mirror images of each other.</p>
+  <div class="outer">
+    <div id="inner" class="inner">
+      <div id="transformed"></div>
+    </div>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.checksum b/LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.checksum
new file mode 100644
index 0000000..75292b1
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.checksum
@@ -0,0 +1 @@
+100c0fda2a75a648a198ea33b5cee90a
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.png b/LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.png
new file mode 100644
index 0000000..4e7b72e
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/simple-composited-reflections-expected.txt b/LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.txt
similarity index 100%
copy from LayoutTests/platform/mac/compositing/reflections/simple-composited-reflections-expected.txt
copy to LayoutTests/platform/mac/compositing/masks/direct-image-mask-expected.txt
diff --git a/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.checksum
new file mode 100644
index 0000000..4b5c4a6
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.checksum
@@ -0,0 +1 @@
+8946182c3f5076878f01a8b59932c89e
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.png b/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.png
new file mode 100644
index 0000000..dcc066d
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.txt b/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.txt
new file mode 100644
index 0000000..cbf4f58
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/animation-inside-reflection-expected.txt
@@ -0,0 +1,18 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x342
+  RenderBlock {HTML} at (0,0) size 800x342
+    RenderBody {BODY} at (8,16) size 784x318
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 379x18
+          text run at (0,0) width 379: "The top left box, and all reflections should be rotated 45deg."
+      RenderBlock {DIV} at (0,300) size 784x18
+        RenderText {#text} at (0,0) size 625x18
+          text run at (0,0) width 625: "PASS - \"webkitTransform.0\" property for \"animated\" element at 0.5s saw something close to: 0.76"
+        RenderBR {BR} at (625,0) size 0x18
+layer at (28,54) size 122x242
+  RenderBlock {DIV} at (20,38) size 122x242 [border: (1px solid #000000)]
+layer at (39,65) size 104x104
+  RenderBlock {DIV} at (11,11) size 104x104 [border: (2px solid #0000FF)]
+layer at (51,77) size 80x80
+  RenderBlock {DIV} at (12,12) size 80x80 [bgcolor=#008000]
diff --git a/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.checksum
new file mode 100644
index 0000000..cfc3802
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.checksum
@@ -0,0 +1 @@
+69c20dc2fc88b068c61207608eef0190
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.png b/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.png
new file mode 100644
index 0000000..70ff394
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.txt b/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.txt
new file mode 100644
index 0000000..bcd4edc
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/compositing-change-inside-reflection-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x50
+  RenderBlock {HTML} at (0,0) size 800x50
+    RenderBody {BODY} at (8,16) size 784x18
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 574x18
+          text run at (0,0) width 574: "Test dynamically created compositing layer inside reflection. You should see no red below."
+layer at (19,181) size 100x100
+  RenderBlock (positioned) {DIV} at (11,131) size 100x100 [bgcolor=#FF0000]
+layer at (8,50) size 120x120
+  RenderBlock (positioned) {DIV} at (0,0) size 120x120 [border: (1px solid #000000)]
+layer at (19,61) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
diff --git a/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.checksum
new file mode 100644
index 0000000..b3979d8
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.checksum
@@ -0,0 +1 @@
+14aa41bab0c9af314a403bf555b276ab
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.png b/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.png
new file mode 100644
index 0000000..30a1eac
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.txt b/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.txt
new file mode 100644
index 0000000..41b3849
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/deeply-nested-reflections-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x298
+  RenderBlock {HTML} at (0,0) size 800x298
+    RenderBody {BODY} at (8,16) size 784x274
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 163x18
+          text run at (0,0) width 163: "Deeply nested reflections."
+layer at (10,50) size 234x240
+  RenderBlock {DIV} at (2,34) size 234x240 [border: (1px solid #000000)]
+layer at (13,53) size 228x234
+  RenderBlock {DIV} at (3,3) size 228x234 [border: (1px solid #FFA500)]
+layer at (16,56) size 222x112
+  RenderBlock {DIV} at (3,3) size 222x112 [border: (1px solid #0000FF)]
+layer at (19,59) size 106x106
+  RenderBlock {DIV} at (3,3) size 106x106 [border: (1px solid #FF0000)]
+layer at (22,62) size 100x100
+  RenderBlock {DIV} at (3,3) size 100x100 [bgcolor=#008000] [border: (1px solid #000000)]
+    RenderText {#text} at (28,1) size 43x74
+      text run at (28,1) width 43: "C"
diff --git a/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.checksum
new file mode 100644
index 0000000..78b8f57
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.checksum
@@ -0,0 +1 @@
+15849b2e215bbc6fb5a526d8867f4b71
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.png b/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.png
new file mode 100644
index 0000000..e59e4c4
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.txt b/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.txt
new file mode 100644
index 0000000..20021c0
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/masked-reflection-on-composited-expected.txt
@@ -0,0 +1,10 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x274
+  RenderBlock {HTML} at (0,0) size 800x274
+    RenderBody {BODY} at (8,16) size 784x138
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 273x18
+          text run at (0,0) width 273: "Reflection should be masked with gradient."
+layer at (28,54) size 100x100
+  RenderBlock {DIV} at (20,38) size 100x100 [bgcolor=#008000]
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.checksum
new file mode 100644
index 0000000..29f40c6
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.checksum
@@ -0,0 +1 @@
+ac58aeca26db80e701f0069fe38a9a57
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.png
new file mode 100644
index 0000000..e8b0e07
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.txt
new file mode 100644
index 0000000..9ad0675
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-anchor-point-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x306
+  RenderBlock {HTML} at (0,0) size 800x306
+    RenderBody {BODY} at (8,16) size 784x270
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 283x18
+          text run at (0,0) width 283: "Left and right sides should look symmetrical."
+layer at (68,54) size 122x232
+  RenderBlock {DIV} at (60,38) size 122x232 [border: (1px solid #000000)]
+layer at (79,65) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
+    RenderText {#text} at (33,0) size 34x77
+      text run at (33,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.checksum
new file mode 100644
index 0000000..5ea9789
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.checksum
@@ -0,0 +1 @@
+57880e6e873a3d3bad58f2b4a9a486f2
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.png
new file mode 100644
index 0000000..6b86757
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.txt
new file mode 100644
index 0000000..e7781f4
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.txt
@@ -0,0 +1,18 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x332
+  RenderBlock {HTML} at (0,0) size 800x332
+    RenderBody {BODY} at (8,16) size 784x308
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 633x18
+          text run at (0,0) width 633: "Animation on original and reflection should both be paused half way through, giving 45deg rotation."
+      RenderBlock {DIV} at (0,290) size 784x18
+        RenderText {#text} at (0,0) size 600x18
+          text run at (0,0) width 600: "PASS - \"webkitTransform.0\" property for \"inner\" element at 0.5s saw something close to: 0.76"
+        RenderBR {BR} at (600,0) size 0x18
+layer at (108,54) size 122x232
+  RenderBlock {DIV} at (100,38) size 122x232 [border: (1px solid #000000)]
+layer at (119,65) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
+    RenderText {#text} at (33,0) size 34x77
+      text run at (33,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.checksum
new file mode 100644
index 0000000..53207c6
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.checksum
@@ -0,0 +1 @@
+eed68807ff77668f5488a4ef8f1c60ee
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.png
new file mode 100644
index 0000000..ebd1d7e
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.txt
new file mode 100644
index 0000000..94e3c73
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x306
+  RenderBlock {HTML} at (0,0) size 800x306
+    RenderBody {BODY} at (8,16) size 784x270
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 382x18
+          text run at (0,0) width 382: "You should see the original and three copies of the blue box."
+layer at (28,54) size 122x232
+  RenderBlock {DIV} at (20,38) size 122x232 [border: (1px solid #000000)]
+layer at (39,65) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
+    RenderText {#text} at (33,0) size 34x77
+      text run at (33,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.checksum
new file mode 100644
index 0000000..ae08179
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.checksum
@@ -0,0 +1 @@
+be1c6ffd368b11f86c851a525932f8bd
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.png
new file mode 100644
index 0000000..0a739f6
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.txt
new file mode 100644
index 0000000..fb3db39
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-mask-change-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x306
+  RenderBlock {HTML} at (0,0) size 800x306
+    RenderBody {BODY} at (8,16) size 784x270
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 358x18
+          text run at (0,0) width 358: "The four green squares should all have the mask applied."
+layer at (28,54) size 122x232
+  RenderBlock {DIV} at (20,38) size 122x232 [border: (1px solid #000000)]
+layer at (39,65) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
+    RenderText {#text} at (33,0) size 34x77
+      text run at (33,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.checksum
new file mode 100644
index 0000000..9058bbc
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.checksum
@@ -0,0 +1 @@
+66b4852d3b139eafc971ddf8ee67d6e4
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.png
new file mode 100644
index 0000000..764aa62
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.txt
new file mode 100644
index 0000000..44adf53
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-on-overflow-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x306
+  RenderBlock {HTML} at (0,0) size 800x306
+    RenderBody {BODY} at (8,16) size 784x270
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 449x18
+          text run at (0,0) width 449: "You should see the original and three copies of the green box with text."
+layer at (28,54) size 122x232
+  RenderBlock {DIV} at (20,38) size 122x232 [border: (1px solid #000000)]
+layer at (39,65) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
+layer at (39,65) size 100x100 clip at (39,65) size 85x85 scrollHeight 500
+  RenderBlock (relative positioned) {DIV} at (0,0) size 100x100
+layer at (39,65) size 85x500 backgroundClip at (39,65) size 85x85 clip at (39,65) size 85x85 outlineClip at (39,65) size 85x85
+  RenderBlock {DIV} at (0,0) size 85x500
+    RenderText {#text} at (0,0) size 84x414
+      text run at (0,0) width 84: "Lorem ipsum"
+      text run at (0,18) width 51: "dolor sit"
+      text run at (0,36) width 34: "amet,"
+      text run at (0,54) width 71: "consectetur"
+      text run at (0,72) width 68: "adipisicing"
+      text run at (0,90) width 68: "elit, sed do"
+      text run at (0,108) width 53: "eiusmod"
+      text run at (0,126) width 44: "tempor"
+      text run at (0,144) width 79: "incididunt ut"
+      text run at (0,162) width 54: "labore et"
+      text run at (0,180) width 40: "dolore"
+      text run at (0,198) width 42: "magna"
+      text run at (0,216) width 62: "aliqua. Ut"
+      text run at (0,234) width 50: "enim ad"
+      text run at (0,252) width 40: "minim"
+      text run at (0,270) width 80: "veniam, quis"
+      text run at (0,288) width 47: "nostrud"
+      text run at (0,306) width 73: "exercitation"
+      text run at (0,324) width 50: "ullamco"
+      text run at (0,342) width 84: "laboris nisi ut"
+      text run at (0,360) width 80: "aliquip ex ea"
+      text run at (0,378) width 63: "commodo"
+      text run at (0,396) width 67: "consequat."
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.checksum
new file mode 100644
index 0000000..a5f32d0
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.checksum
@@ -0,0 +1 @@
+78648ad1c5504cbfce7d01f8237d6d5e
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.png
new file mode 100644
index 0000000..79e0e0f
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.txt
new file mode 100644
index 0000000..e8d074b
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-opacity-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x306
+  RenderBlock {HTML} at (0,0) size 800x306
+    RenderBody {BODY} at (8,16) size 784x270
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 350x18
+          text run at (0,0) width 350: "The four green squares should look equally transparent."
+layer at (28,54) size 122x232
+  RenderBlock {DIV} at (20,38) size 122x232 [border: (1px solid #000000)]
+layer at (39,65) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
+    RenderText {#text} at (33,0) size 34x77
+      text run at (33,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.checksum
new file mode 100644
index 0000000..2baaa1a
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.checksum
@@ -0,0 +1 @@
+2604f00941aac6e26ba2b5cdd7901fd3
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.png
new file mode 100644
index 0000000..175c3bc
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.txt
new file mode 100644
index 0000000..906f630
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-size-change-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x346
+  RenderBlock {HTML} at (0,0) size 800x346
+    RenderBody {BODY} at (8,16) size 784x310
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 288x18
+          text run at (0,0) width 288: "The four green squares should all be lined up."
+layer at (28,54) size 142x272
+  RenderBlock {DIV} at (20,38) size 142x272 [border: (1px solid #000000)]
+layer at (39,65) size 120x120
+  RenderBlock {DIV} at (11,11) size 120x120 [bgcolor=#008000]
+    RenderText {#text} at (43,0) size 34x77
+      text run at (43,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.checksum
new file mode 100644
index 0000000..249c896
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.checksum
@@ -0,0 +1 @@
+968c3680a1b1b0608c17f8ecd2379f23
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.png
new file mode 100644
index 0000000..4289fe4
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.txt
new file mode 100644
index 0000000..58509ca
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transformed-expected.txt
@@ -0,0 +1,14 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x306
+  RenderBlock {HTML} at (0,0) size 800x306
+    RenderBody {BODY} at (8,16) size 784x270
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 549x18
+          text run at (0,0) width 549: "Test transform change on reflected elements. Left and right side should be symmetrical."
+layer at (28,54) size 122x232
+  RenderBlock {DIV} at (20,38) size 122x232 [border: (1px solid #000000)]
+layer at (39,65) size 100x100
+  RenderBlock {DIV} at (11,11) size 100x100 [bgcolor=#008000]
+    RenderText {#text} at (33,0) size 34x77
+      text run at (33,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.checksum
new file mode 100644
index 0000000..ec520c1
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.checksum
@@ -0,0 +1 @@
+9db1abeed1cce4cf9c0c1fe9b812ba67
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.png b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.png
new file mode 100644
index 0000000..b4020c1
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.txt b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.txt
new file mode 100644
index 0000000..cdca8b5
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.txt
@@ -0,0 +1,17 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x298
+  RenderBlock {HTML} at (0,0) size 800x298
+    RenderBody {BODY} at (8,20) size 784x270
+      RenderBlock {DIV} at (0,252) size 784x18
+        RenderText {#text} at (0,0) size 604x18
+          text run at (0,0) width 604: "PASS - \"-webkit-transform.1\" property for \"inner\" element at 0.5s saw something close to: 0.76"
+        RenderBR {BR} at (604,0) size 0x18
+layer at (28,20) size 122x232
+  RenderBlock {DIV} at (20,0) size 122x232 [border: (1px solid #000000)]
+layer at (29,31) size 100x100
+  RenderBlock {DIV} at (1,11) size 100x100
+layer at (39,31) size 100x100
+  RenderBlock {DIV} at (10,0) size 100x100 [bgcolor=#008000]
+    RenderText {#text} at (33,0) size 34x77
+      text run at (33,0) width 34: "1"
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.checksum
new file mode 100644
index 0000000..5be42f8
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.checksum
@@ -0,0 +1 @@
+f4cbdf8ddfceb02d9676acc0b099f5c3
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.png b/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.png
new file mode 100644
index 0000000..b3da2a2
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.txt b/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.txt
new file mode 100644
index 0000000..9460a00
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/reflection-opacity-expected.txt
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: line 26: TypeError: Result of expression 'document.getElementById('inner')' [null] is not an object.
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x176
+  RenderBlock {HTML} at (0,0) size 800x176
+    RenderBody {BODY} at (8,16) size 784x152
+      RenderBlock {P} at (0,0) size 784x36
+        RenderText {#text} at (0,0) size 777x36
+          text run at (0,0) width 777: "Opacity should be applied after reflection, so you should see a green rectangle below. The overlap between the original and"
+          text run at (0,18) width 197: "reflection should not be visible."
+layer at (8,68) size 150x100
+  RenderBlock (relative positioned) {DIV} at (0,52) size 150x100 [bgcolor=#008000]
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.checksum
new file mode 100644
index 0000000..fb08bb8
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.checksum
@@ -0,0 +1 @@
+bed35423b662d03dcbca0a54ea6d0068
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.png b/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.png
new file mode 100644
index 0000000..4362c40
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.txt b/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.txt
new file mode 100644
index 0000000..22f6ced
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/reflection-ordering-expected.txt
@@ -0,0 +1,12 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x194
+  RenderBlock {HTML} at (0,0) size 800x194
+    RenderBody {BODY} at (8,16) size 784x158
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 769x18
+          text run at (0,0) width 769: "You should see a black rectangle divided into two parts; the top part should be taller (reflection should be behind original)."
+layer at (28,54) size 220x120
+  RenderBlock {DIV} at (20,38) size 220x120 [bgcolor=#FFFFFF] [border: (10px solid #000000)]
+    RenderText {#text} at (67,10) size 86x28
+      text run at (67,10) width 86: "Contents"
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.checksum
new file mode 100644
index 0000000..fc6d50e
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.checksum
@@ -0,0 +1 @@
+d91382247bac1f2beb87462ae8ee1b1c
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.png b/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.png
new file mode 100644
index 0000000..c865535
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.txt b/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.txt
new file mode 100644
index 0000000..24a810e
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/reflection-positioning-expected.txt
@@ -0,0 +1,16 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x50
+  RenderBlock {HTML} at (0,0) size 800x50
+    RenderBody {BODY} at (8,16) size 784x18
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 509x18
+          text run at (0,0) width 509: "Position of reflected layer should update correctly. You should see no red below."
+layer at (20,50) size 150x120
+  RenderBlock (positioned) {DIV} at (20,50) size 150x120
+layer at (46,185) size 100x100
+  RenderBlock (positioned) {DIV} at (26,135) size 100x100 [bgcolor=#FF0000]
+layer at (20,50) size 150x120
+  RenderBlock (relative positioned) {DIV} at (0,0) size 150x120 [border: (1px solid #000000)]
+layer at (46,61) size 100x100
+  RenderBlock (positioned) {DIV} at (26,11) size 100x100 [bgcolor=#008000]
diff --git a/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.checksum b/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.checksum
new file mode 100644
index 0000000..3417b43
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.checksum
@@ -0,0 +1 @@
+bdecf46beb596b45dbe5137c2405510c
\ No newline at end of file
diff --git a/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.png b/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.png
new file mode 100644
index 0000000..b65a366
Binary files /dev/null and b/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.png differ
diff --git a/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.txt b/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.txt
new file mode 100644
index 0000000..6d8850b
--- /dev/null
+++ b/LayoutTests/platform/mac/compositing/reflections/transform-inside-reflection-expected.txt
@@ -0,0 +1,15 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x324
+  RenderBlock {HTML} at (0,0) size 800x324
+    RenderBody {BODY} at (8,16) size 784x288
+      RenderBlock {P} at (0,0) size 784x36
+        RenderText {#text} at (0,0) size 769x36
+          text run at (0,0) width 769: "Transform inside nested reflections should be applied correctly. You should see four rotated green boxes, as mirror images"
+          text run at (0,18) width 86: "of each other."
+layer at (28,72) size 122x232
+  RenderBlock {DIV} at (20,56) size 122x232 [border: (1px solid #000000)]
+layer at (39,83) size 102x102
+  RenderBlock {DIV} at (11,11) size 102x102 [border: (1px solid #000000)]
+layer at (50,94) size 80x80
+  RenderBlock {DIV} at (11,11) size 80x80 [bgcolor=#008000]
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 59de5b0..028b869 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,177 @@
+2010-01-15  Simon Fraser  <simon.fraser at apple.com>
+
+        Reviewed by Dan Bernstein and Adele Peterson.
+
+        Support reflections on composited layers
+        https://bugs.webkit.org/show_bug.cgi?id=31885
+        
+        Implement reflections (via -webkit-box-reflect:) on compositing layers.
+        
+        We add to the GraphicsLayer the notion of having a replica, and being a replicated layer.
+        The replica layer is not parented in the tree, but referenced by another layer.
+        RenderLayerBacking sets this up when it finds RenderLayers for reflections.
+        
+        GraphicsLayerCA implements rendering of replica layers by cloning CA layers,
+        and copying their properties, including animations and contents. Deep reflections
+        are supported by a hash of clone layers on each GraphicsLayerCA, indexed by
+        the path down the tree to each replica instance.
+        
+        When GraphicsLayerCA properties are changed, in most cases the clones must also
+        be updated.
+
+        Tests: compositing/masks/direct-image-mask.html
+               compositing/reflections/animation-inside-reflection.html
+               compositing/reflections/compositing-change-inside-reflection.html
+               compositing/reflections/deeply-nested-reflections.html
+               compositing/reflections/masked-reflection-on-composited.html
+               compositing/reflections/nested-reflection-anchor-point.html
+               compositing/reflections/nested-reflection-animated.html
+               compositing/reflections/nested-reflection-mask-change.html
+               compositing/reflections/nested-reflection-on-overflow.html
+               compositing/reflections/nested-reflection-opacity.html
+               compositing/reflections/nested-reflection-size-change.html
+               compositing/reflections/nested-reflection-transformed.html
+               compositing/reflections/nested-reflection-transition.html
+               compositing/reflections/nested-reflection.html
+               compositing/reflections/reflection-opacity.html
+               compositing/reflections/reflection-ordering.html
+               compositing/reflections/reflection-positioning.html
+               compositing/reflections/transform-inside-reflection.html
+
+        * platform/graphics/GraphicsLayer.h:
+        (WebCore::GraphicsLayer::isReplicated): Returns true when this layer has a replicated layer.
+        (WebCore::GraphicsLayer::replicatedLayerPosition):
+        (WebCore::GraphicsLayer::setReplicatedLayerPosition): The position of the replica layer must be 
+        special-cased; we cannot just copy the position of the original.
+        (WebCore::GraphicsLayer::didDisplay): Method that indicates that the contents of the layer changed,
+        which gives us a chance to update clone layers.
+        (WebCore::GraphicsLayer::replicaLayer): reference to the replica layer.
+        (WebCore::GraphicsLayer::replicatedLayer): reference to the layer that this (replica) layer is replicating.
+        (WebCore::GraphicsLayer::setReplicatedLayer):
+
+        * platform/graphics/GraphicsLayer.cpp:
+        (WebCore::GraphicsLayer::GraphicsLayer):
+        (WebCore::GraphicsLayer::setReplicatedByLayer): Hook up a replica with its replicated layer.
+        (WebCore::GraphicsLayer::dumpProperties):
+
+        * platform/graphics/mac/GraphicsLayerCA.h:
+        (WebCore::GraphicsLayerCA::primaryLayer): Returns a CALayer, since structural layers may not be WebLayers.
+        (WebCore::GraphicsLayerCA::isReplicatedRootClone): Given a cloneID (string representation of the path to a clone
+        down the tree, which is a bitstring of 1 (replica), or 0 (non-replica)), returns true if this ID represents the
+        root of a replica tree.
+        (WebCore::GraphicsLayerCA::primaryLayerClones): Returns a pointer to the hash map of clones of the primary layers.
+
+        (WebCore::GraphicsLayerCA::ReplicaState::ReplicaState): Small struct used to track original/clone branching
+        down the tree during recursion, to build cloneID paths.
+
+        (WebCore::GraphicsLayerCA::hasCloneLayers): returns true if this layer has clone layers.
+
+        * platform/graphics/mac/GraphicsLayerCA.mm:
+        (WebCore::GraphicsLayerCA::~GraphicsLayerCA): remove the clone layers.
+        (WebCore::GraphicsLayerCA::setChildren): call noteSublayersChanged() since we may have to update replicas too.
+        (WebCore::GraphicsLayerCA::addChild): ditto
+        (WebCore::GraphicsLayerCA::addChildAtIndex): ditto
+        (WebCore::GraphicsLayerCA::addChildBelow): ditto
+        (WebCore::GraphicsLayerCA::addChildAbove): ditto
+        (WebCore::GraphicsLayerCA::replaceChild): ditto
+        (WebCore::GraphicsLayerCA::removeFromParent): ditto
+        (WebCore::GraphicsLayerCA::setMaskLayer): call propagateLayerChangeToReplicas()
+        (WebCore::GraphicsLayerCA::setReplicatedLayer): note replica changed.
+        (WebCore::GraphicsLayerCA::setReplicatedByLayer): ditto
+        (WebCore::GraphicsLayerCA::moveOrCopyAllAnimationsForProperty): Enhanced to allow moving or copying animations.
+        (WebCore::GraphicsLayerCA::moveOrCopyAnimationsForProperty): Ditto.
+        (WebCore::GraphicsLayerCA::setContentsToImage): call noteSublayersChanged()
+        (WebCore::GraphicsLayerCA::setContentsToVideo): call noteSublayersChanged()
+        (WebCore::GraphicsLayerCA::didDisplay): here is our chance to copy updated contents to clone layers.
+        (WebCore::GraphicsLayerCA::recursiveCommitChanges):
+        (WebCore::GraphicsLayerCA::commitLayerChangesBeforeSublayers): pre-order commit, for things that need to be
+            committed before we recurse on children.
+        (WebCore::GraphicsLayerCA::commitLayerChangesAfterSublayers): post-order commit, for things that need to be
+            committed after we recurse on children, like clones.
+        (WebCore::GraphicsLayerCA::updateLayerNames): New method to match the other 'update' methods.
+        (WebCore::GraphicsLayerCA::updateSublayerList): Insert replica layers into the hierarchy.
+        (WebCore::GraphicsLayerCA::updateLayerPosition): update clones.
+        (WebCore::GraphicsLayerCA::updateLayerSize): ditto
+        (WebCore::GraphicsLayerCA::updateAnchorPoint): ditto
+        (WebCore::GraphicsLayerCA::updateTransform): ditto
+        (WebCore::GraphicsLayerCA::updateChildrenTransform): ditto
+        (WebCore::GraphicsLayerCA::updateMasksToBounds): ditto
+        (WebCore::GraphicsLayerCA::updateContentsOpaque): ditto
+        (WebCore::GraphicsLayerCA::updateBackfaceVisibility): ditto
+        (WebCore::GraphicsLayerCA::updateStructuralLayer): call ensureStructuralLayer()
+        (WebCore::moveAnimation): utility to move a CAAnimation from one layer to another.
+        (WebCore::GraphicsLayerCA::ensureStructuralLayer): refactored code which creates enclosing CALayers for reflection
+        flattening, or CATransformLayers for preserve-3d.
+        (WebCore::GraphicsLayerCA::structuralLayerPurpose): indicates why we need a structural layer.
+        (WebCore::GraphicsLayerCA::updateLayerDrawsContent): update clones
+        (WebCore::GraphicsLayerCA::updateContentsImage): ditto
+        (WebCore::GraphicsLayerCA::updateContentsRect): ditto
+        (WebCore::GraphicsLayerCA::updateMaskLayer): ditto
+        (WebCore::GraphicsLayerCA::updateReplicatedLayers): This is where we ask for the tree of layers for the replica
+        and its children, and attach them as sublayers.
+        (WebCore::GraphicsLayerCA::ReplicaState::cloneID): Build a bitstring from the array of original/clone values; this
+        string serves to identify clones in the hash map.
+        (WebCore::GraphicsLayerCA::replicatedLayerRoot): Request the tree of clone layers, set its position and transform,
+        and return it.
+        (WebCore::GraphicsLayerCA::setAnimationOnLayer): update clones
+        (WebCore::GraphicsLayerCA::removeAnimationFromLayer): ditto
+        (WebCore::GraphicsLayerCA::pauseAnimationOnLayer): ditto
+        (WebCore::GraphicsLayerCA::setContentsToGraphicsContext3D): udpate sublayers.
+        (WebCore::GraphicsLayerCA::suspendAnimations): update clones.
+        (WebCore::GraphicsLayerCA::resumeAnimations): ditto
+        (WebCore::GraphicsLayerCA::animatedLayerClones): return the hash map for clones of the appropriate layer for the given property.
+        (WebCore::GraphicsLayerCA::ensureCloneLayers): create and return clones for the CALayers for this layer.
+        (WebCore::GraphicsLayerCA::removeCloneLayers): clear out the clone layers.
+        (WebCore::GraphicsLayerCA::positionForCloneRootLayer): the root of a clonal subtree needs its position and transform to be special-cased,
+        since it doesn't just copy those properties from the original.
+        (WebCore::GraphicsLayerCA::propagateLayerChangeToReplicas): push the change flags onto the replica.
+        (WebCore::GraphicsLayerCA::fetchCloneLayers): recurse down sublayers, creating clones of the CALayers along the way, and returning
+        the root of the clone tree.
+        (WebCore::copyAnimation): utility to copy an animation from one layer to another. Animations can be shared between layers.
+        (WebCore::GraphicsLayerCA::cloneLayer): utility to clone a CALayer, copying those properties which GraphicsLayerCA makes use of
+        (WebCore::GraphicsLayerCA::setOpacityInternal): push opacity changes to clones.
+        (WebCore::GraphicsLayerCA::updateOpacityOnLayer): ditto
+        (WebCore::GraphicsLayerCA::noteSublayersChanged): set the ChildrenChanged flag, and proprate changes to the replica, if any.
+
+        * platform/graphics/mac/WebLayer.mm:
+        (-[WebLayer display]): override -display so we know when to update the contents of clone layers
+
+        * platform/graphics/mac/WebTiledLayer.mm:
+        (-[WebTiledLayer display]): ditto.
+
+        * rendering/RenderLayer.h:
+        (WebCore::RenderLayer::isReflection): New method that returns true if the renderer is a replica.
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::RenderLayer): initialize m_isReflection
+        (WebCore::RenderLayer::updateReflectionStyle): call setIsReflection
+
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::createGraphicsLayer): Put a name on the reflection layer.
+        (WebCore::RenderLayerBacking::updateGraphicsLayerConfiguration): Hook up the GraphicsLayers for the reflection.
+        (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry): Reflection overrides preserve-3d (you have to flatten to reflect).
+        Also hook up updating the reflection layer geometry, and the relica position.
+        
+        (WebCore::RenderLayerBacking::paintIntoLayer): We no longer paint the reflection in software.
+
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::computeCompositingRequirements): Hook reflection layers into the compositing logic.
+        (WebCore::RenderLayerCompositor::canAccelerateVideoRendering): No longer have to push video into software if it's reflected.
+        (WebCore::RenderLayerCompositor::rebuildCompositingLayerTree): Update the bounds of the reflection layer.
+        (WebCore::RenderLayerCompositor::updateCompositingDescendantGeometry): ditto
+        (WebCore::RenderLayerCompositor::requiresCompositingWhenDescendantsAreCompositing): a compositing descendant forces
+        a reflection ancestor to composite now.
+        (WebCore::RenderLayerBacking::containsPaintedContent): Reflection layers don't paint anything.
+        (WebCore::RenderLayerBacking::isDirectlyCompositedImage): No need to fall out of direct compositing mode
+        for masks or reflections any more.
+        (WebCore::RenderLayerBacking::paintIntoLayer): No need to paint the reflection manually now.
+
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::isReplica):
+        * rendering/RenderReplica.h:
+        (WebCore::RenderReplica::isReplica):
+        New method used to determine if a render is a replica.
+
 2010-01-15  Carol Szabo  <carol.szabo at nokia.com>
 
         Reviewed by Darin Adler.
diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp
index e215097..2336d0b 100644
--- a/WebCore/platform/graphics/GraphicsLayer.cpp
+++ b/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -72,6 +72,8 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
     , m_contentsOrientation(CompositingCoordinatesTopDown)
     , m_parent(0)
     , m_maskLayer(0)
+    , m_replicaLayer(0)
+    , m_replicatedLayer(0)
     , m_repaintCount(0)
 {
 }
@@ -214,6 +216,14 @@ void GraphicsLayer::removeFromParent()
     }
 }
 
+void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
+{
+    if (layer)
+        layer->setReplicatedLayer(this);
+
+    m_replicaLayer = layer;
+}
+
 void GraphicsLayer::setBackgroundColor(const Color& color)
 {
     m_backgroundColor = color;
@@ -454,14 +464,27 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const
     }
     ts << ")\n";
 
-    writeIndent(ts, indent + 1);
-    ts << "(children " << m_children.size() << "\n";
+    if (m_replicaLayer) {
+        writeIndent(ts, indent + 1);
+        ts << "(replica layer " << m_replicaLayer << ")\n";
+        m_replicaLayer->dumpLayer(ts, indent+2);
+    }
+
+    if (m_replicatedLayer) {
+        writeIndent(ts, indent + 1);
+        ts << "(replicated layer " << m_replicatedLayer << ")\n";
+    }
     
-    unsigned i;
-    for (i = 0; i < m_children.size(); i++)
-        m_children[i]->dumpLayer(ts, indent+2);
-    writeIndent(ts, indent + 1);
-    ts << ")\n";
+    if (m_children.size()) {
+        writeIndent(ts, indent + 1);
+        ts << "(children " << m_children.size() << "\n";
+        
+        unsigned i;
+        for (i = 0; i < m_children.size(); i++)
+            m_children[i]->dumpLayer(ts, indent+2);
+        writeIndent(ts, indent + 1);
+        ts << ")\n";
+    }
 }
 
 } // namespace WebCore
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
index c0b0245..ee01911 100644
--- a/WebCore/platform/graphics/GraphicsLayer.h
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -198,6 +198,14 @@ public:
     GraphicsLayer* maskLayer() const { return m_maskLayer; }
     virtual void setMaskLayer(GraphicsLayer* layer) { m_maskLayer = layer; }
     
+    // The given layer will replicate this layer and its children; the replica renders behind this layer.
+    virtual void setReplicatedByLayer(GraphicsLayer*);
+    // Whether this layer is being replicated by another layer.
+    bool isReplicated() const { return m_replicaLayer; }
+
+    const FloatPoint& replicatedLayerPosition() const { return m_replicatedLayerPosition; }
+    void setReplicatedLayerPosition(const FloatPoint& p) { m_replicatedLayerPosition = p; }
+
     // Offset is origin of the renderer minus origin of the graphics layer (so either zero or negative).
     IntSize offsetFromRenderer() const { return m_offsetFromRenderer; }
     void setOffsetFromRenderer(const IntSize& offset) { m_offsetFromRenderer = offset; }
@@ -279,6 +287,8 @@ public:
 #endif
     // Callback from the underlying graphics system to draw layer contents.
     void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip);
+    // Callback from the underlying graphics system when the layer has been displayed
+    virtual void didDisplay() { }
     
     virtual PlatformLayer* platformLayer() const { return 0; }
     
@@ -327,6 +337,12 @@ protected:
 
     virtual void setOpacityInternal(float) { }
     
+    // The layer that replicates this layer (if any).
+    GraphicsLayer* replicaLayer() const { return m_replicaLayer; }
+    // The layer being replicated.
+    GraphicsLayer* replicatedLayer() const { return m_replicatedLayer; }
+    virtual void setReplicatedLayer(GraphicsLayer* layer) { m_replicatedLayer = layer; }
+
     GraphicsLayer(GraphicsLayerClient*);
 
     void dumpProperties(TextStream&, int indent) const;
@@ -365,6 +381,11 @@ protected:
 
     GraphicsLayer* m_maskLayer; // Reference to mask layer. We don't own this.
 
+    GraphicsLayer* m_replicaLayer; // A layer that replicates this layer. We only allow one, for now.
+                                   // The replica is not parented; this is the primary reference to it.
+    GraphicsLayer* m_replicatedLayer; // For a replica layer, a reference to the original layer.
+    FloatPoint m_replicatedLayerPosition; // For a replica layer, the position of the replica.
+
     IntRect m_contentsRect;
 
     int m_repaintCount;
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
index 9c31223..3ca92e3 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
@@ -64,6 +64,7 @@ public:
     virtual void removeFromParent();
 
     virtual void setMaskLayer(GraphicsLayer*);
+    virtual void setReplicatedLayer(GraphicsLayer*);
 
     virtual void setPosition(const FloatPoint&);
     virtual void setAnchorPoint(const FloatPoint3D&);
@@ -116,8 +117,9 @@ public:
 
     virtual void setGeometryOrientation(CompositingCoordinatesOrientation);
 
+    virtual void didDisplay();
+
     void recursiveCommitChanges();
-    void commitLayerChanges();
 
     virtual void syncCompositingState();
 
@@ -132,6 +134,13 @@ private:
     CALayer* layerForSuperlayer() const;
     CALayer* animatedLayer(AnimatedPropertyID property) const;
 
+    typedef String CloneID; // Identifier for a given clone, based on original/replica branching down the tree.
+    static bool isReplicatedRootClone(const CloneID& cloneID) { return cloneID[0U] & 1; }
+
+    typedef HashMap<CloneID, RetainPtr<CALayer> > LayerMap;
+    LayerMap* primaryLayerClones() const { return m_structuralLayer.get() ? m_structuralLayerClones.get() : m_layerClones.get(); }
+    LayerMap* animatedLayerClones(AnimatedPropertyID property) const;
+
     bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset);
     bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset, const IntSize& boxSize);
 
@@ -153,6 +162,9 @@ private:
         return m_runningKeyframeAnimations.find(keyframesName) != m_runningKeyframeAnimations.end();
     }
 
+    void commitLayerChangesBeforeSublayers();
+    void commitLayerChangesAfterSublayers();
+
     bool requiresTiledLayer(const FloatSize&) const;
     void swapFromOrToTiledLayer(bool useTiledLayer);
 
@@ -161,6 +173,69 @@ private:
     
     void setupContentsLayer(CALayer*);
     CALayer* contentsLayer() const { return m_contentsLayer.get(); }
+
+    virtual void setReplicatedByLayer(GraphicsLayer*);
+
+    // Used to track the path down the tree for replica layers.
+    struct ReplicaState {
+        static const size_t maxReplicaDepth = 16;
+        enum ReplicaBranchType { ChildBranch = 0, ReplicaBranch = 1 };
+        ReplicaState(ReplicaBranchType firstBranch)
+            : m_replicaDepth(0)
+        {
+            push(firstBranch);
+        }
+        
+        // Called as we walk down the tree to build replicas.
+        void push(ReplicaBranchType branchType)
+        {
+            m_replicaBranches.append(branchType);
+            if (branchType == ReplicaBranch)
+                ++m_replicaDepth;
+        }
+        
+        void setBranchType(ReplicaBranchType branchType)
+        {
+            ASSERT(!m_replicaBranches.isEmpty());
+
+            if (m_replicaBranches.last() != branchType) {
+                if (branchType == ReplicaBranch)
+                    ++m_replicaDepth;
+                else
+                    --m_replicaDepth;
+            }
+
+            m_replicaBranches.last() = branchType;
+        }
+
+        void pop()
+        {
+            if (m_replicaBranches.last() == ReplicaBranch)
+                --m_replicaDepth;
+            m_replicaBranches.removeLast();
+        }
+        
+        size_t depth() const { return m_replicaBranches.size(); }
+        size_t replicaDepth() const { return m_replicaDepth; }
+
+        CloneID cloneID() const;        
+
+    private:
+        Vector<ReplicaBranchType> m_replicaBranches;
+        size_t m_replicaDepth;
+    };
+    CALayer *replicatedLayerRoot(ReplicaState&);
+
+    enum CloneLevel { RootCloneLevel, IntermediateCloneLevel };
+    CALayer *fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState&, CloneLevel);
+    void ensureCloneLayers(CloneID index, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel);
+    CALayer *cloneLayer(CALayer *, CloneLevel);
+
+    bool hasCloneLayers() const { return m_layerClones; }
+    void removeCloneLayers();
+    FloatPoint positionForCloneRootLayer() const;
+    
+    void propagateLayerChangeToReplicas();
     
     // All these "update" methods will be called inside a BEGIN_BLOCK_OBJC_EXCEPTIONS/END_BLOCK_OBJC_EXCEPTIONS block.
     void updateLayerNames();
@@ -185,6 +260,7 @@ private:
     void updateContentsRect();
     void updateGeometryOrientation();
     void updateMaskLayer();
+    void updateReplicatedLayers();
 
     void updateLayerAnimations();
     
@@ -200,7 +276,9 @@ private:
     bool removeAnimationFromLayer(AnimatedPropertyID, const String& keyframesName, int index);
     void pauseAnimationOnLayer(AnimatedPropertyID, const String& keyframesName, int index, double timeOffset);
 
-    void moveAnimationsForProperty(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer);
+    enum MoveOrCopy { Move, Copy };
+    void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID property, CALayer * fromLayer, CALayer * toLayer);
+    static void moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer * fromLayer, CALayer * toLayer);
     
     enum LayerChange {
         NoChange = 0,
@@ -227,10 +305,12 @@ private:
 #endif
         ContentsRectChanged = 1 << 20,
         GeometryOrientationChanged = 1 << 21,
-        MaskLayerChanged = 1 << 22
+        MaskLayerChanged = 1 << 22,
+        ReplicatedLayerChanged = 1 << 23
     };
     typedef unsigned LayerChangeFlags;
     void noteLayerPropertyChanged(LayerChangeFlags flags);
+    void noteSublayersChanged();
 
     void repaintLayerDirtyRects();
 
@@ -238,6 +318,11 @@ private:
     RetainPtr<CALayer> m_structuralLayer;   // A layer used for structual reasons, like preserves-3d or replica-flattening. Is the parent of m_layer.
     RetainPtr<CALayer> m_contentsLayer;     // A layer used for inner content, like image and video
 
+    // References to clones of our layers, for replicated layers.
+    OwnPtr<LayerMap> m_layerClones;
+    OwnPtr<LayerMap> m_structuralLayerClones;
+    OwnPtr<LayerMap> m_contentsLayerClones;
+    
     enum ContentsLayerPurpose {
         NoContentsLayer = 0,
         ContentsLayerForImage,
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
index 4af56b6..958722a 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -87,6 +87,10 @@ static double mediaTimeToCurrentTime(CFTimeInterval t)
 
 } // namespace WebCore
 
+ at interface CALayer(Private)
+- (void)setContentsChanged;
+ at end
+
 @interface WebAnimationDelegate : NSObject {
     WebCore::GraphicsLayerCA* m_graphicsLayer;
 }
@@ -404,6 +408,9 @@ GraphicsLayerCA::~GraphicsLayerCA()
     // animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
     [m_animationDelegate.get() setLayer:0];
 
+    // Release the clone layers inside the exception-handling block.
+    removeCloneLayers();
+    
     END_BLOCK_OBJC_EXCEPTIONS
 }
 
@@ -423,7 +430,7 @@ bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
 {
     bool childrenChanged = GraphicsLayer::setChildren(children);
     if (childrenChanged)
-        noteLayerPropertyChanged(ChildrenChanged);
+        noteSublayersChanged();
     
     return childrenChanged;
 }
@@ -431,31 +438,31 @@ bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
 void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
 {
     GraphicsLayer::addChild(childLayer);
-    noteLayerPropertyChanged(ChildrenChanged);
+    noteSublayersChanged();
 }
 
 void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
 {
     GraphicsLayer::addChildAtIndex(childLayer, index);
-    noteLayerPropertyChanged(ChildrenChanged);
+    noteSublayersChanged();
 }
 
 void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
 {
     GraphicsLayer::addChildBelow(childLayer, sibling);
-    noteLayerPropertyChanged(ChildrenChanged);
+    noteSublayersChanged();
 }
 
 void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
 {
     GraphicsLayer::addChildAbove(childLayer, sibling);
-    noteLayerPropertyChanged(ChildrenChanged);
+    noteSublayersChanged();
 }
 
 bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
 {
     if (GraphicsLayer::replaceChild(oldChild, newChild)) {
-        noteLayerPropertyChanged(ChildrenChanged);
+        noteSublayersChanged();
         return true;
     }
     return false;
@@ -464,7 +471,7 @@ bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newCh
 void GraphicsLayerCA::removeFromParent()
 {
     if (m_parent)
-        static_cast<GraphicsLayerCA*>(m_parent)->noteLayerPropertyChanged(ChildrenChanged);
+        static_cast<GraphicsLayerCA*>(m_parent)->noteSublayersChanged();
     GraphicsLayer::removeFromParent();
 }
 
@@ -475,6 +482,30 @@ void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer)
 
     GraphicsLayer::setMaskLayer(layer);
     noteLayerPropertyChanged(MaskLayerChanged);
+
+    propagateLayerChangeToReplicas();
+    
+    if (m_replicatedLayer)
+        static_cast<GraphicsLayerCA*>(m_replicatedLayer)->propagateLayerChangeToReplicas();
+}
+
+void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer)
+{
+    if (layer == m_replicatedLayer)
+        return;
+
+    GraphicsLayer::setReplicatedLayer(layer);
+    noteLayerPropertyChanged(ReplicatedLayerChanged);
+}
+
+void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer)
+{
+    if (layer == m_replicaLayer)
+        return;
+
+    GraphicsLayer::setReplicatedByLayer(layer);
+    noteSublayersChanged();
+    noteLayerPropertyChanged(ReplicatedLayerChanged);
 }
 
 void GraphicsLayerCA::setPosition(const FloatPoint& point)
@@ -522,7 +553,7 @@ void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
     noteLayerPropertyChanged(ChildrenTransformChanged);
 }
 
-static void moveAllAnimationsForProperty(AnimatedPropertyID property, const String& keyframesName, CALayer* fromLayer, CALayer* toLayer)
+void GraphicsLayerCA::moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer *fromLayer, CALayer *toLayer)
 {
     for (int index = 0; ; ++index) {
         String animName = animationIdentifier(property, keyframesName, index);
@@ -531,22 +562,30 @@ static void moveAllAnimationsForProperty(AnimatedPropertyID property, const Stri
         if (!anim)
             break;
 
-        [anim retain];
-        [fromLayer removeAnimationForKey:animName];
-        [toLayer addAnimation:anim forKey:animName];
-        [anim release];
+        switch (operation) {
+            case Move:
+                [anim retain];
+                [fromLayer removeAnimationForKey:animName];
+                [toLayer addAnimation:anim forKey:animName];
+                [anim release];
+                break;
+
+            case Copy:
+                [toLayer addAnimation:anim forKey:animName];
+                break;
+        }
     }
 }
 
-void GraphicsLayerCA::moveAnimationsForProperty(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
+void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, CALayer *fromLayer, CALayer *toLayer)
 {
     // Move transitions for this property.
-    moveAllAnimationsForProperty(property, "", fromLayer, toLayer);
+    moveOrCopyAllAnimationsForProperty(operation, property, "", fromLayer, toLayer);
     
     // Look for running animations affecting this property.
     KeyframeAnimationsMap::const_iterator end = m_runningKeyframeAnimations.end();
     for (KeyframeAnimationsMap::const_iterator it = m_runningKeyframeAnimations.begin(); it != end; ++it)
-        moveAllAnimationsForProperty(property, it->first, fromLayer, toLayer);
+        moveOrCopyAllAnimationsForProperty(operation, property, it->first, fromLayer, toLayer);
 }
 
 void GraphicsLayerCA::setPreserves3D(bool preserves3D)
@@ -737,12 +776,12 @@ void GraphicsLayerCA::setContentsToImage(Image* image)
         }
         m_contentsLayerPurpose = ContentsLayerForImage;
         if (!m_contentsLayer)
-            noteLayerPropertyChanged(ChildrenChanged);
+            noteSublayersChanged();
     } else {
         m_pendingContentsImage = 0;
         m_contentsLayerPurpose = NoContentsLayer;
         if (m_contentsLayer)
-            noteLayerPropertyChanged(ChildrenChanged);
+            noteSublayersChanged();
     }
 
     noteLayerPropertyChanged(ContentsImageChanged);
@@ -751,7 +790,7 @@ void GraphicsLayerCA::setContentsToImage(Image* image)
 void GraphicsLayerCA::setContentsToMedia(PlatformLayer* mediaLayer)
 {
     if (mediaLayer != m_contentsLayer.get())
-        noteLayerPropertyChanged(ChildrenChanged);
+        noteSublayersChanged();
 
     m_contentsLayer = mediaLayer;
     noteLayerPropertyChanged(ContentsMediaLayerChanged);
@@ -781,6 +820,23 @@ void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation o
 #endif
 }
 
+void GraphicsLayerCA::didDisplay()
+{
+    if (LayerMap* layerCloneMap = m_layerClones.get()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currClone = it->second.get();
+            if (!currClone)
+                continue;
+
+            if ([currClone contents] != [m_layer.get() contents])
+                [currClone setContents:[m_layer.get() contents]];
+            else
+                [currClone setContentsChanged];
+        }
+    }
+}
+
 void GraphicsLayerCA::syncCompositingState()
 {
     recursiveCommitChanges();
@@ -788,10 +844,10 @@ void GraphicsLayerCA::syncCompositingState()
 
 void GraphicsLayerCA::recursiveCommitChanges()
 {
-    commitLayerChanges();
+    commitLayerChangesBeforeSublayers();
 
     if (m_maskLayer)
-        static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChanges();
+        static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesBeforeSublayers();
 
     const Vector<GraphicsLayer*>& childLayers = children();
     size_t numChildren = childLayers.size();
@@ -799,9 +855,17 @@ void GraphicsLayerCA::recursiveCommitChanges()
         GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
         curChild->recursiveCommitChanges();
     }
+
+    if (m_replicaLayer)
+        static_cast<GraphicsLayerCA*>(m_replicaLayer)->recursiveCommitChanges();
+
+    if (m_maskLayer)
+        static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesAfterSublayers();
+
+    commitLayerChangesAfterSublayers();
 }
 
-void GraphicsLayerCA::commitLayerChanges()
+void GraphicsLayerCA::commitLayerChangesBeforeSublayers()
 {
     if (!m_uncommittedChanges)
         return;
@@ -809,7 +873,7 @@ void GraphicsLayerCA::commitLayerChanges()
     BEGIN_BLOCK_OBJC_EXCEPTIONS
 
     // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to
-    if (m_uncommittedChanges & Preserves3DChanged)
+    if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged))
         updateStructuralLayer();
 
     if (m_uncommittedChanges & NameChanged)
@@ -877,6 +941,19 @@ void GraphicsLayerCA::commitLayerChanges()
     if (m_uncommittedChanges & MaskLayerChanged)
         updateMaskLayer();
 
+    END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::commitLayerChangesAfterSublayers()
+{
+    if (!m_uncommittedChanges)
+        return;
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+    if (m_uncommittedChanges & ReplicatedLayerChanged)
+        updateReplicatedLayers();
+
     m_uncommittedChanges = NoChange;
     END_BLOCK_OBJC_EXCEPTIONS
 }
@@ -906,6 +983,9 @@ void GraphicsLayerCA::updateSublayerList()
         newSublayers = [[NSMutableArray alloc] init];
 
         if (m_structuralLayer) {
+            // Add the replica layer first.
+            if (m_replicaLayer)
+                [newSublayers addObject:static_cast<GraphicsLayerCA*>(m_replicaLayer)->primaryLayer()];
             // Add the primary layer. Even if we have negative z-order children, the primary layer always comes behind.
             [newSublayers addObject:m_layer.get()];
         } else if (m_contentsLayer) {
@@ -918,7 +998,7 @@ void GraphicsLayerCA::updateSublayerList()
         size_t numChildren = childLayers.size();
         for (size_t i = 0; i < numChildren; ++i) {
             GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
-            CALayer* childLayer = curChild->layerForSuperlayer();
+            CALayer *childLayer = curChild->layerForSuperlayer();
             [newSublayers addObject:childLayer];
         }
 
@@ -947,6 +1027,20 @@ void GraphicsLayerCA::updateLayerPosition()
                                    m_position.y() + m_anchorPoint.y() * m_size.height());
     
     [primaryLayer() setPosition:posPoint];
+
+    if (LayerMap* layerCloneMap = primaryLayerClones()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CGPoint clonePosition = posPoint;
+            if (m_replicaLayer && isReplicatedRootClone(it->first)) {
+                // Maintain the special-case position for the root of a clone subtree,
+                // which we set up in replicatedLayerRoot().
+                clonePosition = positionForCloneRootLayer();
+            }
+            CALayer *currLayer = it->second.get();
+            [currLayer setPosition:clonePosition];
+        }
+    }
 }
 
 void GraphicsLayerCA::updateLayerSize()
@@ -954,10 +1048,22 @@ void GraphicsLayerCA::updateLayerSize()
     CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height());
     if (m_structuralLayer) {
         [m_structuralLayer.get() setBounds:rect];
+        
+        if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
+            LayerMap::const_iterator end = layerCloneMap->end();
+            for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+                [it->second.get() setBounds:rect];
+        }
 
         // 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);
         [m_layer.get() setPosition:centerPoint];
+
+        if (LayerMap* layerCloneMap = m_layerClones.get()) {
+            LayerMap::const_iterator end = layerCloneMap->end();
+            for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+                [it->second.get() setPosition:centerPoint];
+        }
     }
     
     bool needTiledLayer = requiresTiledLayer(m_size);
@@ -965,6 +1071,11 @@ void GraphicsLayerCA::updateLayerSize()
         swapFromOrToTiledLayer(needTiledLayer);
     
     [m_layer.get() setBounds:rect];
+    if (LayerMap* layerCloneMap = m_layerClones.get()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+            [it->second.get() setBounds:rect];
+    }
     
     // Contents transform may depend on height.
     updateContentsTransform();
@@ -982,6 +1093,18 @@ void GraphicsLayerCA::updateAnchorPoint()
 #if HAVE_MODERN_QUARTZCORE
     [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
 #endif
+
+    if (LayerMap* layerCloneMap = primaryLayerClones()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {   
+            CALayer *currLayer = it->second.get();
+            [currLayer setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())];
+#if HAVE_MODERN_QUARTZCORE
+            [currLayer setAnchorPointZ:m_anchorPoint.z()];
+#endif
+        }
+    }
+
     updateLayerPosition();
 }
 
@@ -990,6 +1113,19 @@ void GraphicsLayerCA::updateTransform()
     CATransform3D transform;
     copyTransform(transform, m_transform);
     [primaryLayer() setTransform:transform];
+
+    if (LayerMap* layerCloneMap = primaryLayerClones()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            if (m_replicaLayer && isReplicatedRootClone(it->first)) {
+                // Maintain the special-case transform for the root of a clone subtree,
+                // which we set up in replicatedLayerRoot().
+                [currLayer setTransform:CATransform3DIdentity];
+            } else
+                [currLayer setTransform:transform];
+        }
+    }
 }
 
 void GraphicsLayerCA::updateChildrenTransform()
@@ -997,22 +1133,55 @@ void GraphicsLayerCA::updateChildrenTransform()
     CATransform3D transform;
     copyTransform(transform, m_childrenTransform);
     [primaryLayer() setSublayerTransform:transform];
+
+    if (LayerMap* layerCloneMap = primaryLayerClones()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            [currLayer setSublayerTransform:transform];
+        }
+    }
 }
 
 void GraphicsLayerCA::updateMasksToBounds()
 {
     [m_layer.get() setMasksToBounds:m_masksToBounds];
+
+    if (LayerMap* layerCloneMap = m_layerClones.get()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            [currLayer setMasksToBounds:m_masksToBounds];
+        }
+    }
+
     updateDebugIndicators();
 }
 
 void GraphicsLayerCA::updateContentsOpaque()
 {
     [m_layer.get() setOpaque:m_contentsOpaque];
+
+    if (LayerMap* layerCloneMap = m_layerClones.get()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            [currLayer setOpaque:m_contentsOpaque];
+        }
+    }
 }
 
 void GraphicsLayerCA::updateBackfaceVisibility()
 {
     [m_layer.get() setDoubleSided:m_backfaceVisibility];
+
+    if (LayerMap* layerCloneMap = m_layerClones.get()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            [currLayer setDoubleSided:m_backfaceVisibility];
+        }
+    }
 }
 
 void GraphicsLayerCA::updateStructuralLayer()
@@ -1028,11 +1197,13 @@ void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose)
             [m_layer.get() removeFromSuperlayer];
             [[m_structuralLayer.get() superlayer] replaceSublayer:m_structuralLayer.get() with:m_layer.get()];
 
-            moveAnimationsForProperty(AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get());
+            moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get());
+            moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_structuralLayer.get(), m_layer.get());
 
             // Release the structural layer.
             m_structuralLayer = 0;
 
+            // Update the properties of m_layer now that we no loner have a structural layer.
             updateLayerPosition();
             updateLayerSize();
             updateAnchorPoint();
@@ -1077,30 +1248,28 @@ void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose)
 
     updateLayerNames();
 
-    // Copy the position from this layer.
+    // Update the properties of the structural layer.
     updateLayerPosition();
     updateLayerSize();
     updateAnchorPoint();
     updateTransform();
     updateChildrenTransform();
     
+    // Set properties of m_layer to their default values, since these are expressed on on the structural layer.
     CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
     [m_layer.get() setPosition:point];
-
     [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)];
     [m_layer.get() setTransform:CATransform3DIdentity];
-    
-    // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
     [m_layer.get() setOpacity:1];
 
     // Move this layer to be a child of the transform layer.
     [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_structuralLayer.get()];
     [m_structuralLayer.get() addSublayer:m_layer.get()];
 
-    moveAnimationsForProperty(AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get());
+    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get());
+    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_layer.get(), m_structuralLayer.get());
     
     updateSublayerList();
-
     updateOpacityOnLayer();
 }
 
@@ -1109,6 +1278,9 @@ GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose(
     if (preserves3D())
         return StructuralLayerForPreserves3D;
     
+    if (isReplicated())
+        return StructuralLayerForReplicaFlattening;
+    
     return NoStructuralLayer;
 }
 
@@ -1158,6 +1330,12 @@ void GraphicsLayerCA::updateContentsImage()
 #endif
         [m_contentsLayer.get() setContents:(id)m_pendingContentsImage.get()];
         m_pendingContentsImage = 0;
+
+        if (m_contentsLayerClones) {
+            LayerMap::const_iterator end = m_contentsLayerClones->end();
+            for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
+                [it->second.get() setContents:[m_contentsLayer.get() contents]];
+        }
         
         updateContentsRect();
     } else {
@@ -1202,6 +1380,15 @@ void GraphicsLayerCA::updateContentsRect()
 
     [m_contentsLayer.get() setPosition:point];
     [m_contentsLayer.get() setBounds:rect];
+
+    if (m_contentsLayerClones) {
+        LayerMap::const_iterator end = m_contentsLayerClones->end();
+        for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            [currLayer setPosition:point];
+            [currLayer setBounds:rect];
+        }
+    }
 }
 
 void GraphicsLayerCA::updateGeometryOrientation()
@@ -1223,8 +1410,74 @@ void GraphicsLayerCA::updateGeometryOrientation()
 
 void GraphicsLayerCA::updateMaskLayer()
 {
-    CALayer* maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0;
+    CALayer *maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0;
     [m_layer.get() setMask:maskCALayer];
+
+    LayerMap* maskLayerCloneMap = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayerClones() : 0;
+    
+    if (LayerMap* layerCloneMap = m_layerClones.get()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            
+            CALayer *maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->first).get() : 0;
+            [currLayer setMask:maskClone];
+        }
+    }
+}
+
+void GraphicsLayerCA::updateReplicatedLayers()
+{
+    // Clone the descendants of the replicated layer, and parent under us.
+    ReplicaState replicaState(ReplicaState::ReplicaBranch);
+
+    CALayer *replicaRoot = replicatedLayerRoot(replicaState);
+    if (!replicaRoot)
+        return;
+
+    if (m_structuralLayer)
+        [m_structuralLayer.get() insertSublayer:replicaRoot atIndex:0];
+    else
+        [m_layer.get() insertSublayer:replicaRoot atIndex:0];
+}
+
+// For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1.
+GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const
+{
+    size_t depth = m_replicaBranches.size();
+
+    const size_t bitsPerUChar = sizeof(UChar) * 8;
+    size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar;
+    
+    Vector<UChar> result(vectorSize);
+    result.fill(0);
+
+    // Create a string from the bit sequence which we can use to identify the clone.
+    // Note that the string may contain embedded nulls, but that's OK.
+    for (size_t i = 0; i < depth; ++i) {
+        UChar& currChar = result[i / bitsPerUChar];
+        currChar = (currChar << 1) | m_replicaBranches[i];
+    }
+    
+    return String::adopt(result);
+}
+
+CALayer *GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState)
+{
+    // Limit replica nesting, to avoid 2^N explosion of replica layers.
+    if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth)
+        return nil;
+
+    GraphicsLayerCA* replicatedLayer = static_cast<GraphicsLayerCA*>(m_replicatedLayer);
+    
+    CALayer *clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel);
+    FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer();
+
+    // Replica root has no offset or transform
+    [clonedLayerRoot setPosition:cloneRootPosition];
+    [clonedLayerRoot setTransform:CATransform3DIdentity];
+
+    return clonedLayerRoot;
 }
 
 void GraphicsLayerCA::updateLayerAnimations()
@@ -1308,6 +1561,18 @@ void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedP
     
     [layer removeAnimationForKey:animationName];
     [layer addAnimation:caAnim forKey:animationName];
+
+    if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            // Skip immediate replicas, since they move with the original.
+            if (m_replicaLayer && isReplicatedRootClone(it->first))
+                continue;
+            CALayer *currLayer = it->second.get();
+            [currLayer removeAnimationForKey:animationName];
+            [currLayer addAnimation:caAnim forKey:animationName];
+        }
+    }
 }
 
 // Workaround for <rdar://problem/7311367>
@@ -1336,6 +1601,18 @@ bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, cons
     
     [layer removeAnimationForKey:animationName];
     bug7311367Workaround(m_structuralLayer.get(), m_transform);
+
+    if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            // Skip immediate replicas, since they move with the original.
+            if (m_replicaLayer && isReplicatedRootClone(it->first))
+                continue;
+
+            CALayer *currLayer = it->second.get();
+            [currLayer removeAnimationForKey:animationName];
+        }
+    }
     return true;
 }
 
@@ -1389,6 +1666,18 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const S
     [pausedAnim setTimeOffset:timeOffset];
     
     [layer addAnimation:pausedAnim forKey:animationName];  // This will replace the running animation.
+
+    // Pause the animations on the clones too.
+    if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            // Skip immediate replicas, since they move with the original.
+            if (m_replicaLayer && isReplicatedRootClone(it->first))
+                continue;
+            CALayer *currLayer = it->second.get();
+            [currLayer addAnimation:pausedAnim forKey:animationName];
+        }
+    }
 }
 
 #if ENABLE(3D_CANVAS)
@@ -1403,7 +1692,7 @@ void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* gr
     m_platformGraphicsContext3D = context;
     m_platformTexture = texture;
     
-    noteLayerPropertyChanged(ChildrenChanged);
+    noteSublayersChanged();
     
     BEGIN_BLOCK_OBJC_EXCEPTIONS
 
@@ -1729,12 +2018,32 @@ void GraphicsLayerCA::suspendAnimations(double time)
     double t = currentTimeToMediaTime(time ? time : currentTime());
     [primaryLayer() setSpeed:0];
     [primaryLayer() setTimeOffset:t];
+
+    // Suspend the animations on the clones too.
+    if (LayerMap* layerCloneMap = primaryLayerClones()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            [currLayer setSpeed:0 ];
+            [currLayer setTimeOffset:t];
+        }
+    }
 }
 
 void GraphicsLayerCA::resumeAnimations()
 {
     [primaryLayer() setSpeed:1];
     [primaryLayer() setTimeOffset:0];
+
+    // Resume the animations on the clones too.
+    if (LayerMap* layerCloneMap = primaryLayerClones()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            CALayer *currLayer = it->second.get();
+            [currLayer setSpeed:1];
+            [currLayer setTimeOffset:0];
+        }
+    }
 }
 
 CALayer* GraphicsLayerCA::hostLayerForSublayers() const
@@ -1752,6 +2061,11 @@ CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
     return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
 }
 
+GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const
+{
+    return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones();
+}
+
 PlatformLayer* GraphicsLayerCA::platformLayer() const
 {
     return primaryLayer();
@@ -1853,9 +2167,9 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
 #endif
 
     // move over animations
-    moveAnimationsForProperty(AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
-    moveAnimationsForProperty(AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
-    moveAnimationsForProperty(AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
+    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
+    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
+    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
     
     // need to tell new layer to draw itself
     setNeedsDisplay();
@@ -1910,9 +2224,242 @@ void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer)
     }
 }
 
+void GraphicsLayerCA::ensureCloneLayers(CloneID cloneID, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel cloneLevel)
+{
+    structuralLayer = nil;
+    contentsLayer = nil;
+
+    if (!m_layerClones)
+        m_layerClones = new LayerMap;
+
+    if (!m_structuralLayerClones && m_structuralLayer)
+        m_structuralLayerClones = new LayerMap;
+
+    if (!m_contentsLayerClones && m_contentsLayer)
+        m_contentsLayerClones = new LayerMap;
+
+    // If we have the layers already, return them.
+    LayerMap::const_iterator it = m_layerClones->find(cloneID);
+    LayerMap::const_iterator end = m_layerClones->end();
+    if (it != end) {
+            primaryLayer = it->second.get();
+
+        if (m_structuralLayerClones)
+            structuralLayer = m_structuralLayerClones->get(cloneID).get();
+
+        if (m_contentsLayerClones)
+            contentsLayer = m_contentsLayerClones->get(cloneID).get();
+
+        return;
+    }
+    
+    // Create clones of the primary layer, and the structural and contents layers if we have them.
+    primaryLayer = cloneLayer(m_layer.get(), cloneLevel);
+
+#ifndef NDEBUG
+    [primaryLayer setName:[NSString stringWithFormat:@"Clone %d of layer %@", cloneID[0U], m_layer.get()]];
+#endif
+    m_layerClones->set(cloneID, primaryLayer);
+
+    if (m_structuralLayer) {
+        structuralLayer = cloneLayer(m_structuralLayer.get(), cloneLevel);
+#ifndef NDEBUG
+        [structuralLayer setName:[NSString stringWithFormat:@"Clone %d of layer %@", cloneID[0U], m_structuralLayer.get()]];
+#endif
+        m_structuralLayerClones->set(cloneID, structuralLayer);
+    }
+
+    if (m_contentsLayer) {
+        contentsLayer = cloneLayer(m_contentsLayer.get(), cloneLevel);
+#ifndef NDEBUG
+        [contentsLayer setName:[NSString stringWithFormat:@"Clone %d of layer %@", cloneID[0U], m_contentsLayer.get()]];
+#endif
+        m_contentsLayerClones->set(cloneID, contentsLayer);
+    }
+}
+
+void GraphicsLayerCA::removeCloneLayers()
+{
+    m_layerClones = 0;
+    m_structuralLayerClones = 0;
+    m_contentsLayerClones = 0;
+}
+
+FloatPoint GraphicsLayerCA::positionForCloneRootLayer() const
+{
+    // This can get called during a sync when we've just removed the m_replicaLayer.
+    if (!m_replicaLayer)
+        return FloatPoint();
+
+    FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition();
+    return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(),
+                      replicaPosition.y() + m_anchorPoint.y() * m_size.height());
+}
+
+void GraphicsLayerCA::propagateLayerChangeToReplicas()
+{
+    for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
+        GraphicsLayerCA* currLayerCA = static_cast<GraphicsLayerCA*>(currLayer);
+        if (!currLayerCA->hasCloneLayers())
+            break;
+
+        if (currLayerCA->replicaLayer())
+            static_cast<GraphicsLayerCA*>(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged);
+    }
+}
+
+CALayer *GraphicsLayerCA::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel)
+{
+    CALayer *primaryLayer;
+    CALayer *structuralLayer;
+    CALayer *contentsLayer;
+    ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, cloneLevel);
+
+    if (m_maskLayer) {
+        CALayer *maskClone = static_cast<GraphicsLayerCA*>(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
+        [primaryLayer setMask:maskClone];
+    }
+
+    if (m_replicatedLayer) {
+        // We are a replica being asked for clones of our layers.
+        CALayer *replicaRoot = replicatedLayerRoot(replicaState);
+        if (!replicaRoot)
+            return nil;
+
+        if (structuralLayer) {
+            [structuralLayer insertSublayer:replicaRoot atIndex:0];
+            return structuralLayer;
+        }
+        
+        [primaryLayer insertSublayer:replicaRoot atIndex:0];
+        return primaryLayer;
+    }
+
+    const Vector<GraphicsLayer*>& childLayers = children();
+    NSMutableArray* clonalSublayers = nil;
+
+    CALayer *replicaLayer = nil;
+    if (m_replicaLayer && m_replicaLayer != replicaRoot) {
+        // We have nested replicas. Ask the replica layer for a clone of its contents.
+        replicaState.setBranchType(ReplicaState::ReplicaBranch);
+        replicaLayer = static_cast<GraphicsLayerCA*>(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel);
+        replicaState.setBranchType(ReplicaState::ChildBranch);
+    }
+    
+    if (replicaLayer || structuralLayer || contentsLayer || childLayers.size() > 0) {
+        clonalSublayers = [[NSMutableArray alloc] init];
+
+        if (structuralLayer) {
+            // Replicas render behind the actual layer content.
+            if (replicaLayer)
+                [clonalSublayers addObject:replicaLayer];
+                
+            // Add the primary layer next. Even if we have negative z-order children, the primary layer always comes behind.
+            [clonalSublayers addObject:primaryLayer];
+        } else if (contentsLayer) {
+            // FIXME: add the contents layer in the correct order with negative z-order children.
+            // This does not cause visible rendering issues because currently contents layers are only used
+            // for replaced elements that don't have children.
+            [clonalSublayers addObject:contentsLayer];
+        }
+        
+        replicaState.push(ReplicaState::ChildBranch);
+
+        size_t numChildren = childLayers.size();
+        for (size_t i = 0; i < numChildren; ++i) {
+            GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+
+            CALayer *childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
+            if (childLayer)
+                [clonalSublayers addObject:childLayer];
+        }
+
+        replicaState.pop();
+
+        [clonalSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
+    }
+    
+    CALayer *result;
+    if (structuralLayer) {
+        [structuralLayer setSublayers:clonalSublayers];
+
+        if (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).
+            [primaryLayer setSublayers:nil];
+            [primaryLayer addSublayer:contentsLayer];
+        }
+
+        result = structuralLayer;
+    } else {
+        [primaryLayer setSublayers:clonalSublayers];
+        result = primaryLayer;
+    }
+
+    [clonalSublayers release];
+    return result;
+}
+
+CALayer *GraphicsLayerCA::cloneLayer(CALayer *layer, CloneLevel cloneLevel)
+{
+    static Class transformLayerClass = NSClassFromString(@"CATransformLayer");
+    CALayer *newLayer = nil;
+    if ([layer isKindOfClass:transformLayerClass])
+        newLayer = [transformLayerClass layer];
+    else
+        newLayer = [CALayer layer];
+
+    [newLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+    
+    [newLayer setPosition:[layer position]];
+    [newLayer setBounds:[layer bounds]];
+    [newLayer setAnchorPoint:[layer anchorPoint]];
+#if HAVE_MODERN_QUARTZCORE
+    [newLayer setAnchorPointZ:[layer anchorPointZ]];
+#endif
+    [newLayer setTransform:[layer transform]];
+    [newLayer setSublayerTransform:[layer sublayerTransform]];
+    [newLayer setContents:[layer contents]];
+    [newLayer setMasksToBounds:[layer masksToBounds]];
+    [newLayer setDoubleSided:[layer isDoubleSided]];
+    [newLayer setOpaque:[layer isOpaque]];
+    [newLayer setBackgroundColor:[layer backgroundColor]];
+
+    if (cloneLevel == IntermediateCloneLevel) {
+        [newLayer setOpacity:[layer opacity]];
+        moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyWebkitTransform, layer, newLayer);
+        moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyOpacity, layer, newLayer);
+    }
+    
+    if (showDebugBorders()) {
+        setLayerBorderColor(newLayer, Color(255, 122, 251));
+        [newLayer setBorderWidth:2];
+    }
+    
+    return newLayer;
+}
+
 void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
 {
-    [(preserves3D() ? m_layer.get() : primaryLayer()) setOpacity:accumulatedOpacity];
+    LayerMap* layerCloneMap = 0;
+    
+    if (preserves3D()) {
+        [m_layer.get() setOpacity:accumulatedOpacity];
+        layerCloneMap = m_layerClones.get();
+    } else {
+        [primaryLayer() setOpacity:accumulatedOpacity];
+        layerCloneMap = primaryLayerClones();
+    }
+
+    if (layerCloneMap) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            if (m_replicaLayer && isReplicatedRootClone(it->first))
+                continue;
+            CALayer *currLayer = it->second.get();
+            [currLayer setOpacity:m_opacity];
+        }
+    }
 }
 
 void GraphicsLayerCA::updateOpacityOnLayer()
@@ -1923,9 +2470,27 @@ void GraphicsLayerCA::updateOpacityOnLayer()
     distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1);
 #else
     [primaryLayer() setOpacity:m_opacity];
+
+    if (LayerMap* layerCloneMap = primaryLayerClones()) {
+        LayerMap::const_iterator end = layerCloneMap->end();
+        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+            if (m_replicaLayer && isReplicatedRootClone(it->first))
+                continue;
+
+            CALayer *currLayer = it->second.get();
+            [currLayer setOpacity:m_opacity];
+        }
+        
+    }
 #endif
 }
 
+void GraphicsLayerCA::noteSublayersChanged()
+{
+    noteLayerPropertyChanged(ChildrenChanged);
+    propagateLayerChangeToReplicas();
+}
+
 void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
 {
     if (!m_uncommittedChanges && m_client)
diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm
index 56b28e6..eb57e33 100644
--- a/WebCore/platform/graphics/mac/WebLayer.mm
+++ b/WebCore/platform/graphics/mac/WebLayer.mm
@@ -153,6 +153,13 @@ using namespace WebCore;
     }
 }
 
+- (void)display
+{
+    [super display];
+    if (m_layerOwner)
+        m_layerOwner->didDisplay();
+}
+
 - (void)drawInContext:(CGContextRef)context
 {
     [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:context];
diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm
index a1f5693..6b2d035 100644
--- a/WebCore/platform/graphics/mac/WebTiledLayer.mm
+++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm
@@ -92,6 +92,13 @@ using namespace WebCore;
     }
 }
 
+- (void)display
+{
+    [super display];
+    if (m_layerOwner)
+        m_layerOwner->didDisplay();
+}
+
 - (void)drawInContext:(CGContextRef)ctx
 {
     [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:ctx];
diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h
index f15c7cf..92f6927 100644
--- a/WebCore/rendering/RenderLayer.h
+++ b/WebCore/rendering/RenderLayer.h
@@ -205,6 +205,7 @@ public:
     void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, PaintBehavior);
 
     bool hasReflection() const { return renderer()->hasReflection(); }
+    bool isReflection() const { return renderer()->isReplica(); }
     RenderReplica* reflection() const { return m_reflection; }
     RenderLayer* reflectionLayer() const;
 
diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp
index c14e808..54e43d6 100644
--- a/WebCore/rendering/RenderLayerBacking.cpp
+++ b/WebCore/rendering/RenderLayerBacking.cpp
@@ -100,7 +100,9 @@ void RenderLayerBacking::createGraphicsLayer()
             else
                 m_graphicsLayer->setName(renderer()->renderName());
         }
-    } else
+    } else if (m_owningLayer->isReflection())
+        m_graphicsLayer->setName("Reflection");
+    else
         m_graphicsLayer->setName("Anonymous Node");
 #endif  // NDEBUG
 
@@ -196,6 +198,14 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
     if (updateMaskLayer(m_owningLayer->renderer()->hasMask()))
         m_graphicsLayer->setMaskLayer(m_maskLayer.get());
 
+    if (m_owningLayer->hasReflection()) {
+        if (m_owningLayer->reflectionLayer()->backing()) {
+            GraphicsLayer* reflectionLayer = m_owningLayer->reflectionLayer()->backing()->graphicsLayer();
+            m_graphicsLayer->setReplicatedByLayer(reflectionLayer);
+        }
+    } else
+        m_graphicsLayer->setReplicatedByLayer(0);
+
     if (isDirectlyCompositedImage())
         updateImageContents();
 
@@ -232,7 +242,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
         updateLayerOpacity(renderer()->style());
     
     RenderStyle* style = renderer()->style();
-    m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D);
+    m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D && !renderer()->hasReflection());
     m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible);
 
     RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer();
@@ -353,6 +363,16 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
         m_foregroundLayer->setOffsetFromRenderer(foregroundOffset);
     }
 
+    if (m_owningLayer->reflectionLayer() && m_owningLayer->reflectionLayer()->isComposited()) {
+        RenderLayerBacking* reflectionBacking = m_owningLayer->reflectionLayer()->backing();
+        reflectionBacking->updateGraphicsLayerGeometry();
+        
+        // The reflection layer has the bounds of m_owningLayer->reflectionLayer(),
+        // but the reflected layer is the bounds of this layer, so we need to position it appropriately.
+        FloatRect reflectedLayerBounds = compositedBounds();
+        reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(reflectedLayerBounds.location());
+    }
+
     m_graphicsLayer->setContentsRect(contentsBox());
     m_graphicsLayer->setDrawsContent(containsPaintedContent());
 }
@@ -666,7 +686,7 @@ bool RenderLayerBacking::hasNonCompositingContent() const
 
 bool RenderLayerBacking::containsPaintedContent() const
 {
-    if (isSimpleContainerCompositingLayer() || paintingGoesToWindow() || m_artificiallyInflatedBounds)
+    if (isSimpleContainerCompositingLayer() || paintingGoesToWindow() || m_artificiallyInflatedBounds || m_owningLayer->isReflection())
         return false;
 
     if (isDirectlyCompositedImage())
@@ -685,9 +705,7 @@ bool RenderLayerBacking::containsPaintedContent() const
 bool RenderLayerBacking::isDirectlyCompositedImage() const
 {
     RenderObject* renderObject = renderer();
-    return renderObject->isImage()
-            && !renderObject->hasMask() && !renderObject->hasReflection()
-            && !hasBoxDecorationsOrBackground(renderObject->style());
+    return renderObject->isImage() && !hasBoxDecorationsOrBackground(renderObject->style());
 }
 
 void RenderLayerBacking::rendererContentChanged()
@@ -861,14 +879,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
     
     m_owningLayer->updateLayerListsIfNeeded();
     
-    // Paint the reflection first if we have one.
-    if (m_owningLayer->hasReflection()) {
-        // Mark that we are now inside replica painting.
-        m_owningLayer->setPaintingInsideReflection(true);
-        m_owningLayer->reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, 0, RenderLayer::PaintLayerPaintingReflection);
-        m_owningLayer->setPaintingInsideReflection(false);
-    }
-
     // Calculate the clip rects we should use.
     IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
     m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect);
diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp
index cbc1849..9a7f3e5 100644
--- a/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/WebCore/rendering/RenderLayerCompositor.cpp
@@ -537,6 +537,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
             addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds);
     }
 
+    if (layer->reflectionLayer())
+        layer->reflectionLayer()->setMustOverlapCompositedLayers(needsToBeComposited(layer));
+
     // Subsequent layers in the parent stacking context also need to composite.
     if (childState.m_subtreeIsCompositing)
         compositingState.m_subtreeIsCompositing = true;
@@ -553,6 +556,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
     // Update backing now, so that we can use isComposited() reliably during tree traversal in rebuildCompositingLayerTree().
     if (updateBacking(layer, CompositingChangeRepaintNow))
         layersChanged = true;
+
+    if (layer->reflectionLayer() && updateLayerCompositingState(layer->reflectionLayer(), CompositingChangeRepaintNow))
+        layersChanged = true;
 }
 
 void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer)
@@ -599,9 +605,7 @@ void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer)
 #if ENABLE(VIDEO)
 bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const
 {
-    // FIXME: ideally we need to look at all ancestors for mask or video. But for now,
-    // just bail on the obvious cases.
-    if (o->hasReflection() || !m_hasAcceleratedCompositing)
+    if (!m_hasAcceleratedCompositing)
         return false;
 
     return o->supportsAcceleratedRendering();
@@ -619,6 +623,10 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, cons
         // The compositing state of all our children has been updated already, so now
         // we can compute and cache the composited bounds for this layer.
         layerBacking->updateCompositedBounds();
+
+        if (layer->reflectionLayer())
+            layer->reflectionLayer()->backing()->updateCompositedBounds();
+
         layerBacking->updateGraphicsLayerConfiguration();
         layerBacking->updateGraphicsLayerGeometry();
 
@@ -734,12 +742,19 @@ void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayer* com
     if (layer != compositingAncestor) {
         if (RenderLayerBacking* layerBacking = layer->backing()) {
             layerBacking->updateCompositedBounds();
+
+            if (layer->reflectionLayer())
+                layer->reflectionLayer()->backing()->updateCompositedBounds();
+
             layerBacking->updateGraphicsLayerGeometry();
             if (updateDepth == RenderLayerBacking::CompositingChildren)
                 return;
         }
     }
 
+    if (layer->reflectionLayer())
+        updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionLayer(), updateDepth);
+
     if (!layer->hasCompositingDescendant())
         return;
     
@@ -996,7 +1011,7 @@ bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* render
 
 bool RenderLayerCompositor::requiresCompositingWhenDescendantsAreCompositing(RenderObject* renderer) const
 {
-    return renderer->hasTransform() || renderer->isTransparent() || renderer->hasMask();
+    return renderer->hasTransform() || renderer->isTransparent() || renderer->hasMask() || renderer->hasReflection();
 }
 
 // If an element has negative z-index children, those children render in front of the 
diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h
index b65a036..3b02b84 100644
--- a/WebCore/rendering/RenderObject.h
+++ b/WebCore/rendering/RenderObject.h
@@ -281,6 +281,7 @@ public:
     virtual bool isRenderInline() const { return false; }
     virtual bool isRenderPart() const { return false; }
     virtual bool isRenderView() const { return false; }
+    virtual bool isReplica() const { return false; }
     virtual bool isRuby() const { return false; }
     virtual bool isRubyBase() const { return false; }
     virtual bool isRubyRun() const { return false; }
diff --git a/WebCore/rendering/RenderReplica.h b/WebCore/rendering/RenderReplica.h
index d5db3b7..48c64e4 100644
--- a/WebCore/rendering/RenderReplica.h
+++ b/WebCore/rendering/RenderReplica.h
@@ -46,6 +46,10 @@ public:
     virtual void calcPrefWidths();
     
     virtual void paint(PaintInfo&, int tx, int ty);
+
+private:
+    virtual bool isReplica() const { return true; }
+
 };
 
 } // namespace WebCore

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list