• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27
28#if USE(ACCELERATED_COMPOSITING)
29
30#import "GraphicsLayerCA.h"
31
32#import "Animation.h"
33#import "BlockExceptions.h"
34#if ENABLE(3D_CANVAS)
35#import "Canvas3DLayer.h"
36#endif
37#import "CString.h"
38#import "FloatConversion.h"
39#import "FloatRect.h"
40#import "Image.h"
41#import "PlatformString.h"
42#import <QuartzCore/QuartzCore.h>
43#import "RotateTransformOperation.h"
44#import "ScaleTransformOperation.h"
45#import "StringBuilder.h"
46#import "SystemTime.h"
47#import "TranslateTransformOperation.h"
48#import "WebLayer.h"
49#import "WebTiledLayer.h"
50#import <limits.h>
51#import <objc/objc-auto.h>
52#import <wtf/CurrentTime.h>
53#import <wtf/UnusedParam.h>
54#import <wtf/RetainPtr.h>
55
56using namespace std;
57
58#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
59
60namespace WebCore {
61
62// The threshold width or height above which a tiled layer will be used. This should be
63// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL
64// texture size limit on all supported hardware.
65static const int cMaxPixelDimension = 2000;
66
67// The width and height of a single tile in a tiled layer. Should be large enough to
68// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
69// to keep the overall tile cost low.
70static const int cTiledLayerTileSize = 512;
71
72// If we send a duration of 0 to CA, then it will use the default duration
73// of 250ms. So send a very small value instead.
74static const float cAnimationAlmostZeroDuration = 1e-3f;
75
76// CACurrentMediaTime() is a time since boot. These methods convert between that and
77// WebCore time, which is system time (UTC).
78static CFTimeInterval currentTimeToMediaTime(double t)
79{
80    return CACurrentMediaTime() + t - WTF::currentTime();
81}
82
83static double mediaTimeToCurrentTime(CFTimeInterval t)
84{
85    return WTF::currentTime() + t - CACurrentMediaTime();
86}
87
88} // namespace WebCore
89
90@interface CALayer(Private)
91- (void)setContentsChanged;
92@end
93
94@interface WebAnimationDelegate : NSObject {
95    WebCore::GraphicsLayerCA* m_graphicsLayer;
96}
97
98- (void)animationDidStart:(CAAnimation *)anim;
99- (WebCore::GraphicsLayerCA*)graphicsLayer;
100- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer;
101
102@end
103
104@implementation WebAnimationDelegate
105
106- (void)animationDidStart:(CAAnimation *)animation
107{
108    if (!m_graphicsLayer)
109        return;
110
111    double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]);
112    m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime);
113}
114
115- (WebCore::GraphicsLayerCA*)graphicsLayer
116{
117    return m_graphicsLayer;
118}
119
120- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer
121{
122    m_graphicsLayer = graphicsLayer;
123}
124
125@end
126
127namespace WebCore {
128
129static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t)
130{
131    toT3D.m11 = narrowPrecisionToFloat(t.m11());
132    toT3D.m12 = narrowPrecisionToFloat(t.m12());
133    toT3D.m13 = narrowPrecisionToFloat(t.m13());
134    toT3D.m14 = narrowPrecisionToFloat(t.m14());
135    toT3D.m21 = narrowPrecisionToFloat(t.m21());
136    toT3D.m22 = narrowPrecisionToFloat(t.m22());
137    toT3D.m23 = narrowPrecisionToFloat(t.m23());
138    toT3D.m24 = narrowPrecisionToFloat(t.m24());
139    toT3D.m31 = narrowPrecisionToFloat(t.m31());
140    toT3D.m32 = narrowPrecisionToFloat(t.m32());
141    toT3D.m33 = narrowPrecisionToFloat(t.m33());
142    toT3D.m34 = narrowPrecisionToFloat(t.m34());
143    toT3D.m41 = narrowPrecisionToFloat(t.m41());
144    toT3D.m42 = narrowPrecisionToFloat(t.m42());
145    toT3D.m43 = narrowPrecisionToFloat(t.m43());
146    toT3D.m44 = narrowPrecisionToFloat(t.m44());
147}
148
149static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size)
150{
151    switch (transformType) {
152        case TransformOperation::ROTATE:
153        case TransformOperation::ROTATE_X:
154        case TransformOperation::ROTATE_Y:
155            return [NSNumber numberWithDouble:transformOp ? deg2rad(static_cast<const RotateTransformOperation*>(transformOp)->angle()) : 0];
156        case TransformOperation::SCALE_X:
157            return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1];
158        case TransformOperation::SCALE_Y:
159            return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1];
160        case TransformOperation::SCALE_Z:
161            return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1];
162        case TransformOperation::TRANSLATE_X:
163            return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0];
164        case TransformOperation::TRANSLATE_Y:
165            return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->y(size) : 0];
166        case TransformOperation::TRANSLATE_Z:
167            return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0];
168        case TransformOperation::SCALE:
169        case TransformOperation::SCALE_3D:
170            return [NSArray arrayWithObjects:
171                        [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1],
172                        [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1],
173                        [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1],
174                        nil];
175        case TransformOperation::TRANSLATE:
176        case TransformOperation::TRANSLATE_3D:
177            return [NSArray arrayWithObjects:
178                        [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0],
179                        [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->y(size) : 0],
180                        [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0],
181                        nil];
182        case TransformOperation::SKEW_X:
183        case TransformOperation::SKEW_Y:
184        case TransformOperation::SKEW:
185        case TransformOperation::MATRIX:
186        case TransformOperation::ROTATE_3D:
187        case TransformOperation::MATRIX_3D:
188        case TransformOperation::PERSPECTIVE:
189        case TransformOperation::IDENTITY:
190        case TransformOperation::NONE: {
191            TransformationMatrix transform;
192            if (transformOp)
193                transformOp->apply(transform, size);
194            CATransform3D caTransform;
195            copyTransform(caTransform, transform);
196            return [NSValue valueWithCATransform3D:caTransform];
197        }
198    }
199
200    return 0;
201}
202
203#if HAVE_MODERN_QUARTZCORE
204static NSString* getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType)
205{
206    // Use literal strings to avoid link-time dependency on those symbols.
207    switch (transformType) {
208        case TransformOperation::ROTATE_X:
209            return @"rotateX"; // kCAValueFunctionRotateX;
210        case TransformOperation::ROTATE_Y:
211            return @"rotateY"; // kCAValueFunctionRotateY;
212        case TransformOperation::ROTATE:
213            return @"rotateZ"; // kCAValueFunctionRotateZ;
214        case TransformOperation::SCALE_X:
215            return @"scaleX"; // kCAValueFunctionScaleX;
216        case TransformOperation::SCALE_Y:
217            return @"scaleY"; // kCAValueFunctionScaleY;
218        case TransformOperation::SCALE_Z:
219            return @"scaleZ"; // kCAValueFunctionScaleZ;
220        case TransformOperation::TRANSLATE_X:
221            return @"translateX"; // kCAValueFunctionTranslateX;
222        case TransformOperation::TRANSLATE_Y:
223            return @"translateY"; // kCAValueFunctionTranslateY;
224        case TransformOperation::TRANSLATE_Z:
225            return @"translateZ"; // kCAValueFunctionTranslateZ;
226        case TransformOperation::SCALE:
227        case TransformOperation::SCALE_3D:
228            return @"scale"; // kCAValueFunctionScale;
229        case TransformOperation::TRANSLATE:
230        case TransformOperation::TRANSLATE_3D:
231            return @"translate"; // kCAValueFunctionTranslate;
232        default:
233            return nil;
234    }
235}
236#endif
237
238static String propertyIdToString(AnimatedPropertyID property)
239{
240    switch (property) {
241        case AnimatedPropertyWebkitTransform:
242            return "transform";
243        case AnimatedPropertyOpacity:
244            return "opacity";
245        case AnimatedPropertyBackgroundColor:
246            return "backgroundColor";
247        case AnimatedPropertyInvalid:
248            ASSERT_NOT_REACHED();
249    }
250    ASSERT_NOT_REACHED();
251    return "";
252}
253
254static String animationIdentifier(AnimatedPropertyID property, const String& keyframesName, int index)
255{
256    StringBuilder builder;
257
258    builder.append(propertyIdToString(property));
259    builder.append("_");
260
261    if (!keyframesName.isEmpty()) {
262        builder.append(keyframesName);
263        builder.append("_");
264    }
265    builder.append("_");
266    builder.append(String::number(index));
267    return builder.toString();
268}
269
270#if !HAVE_MODERN_QUARTZCORE
271static TransformationMatrix flipTransform()
272{
273    TransformationMatrix flipper;
274    flipper.flipY();
275    return flipper;
276}
277#endif
278
279static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction)
280{
281    switch (timingFunction.type()) {
282        case LinearTimingFunction:
283            return [CAMediaTimingFunction functionWithName:@"linear"];
284        case CubicBezierTimingFunction:
285            return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(timingFunction.x1()) :static_cast<float>(timingFunction.y1())
286                        :static_cast<float>(timingFunction.x2()) :static_cast<float>(timingFunction.y2())];
287    }
288    return 0;
289}
290
291static void setLayerBorderColor(PlatformLayer* layer, const Color& color)
292{
293    CGColorRef borderColor = createCGColor(color);
294    [layer setBorderColor:borderColor];
295    CGColorRelease(borderColor);
296}
297
298static void clearBorderColor(PlatformLayer* layer)
299{
300    [layer setBorderColor:nil];
301}
302
303static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color)
304{
305    CGColorRef bgColor = createCGColor(color);
306    [layer setBackgroundColor:bgColor];
307    CGColorRelease(bgColor);
308}
309
310static void clearLayerBackgroundColor(PlatformLayer* layer)
311{
312    [layer setBackgroundColor:0];
313}
314
315static void safeSetSublayers(CALayer* layer, NSArray* sublayers)
316{
317    // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC.
318    if (objc_collectingEnabled() && ![sublayers count]) {
319        while ([[layer sublayers] count])
320            [[[layer sublayers] objectAtIndex:0] removeFromSuperlayer];
321        return;
322    }
323
324    [layer setSublayers:sublayers];
325}
326
327static bool caValueFunctionSupported()
328{
329    static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
330    return sHaveValueFunction;
331}
332
333static bool forceSoftwareAnimation()
334{
335    static bool forceSoftwareAnimation = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreForceSoftwareAnimation"];
336    return forceSoftwareAnimation;
337}
338
339GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation()
340{
341    return CompositingCoordinatesBottomUp;
342}
343
344static NSDictionary* nullActionsDictionary()
345{
346    NSNull* nullValue = [NSNull null];
347    NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys:
348                             nullValue, @"anchorPoint",
349                             nullValue, @"bounds",
350                             nullValue, @"contents",
351                             nullValue, @"contentsRect",
352                             nullValue, @"opacity",
353                             nullValue, @"position",
354                             nullValue, @"shadowColor",
355                             nullValue, @"sublayerTransform",
356                             nullValue, @"sublayers",
357                             nullValue, @"transform",
358                             nullValue, @"zPosition",
359                             nil];
360    return actions;
361}
362
363PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
364{
365    return new GraphicsLayerCA(client);
366}
367
368GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
369    : GraphicsLayer(client)
370    , m_contentsLayerPurpose(NoContentsLayer)
371    , m_contentsLayerHasBackgroundColor(false)
372    , m_uncommittedChanges(NoChange)
373#if ENABLE(3D_CANVAS)
374    , m_platformGraphicsContext3D(NullPlatformGraphicsContext3D)
375    , m_platformTexture(NullPlatform3DObject)
376#endif
377{
378    BEGIN_BLOCK_OBJC_EXCEPTIONS
379    m_layer.adoptNS([[WebLayer alloc] init]);
380    [m_layer.get() setLayerOwner:this];
381
382#if !HAVE_MODERN_QUARTZCORE
383    setContentsOrientation(defaultContentsOrientation());
384#endif
385
386    updateDebugIndicators();
387
388    m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]);
389    [m_animationDelegate.get() setLayer:this];
390
391    END_BLOCK_OBJC_EXCEPTIONS
392}
393
394GraphicsLayerCA::~GraphicsLayerCA()
395{
396    // We release our references to the CALayers here, but do not actively unparent them,
397    // since that will cause a commit and break our batched commit model. The layers will
398    // get released when the rootmost modified GraphicsLayerCA rebuilds its child layers.
399
400    BEGIN_BLOCK_OBJC_EXCEPTIONS
401
402    // Clean up the WK layer.
403    if (m_layer) {
404        WebLayer* layer = m_layer.get();
405        [layer setLayerOwner:nil];
406    }
407
408    if (m_contentsLayer) {
409        if ([m_contentsLayer.get() respondsToSelector:@selector(setLayerOwner:)])
410            [(id)m_contentsLayer.get() setLayerOwner:nil];
411    }
412
413    // animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
414    [m_animationDelegate.get() setLayer:0];
415
416    // Release the clone layers inside the exception-handling block.
417    removeCloneLayers();
418
419    END_BLOCK_OBJC_EXCEPTIONS
420}
421
422void GraphicsLayerCA::setName(const String& name)
423{
424    String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
425    GraphicsLayer::setName(longName);
426    noteLayerPropertyChanged(NameChanged);
427}
428
429NativeLayer GraphicsLayerCA::nativeLayer() const
430{
431    return m_layer.get();
432}
433
434bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
435{
436    bool childrenChanged = GraphicsLayer::setChildren(children);
437    if (childrenChanged)
438        noteSublayersChanged();
439
440    return childrenChanged;
441}
442
443void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
444{
445    GraphicsLayer::addChild(childLayer);
446    noteSublayersChanged();
447}
448
449void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
450{
451    GraphicsLayer::addChildAtIndex(childLayer, index);
452    noteSublayersChanged();
453}
454
455void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
456{
457    GraphicsLayer::addChildBelow(childLayer, sibling);
458    noteSublayersChanged();
459}
460
461void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
462{
463    GraphicsLayer::addChildAbove(childLayer, sibling);
464    noteSublayersChanged();
465}
466
467bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
468{
469    if (GraphicsLayer::replaceChild(oldChild, newChild)) {
470        noteSublayersChanged();
471        return true;
472    }
473    return false;
474}
475
476void GraphicsLayerCA::removeFromParent()
477{
478    if (m_parent)
479        static_cast<GraphicsLayerCA*>(m_parent)->noteSublayersChanged();
480    GraphicsLayer::removeFromParent();
481}
482
483void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer)
484{
485    if (layer == m_maskLayer)
486        return;
487
488    GraphicsLayer::setMaskLayer(layer);
489    noteLayerPropertyChanged(MaskLayerChanged);
490
491    propagateLayerChangeToReplicas();
492
493    if (m_replicatedLayer)
494        static_cast<GraphicsLayerCA*>(m_replicatedLayer)->propagateLayerChangeToReplicas();
495}
496
497void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer)
498{
499    if (layer == m_replicatedLayer)
500        return;
501
502    GraphicsLayer::setReplicatedLayer(layer);
503    noteLayerPropertyChanged(ReplicatedLayerChanged);
504}
505
506void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer)
507{
508    if (layer == m_replicaLayer)
509        return;
510
511    GraphicsLayer::setReplicatedByLayer(layer);
512    noteSublayersChanged();
513    noteLayerPropertyChanged(ReplicatedLayerChanged);
514}
515
516void GraphicsLayerCA::setPosition(const FloatPoint& point)
517{
518    if (point == m_position)
519        return;
520
521    GraphicsLayer::setPosition(point);
522    noteLayerPropertyChanged(PositionChanged);
523}
524
525void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
526{
527    if (point == m_anchorPoint)
528        return;
529
530    GraphicsLayer::setAnchorPoint(point);
531    noteLayerPropertyChanged(AnchorPointChanged);
532}
533
534void GraphicsLayerCA::setSize(const FloatSize& size)
535{
536    if (size == m_size)
537        return;
538
539    GraphicsLayer::setSize(size);
540    noteLayerPropertyChanged(SizeChanged);
541}
542
543void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
544{
545    if (t == m_transform)
546        return;
547
548    GraphicsLayer::setTransform(t);
549    noteLayerPropertyChanged(TransformChanged);
550}
551
552void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
553{
554    if (t == m_childrenTransform)
555        return;
556
557    GraphicsLayer::setChildrenTransform(t);
558    noteLayerPropertyChanged(ChildrenTransformChanged);
559}
560
561void GraphicsLayerCA::moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer *fromLayer, CALayer *toLayer)
562{
563    for (int index = 0; ; ++index) {
564        String animName = animationIdentifier(property, keyframesName, index);
565
566        CAAnimation* anim = [fromLayer animationForKey:animName];
567        if (!anim)
568            break;
569
570        switch (operation) {
571            case Move:
572                [anim retain];
573                [fromLayer removeAnimationForKey:animName];
574                [toLayer addAnimation:anim forKey:animName];
575                [anim release];
576                break;
577
578            case Copy:
579                [toLayer addAnimation:anim forKey:animName];
580                break;
581        }
582    }
583}
584
585void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, CALayer *fromLayer, CALayer *toLayer)
586{
587    // Move transitions for this property.
588    moveOrCopyAllAnimationsForProperty(operation, property, "", fromLayer, toLayer);
589
590    // Look for running animations affecting this property.
591    KeyframeAnimationsMap::const_iterator end = m_runningKeyframeAnimations.end();
592    for (KeyframeAnimationsMap::const_iterator it = m_runningKeyframeAnimations.begin(); it != end; ++it)
593        moveOrCopyAllAnimationsForProperty(operation, property, it->first, fromLayer, toLayer);
594}
595
596void GraphicsLayerCA::setPreserves3D(bool preserves3D)
597{
598    if (preserves3D == m_preserves3D)
599        return;
600
601    GraphicsLayer::setPreserves3D(preserves3D);
602    noteLayerPropertyChanged(Preserves3DChanged);
603}
604
605void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
606{
607    if (masksToBounds == m_masksToBounds)
608        return;
609
610    GraphicsLayer::setMasksToBounds(masksToBounds);
611    noteLayerPropertyChanged(MasksToBoundsChanged);
612}
613
614void GraphicsLayerCA::setDrawsContent(bool drawsContent)
615{
616    if (drawsContent == m_drawsContent)
617        return;
618
619    GraphicsLayer::setDrawsContent(drawsContent);
620    noteLayerPropertyChanged(DrawsContentChanged);
621}
622
623void GraphicsLayerCA::setBackgroundColor(const Color& color)
624{
625    if (m_backgroundColorSet && m_backgroundColor == color)
626        return;
627
628    GraphicsLayer::setBackgroundColor(color);
629
630    m_contentsLayerHasBackgroundColor = true;
631    noteLayerPropertyChanged(BackgroundColorChanged);
632}
633
634void GraphicsLayerCA::clearBackgroundColor()
635{
636    if (!m_backgroundColorSet)
637        return;
638
639    GraphicsLayer::clearBackgroundColor();
640    m_contentsLayerHasBackgroundColor = false;
641    noteLayerPropertyChanged(BackgroundColorChanged);
642}
643
644void GraphicsLayerCA::setContentsOpaque(bool opaque)
645{
646    if (m_contentsOpaque == opaque)
647        return;
648
649    GraphicsLayer::setContentsOpaque(opaque);
650    noteLayerPropertyChanged(ContentsOpaqueChanged);
651}
652
653void GraphicsLayerCA::setBackfaceVisibility(bool visible)
654{
655    if (m_backfaceVisibility == visible)
656        return;
657
658    GraphicsLayer::setBackfaceVisibility(visible);
659    noteLayerPropertyChanged(BackfaceVisibilityChanged);
660}
661
662void GraphicsLayerCA::setOpacity(float opacity)
663{
664    float clampedOpacity = max(0.0f, min(opacity, 1.0f));
665
666    if (clampedOpacity == m_opacity)
667        return;
668
669    GraphicsLayer::setOpacity(clampedOpacity);
670    noteLayerPropertyChanged(OpacityChanged);
671}
672
673void GraphicsLayerCA::setNeedsDisplay()
674{
675    FloatRect hugeRect(-numeric_limits<float>::max() / 2, -numeric_limits<float>::max() / 2,
676                       numeric_limits<float>::max(), numeric_limits<float>::max());
677
678    setNeedsDisplayInRect(hugeRect);
679}
680
681void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
682{
683    if (!drawsContent())
684        return;
685
686    const size_t maxDirtyRects = 32;
687
688    for (size_t i = 0; i < m_dirtyRects.size(); ++i) {
689        if (m_dirtyRects[i].contains(rect))
690            return;
691    }
692
693    if (m_dirtyRects.size() < maxDirtyRects)
694        m_dirtyRects.append(rect);
695    else
696        m_dirtyRects[0].unite(rect);
697
698    noteLayerPropertyChanged(DirtyRectsChanged);
699}
700
701void GraphicsLayerCA::setContentsRect(const IntRect& rect)
702{
703    if (rect == m_contentsRect)
704        return;
705
706    GraphicsLayer::setContentsRect(rect);
707    noteLayerPropertyChanged(ContentsRectChanged);
708}
709
710bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset)
711{
712    if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
713        return false;
714
715#if !HAVE_MODERN_QUARTZCORE
716    // Older versions of QuartzCore do not handle opacity in transform layers properly, so we will
717    // always do software animation in that case.
718    if (valueList.property() == AnimatedPropertyOpacity)
719        return false;
720#endif
721
722    bool createdAnimations = false;
723    if (valueList.property() == AnimatedPropertyWebkitTransform)
724        createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, timeOffset, boxSize);
725    else
726        createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, timeOffset);
727
728    if (createdAnimations)
729        noteLayerPropertyChanged(AnimationChanged);
730
731    return createdAnimations;
732}
733
734void GraphicsLayerCA::removeAnimationsForProperty(AnimatedPropertyID property)
735{
736    if (m_transitionPropertiesToRemove.find(property) != m_transitionPropertiesToRemove.end())
737        return;
738
739    m_transitionPropertiesToRemove.add(property);
740    noteLayerPropertyChanged(AnimationChanged);
741}
742
743void GraphicsLayerCA::removeAnimationsForKeyframes(const String& animationName)
744{
745    if (!animationIsRunning(animationName))
746        return;
747
748    m_keyframeAnimationsToProcess.add(animationName, AnimationProcessingAction(Remove));
749    noteLayerPropertyChanged(AnimationChanged);
750}
751
752void GraphicsLayerCA::pauseAnimation(const String& keyframesName, double timeOffset)
753{
754    if (!animationIsRunning(keyframesName))
755        return;
756
757    AnimationsToProcessMap::iterator it = m_keyframeAnimationsToProcess.find(keyframesName);
758    if (it != m_keyframeAnimationsToProcess.end()) {
759        AnimationProcessingAction& processingInfo = it->second;
760        // If an animation is scheduled to be removed, don't change the remove to a pause.
761        if (processingInfo.action != Remove)
762            processingInfo.action = Pause;
763    } else
764        m_keyframeAnimationsToProcess.add(keyframesName, AnimationProcessingAction(Pause, timeOffset));
765
766    noteLayerPropertyChanged(AnimationChanged);
767}
768
769void GraphicsLayerCA::setContentsToImage(Image* image)
770{
771    if (image) {
772        m_pendingContentsImage = image->nativeImageForCurrentFrame();
773        CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get());
774
775        static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
776        if (colorSpace && CFEqual(colorSpace, deviceRGB)) {
777            // CoreGraphics renders images tagged with DeviceRGB using the color space of the main display. When we hand such
778            // images to CA we need to tag them similarly so CA rendering matches CG rendering.
779            static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay);
780            m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB));
781        }
782        m_contentsLayerPurpose = ContentsLayerForImage;
783        if (!m_contentsLayer)
784            noteSublayersChanged();
785    } else {
786        m_pendingContentsImage = 0;
787        m_contentsLayerPurpose = NoContentsLayer;
788        if (m_contentsLayer)
789            noteSublayersChanged();
790    }
791
792    noteLayerPropertyChanged(ContentsImageChanged);
793}
794
795void GraphicsLayerCA::setContentsToMedia(PlatformLayer* mediaLayer)
796{
797    if (mediaLayer == m_contentsLayer)
798        return;
799
800    m_contentsLayer = mediaLayer;
801    m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer;
802
803    noteSublayersChanged();
804    noteLayerPropertyChanged(ContentsMediaLayerChanged);
805}
806
807void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
808{
809    if (orientation == m_geometryOrientation)
810        return;
811
812    GraphicsLayer::setGeometryOrientation(orientation);
813    noteLayerPropertyChanged(GeometryOrientationChanged);
814
815#if !HAVE_MODERN_QUARTZCORE
816    // Geometry orientation is mapped onto children transform in older QuartzCores.
817    switch (m_geometryOrientation) {
818        case CompositingCoordinatesTopDown:
819            setChildrenTransform(TransformationMatrix());
820            break;
821
822        case CompositingCoordinatesBottomUp:
823            setChildrenTransform(flipTransform());
824            break;
825    }
826#endif
827}
828
829void GraphicsLayerCA::didDisplay(PlatformLayer* layer)
830{
831    CALayer* sourceLayer;
832    LayerMap* layerCloneMap;
833
834    if (layer == m_layer) {
835        sourceLayer = m_layer.get();
836        layerCloneMap = m_layerClones.get();
837    } else if (layer == m_contentsLayer) {
838        sourceLayer = m_contentsLayer.get();
839        layerCloneMap = m_contentsLayerClones.get();
840    } else
841        return;
842
843    if (layerCloneMap) {
844        LayerMap::const_iterator end = layerCloneMap->end();
845        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
846            CALayer *currClone = it->second.get();
847            if (!currClone)
848                continue;
849
850            if ([currClone contents] != [sourceLayer contents])
851                [currClone setContents:[sourceLayer contents]];
852            else
853                [currClone setContentsChanged];
854        }
855    }
856}
857
858void GraphicsLayerCA::syncCompositingState()
859{
860    recursiveCommitChanges();
861}
862
863void GraphicsLayerCA::recursiveCommitChanges()
864{
865    commitLayerChangesBeforeSublayers();
866
867    if (m_maskLayer)
868        static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesBeforeSublayers();
869
870    const Vector<GraphicsLayer*>& childLayers = children();
871    size_t numChildren = childLayers.size();
872    for (size_t i = 0; i < numChildren; ++i) {
873        GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
874        curChild->recursiveCommitChanges();
875    }
876
877    if (m_replicaLayer)
878        static_cast<GraphicsLayerCA*>(m_replicaLayer)->recursiveCommitChanges();
879
880    if (m_maskLayer)
881        static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesAfterSublayers();
882
883    commitLayerChangesAfterSublayers();
884}
885
886void GraphicsLayerCA::commitLayerChangesBeforeSublayers()
887{
888    if (!m_uncommittedChanges)
889        return;
890
891    BEGIN_BLOCK_OBJC_EXCEPTIONS
892
893    // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to
894    if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged))
895        updateStructuralLayer();
896
897    if (m_uncommittedChanges & NameChanged)
898        updateLayerNames();
899
900    if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged
901        updateContentsImage();
902
903    if (m_uncommittedChanges & ContentsMediaLayerChanged) // Needs to happen before ChildrenChanged
904        updateContentsMediaLayer();
905
906#if ENABLE(3D_CANVAS)
907    if (m_uncommittedChanges & ContentsGraphicsContext3DChanged) // Needs to happen before ChildrenChanged
908        updateContentsGraphicsContext3D();
909#endif
910
911    if (m_uncommittedChanges & BackgroundColorChanged)  // Needs to happen before ChildrenChanged, and after updating image or video
912        updateLayerBackgroundColor();
913
914    if (m_uncommittedChanges & ChildrenChanged)
915        updateSublayerList();
916
917    if (m_uncommittedChanges & PositionChanged)
918        updateLayerPosition();
919
920    if (m_uncommittedChanges & AnchorPointChanged)
921        updateAnchorPoint();
922
923    if (m_uncommittedChanges & SizeChanged)
924        updateLayerSize();
925
926    if (m_uncommittedChanges & TransformChanged)
927        updateTransform();
928
929    if (m_uncommittedChanges & ChildrenTransformChanged)
930        updateChildrenTransform();
931
932    if (m_uncommittedChanges & MasksToBoundsChanged)
933        updateMasksToBounds();
934
935    if (m_uncommittedChanges & DrawsContentChanged)
936        updateLayerDrawsContent();
937
938    if (m_uncommittedChanges & ContentsOpaqueChanged)
939        updateContentsOpaque();
940
941    if (m_uncommittedChanges & BackfaceVisibilityChanged)
942        updateBackfaceVisibility();
943
944    if (m_uncommittedChanges & OpacityChanged)
945        updateOpacityOnLayer();
946
947    if (m_uncommittedChanges & AnimationChanged)
948        updateLayerAnimations();
949
950    if (m_uncommittedChanges & DirtyRectsChanged)
951        repaintLayerDirtyRects();
952
953    if (m_uncommittedChanges & ContentsRectChanged)
954        updateContentsRect();
955
956    if (m_uncommittedChanges & GeometryOrientationChanged)
957        updateGeometryOrientation();
958
959    if (m_uncommittedChanges & MaskLayerChanged)
960        updateMaskLayer();
961
962    END_BLOCK_OBJC_EXCEPTIONS
963}
964
965void GraphicsLayerCA::commitLayerChangesAfterSublayers()
966{
967    if (!m_uncommittedChanges)
968        return;
969
970    BEGIN_BLOCK_OBJC_EXCEPTIONS
971
972    if (m_uncommittedChanges & ReplicatedLayerChanged)
973        updateReplicatedLayers();
974
975    m_uncommittedChanges = NoChange;
976    END_BLOCK_OBJC_EXCEPTIONS
977}
978
979void GraphicsLayerCA::updateLayerNames()
980{
981    switch (structuralLayerPurpose()) {
982        case StructuralLayerForPreserves3D:
983            [m_structuralLayer.get() setName:("Transform layer " + name())];
984            break;
985        case StructuralLayerForReplicaFlattening:
986            [m_structuralLayer.get() setName:("Replica flattening layer " + name())];
987            break;
988        case NoStructuralLayer:
989            break;
990    }
991    [m_layer.get() setName:name()];
992}
993
994void GraphicsLayerCA::updateSublayerList()
995{
996    NSMutableArray* newSublayers = nil;
997
998    const Vector<GraphicsLayer*>& childLayers = children();
999
1000    if (m_structuralLayer || m_contentsLayer || childLayers.size() > 0) {
1001        newSublayers = [[NSMutableArray alloc] init];
1002
1003        if (m_structuralLayer) {
1004            // Add the replica layer first.
1005            if (m_replicaLayer)
1006                [newSublayers addObject:static_cast<GraphicsLayerCA*>(m_replicaLayer)->primaryLayer()];
1007            // Add the primary layer. Even if we have negative z-order children, the primary layer always comes behind.
1008            [newSublayers addObject:m_layer.get()];
1009        } else if (m_contentsLayer) {
1010            // FIXME: add the contents layer in the correct order with negative z-order children.
1011            // This does not cause visible rendering issues because currently contents layers are only used
1012            // for replaced elements that don't have children.
1013            [newSublayers addObject:m_contentsLayer.get()];
1014        }
1015
1016        size_t numChildren = childLayers.size();
1017        for (size_t i = 0; i < numChildren; ++i) {
1018            GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
1019            CALayer *childLayer = curChild->layerForSuperlayer();
1020            [newSublayers addObject:childLayer];
1021        }
1022
1023        [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
1024    }
1025
1026    if (m_structuralLayer) {
1027        safeSetSublayers(m_structuralLayer.get(), newSublayers);
1028
1029        if (m_contentsLayer) {
1030            // If we have a transform layer, then the contents layer is parented in the
1031            // primary layer (which is itself a child of the transform layer).
1032            safeSetSublayers(m_layer.get(), nil);
1033            [m_layer.get() addSublayer:m_contentsLayer.get()];
1034        }
1035    } else
1036        safeSetSublayers(m_layer.get(), newSublayers);
1037
1038    [newSublayers release];
1039}
1040
1041void GraphicsLayerCA::updateLayerPosition()
1042{
1043    // Position is offset on the layer by the layer anchor point.
1044    CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
1045                                   m_position.y() + m_anchorPoint.y() * m_size.height());
1046
1047    [primaryLayer() setPosition:posPoint];
1048
1049    if (LayerMap* layerCloneMap = primaryLayerClones()) {
1050        LayerMap::const_iterator end = layerCloneMap->end();
1051        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1052            CGPoint clonePosition = posPoint;
1053            if (m_replicaLayer && isReplicatedRootClone(it->first)) {
1054                // Maintain the special-case position for the root of a clone subtree,
1055                // which we set up in replicatedLayerRoot().
1056                clonePosition = positionForCloneRootLayer();
1057            }
1058            CALayer *currLayer = it->second.get();
1059            [currLayer setPosition:clonePosition];
1060        }
1061    }
1062}
1063
1064void GraphicsLayerCA::updateLayerSize()
1065{
1066    CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height());
1067    if (m_structuralLayer) {
1068        [m_structuralLayer.get() setBounds:rect];
1069
1070        if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
1071            LayerMap::const_iterator end = layerCloneMap->end();
1072            for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
1073                [it->second.get() setBounds:rect];
1074        }
1075
1076        // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
1077        CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
1078        [m_layer.get() setPosition:centerPoint];
1079
1080        if (LayerMap* layerCloneMap = m_layerClones.get()) {
1081            LayerMap::const_iterator end = layerCloneMap->end();
1082            for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
1083                [it->second.get() setPosition:centerPoint];
1084        }
1085    }
1086
1087    bool needTiledLayer = requiresTiledLayer(m_size);
1088    if (needTiledLayer != m_usingTiledLayer)
1089        swapFromOrToTiledLayer(needTiledLayer);
1090
1091    [m_layer.get() setBounds:rect];
1092    if (LayerMap* layerCloneMap = m_layerClones.get()) {
1093        LayerMap::const_iterator end = layerCloneMap->end();
1094        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
1095            [it->second.get() setBounds:rect];
1096    }
1097
1098    // Contents transform may depend on height.
1099    updateContentsTransform();
1100
1101    // Note that we don't resize m_contentsLayer. It's up the caller to do that.
1102
1103    // if we've changed the bounds, we need to recalculate the position
1104    // of the layer, taking anchor point into account.
1105    updateLayerPosition();
1106}
1107
1108void GraphicsLayerCA::updateAnchorPoint()
1109{
1110    [primaryLayer() setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())];
1111#if HAVE_MODERN_QUARTZCORE
1112    [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
1113#endif
1114
1115    if (LayerMap* layerCloneMap = primaryLayerClones()) {
1116        LayerMap::const_iterator end = layerCloneMap->end();
1117        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1118            CALayer *currLayer = it->second.get();
1119            [currLayer setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())];
1120#if HAVE_MODERN_QUARTZCORE
1121            [currLayer setAnchorPointZ:m_anchorPoint.z()];
1122#endif
1123        }
1124    }
1125
1126    updateLayerPosition();
1127}
1128
1129void GraphicsLayerCA::updateTransform()
1130{
1131    CATransform3D transform;
1132    copyTransform(transform, m_transform);
1133    [primaryLayer() setTransform:transform];
1134
1135    if (LayerMap* layerCloneMap = primaryLayerClones()) {
1136        LayerMap::const_iterator end = layerCloneMap->end();
1137        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1138            CALayer *currLayer = it->second.get();
1139            if (m_replicaLayer && isReplicatedRootClone(it->first)) {
1140                // Maintain the special-case transform for the root of a clone subtree,
1141                // which we set up in replicatedLayerRoot().
1142                [currLayer setTransform:CATransform3DIdentity];
1143            } else
1144                [currLayer setTransform:transform];
1145        }
1146    }
1147}
1148
1149void GraphicsLayerCA::updateChildrenTransform()
1150{
1151    CATransform3D transform;
1152    copyTransform(transform, m_childrenTransform);
1153    [primaryLayer() setSublayerTransform:transform];
1154
1155    if (LayerMap* layerCloneMap = primaryLayerClones()) {
1156        LayerMap::const_iterator end = layerCloneMap->end();
1157        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1158            CALayer *currLayer = it->second.get();
1159            [currLayer setSublayerTransform:transform];
1160        }
1161    }
1162}
1163
1164void GraphicsLayerCA::updateMasksToBounds()
1165{
1166    [m_layer.get() setMasksToBounds:m_masksToBounds];
1167
1168    if (LayerMap* layerCloneMap = m_layerClones.get()) {
1169        LayerMap::const_iterator end = layerCloneMap->end();
1170        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1171            CALayer *currLayer = it->second.get();
1172            [currLayer setMasksToBounds:m_masksToBounds];
1173        }
1174    }
1175
1176    updateDebugIndicators();
1177}
1178
1179void GraphicsLayerCA::updateContentsOpaque()
1180{
1181    [m_layer.get() setOpaque:m_contentsOpaque];
1182
1183    if (LayerMap* layerCloneMap = m_layerClones.get()) {
1184        LayerMap::const_iterator end = layerCloneMap->end();
1185        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1186            CALayer *currLayer = it->second.get();
1187            [currLayer setOpaque:m_contentsOpaque];
1188        }
1189    }
1190}
1191
1192void GraphicsLayerCA::updateBackfaceVisibility()
1193{
1194    [m_layer.get() setDoubleSided:m_backfaceVisibility];
1195
1196    if (LayerMap* layerCloneMap = m_layerClones.get()) {
1197        LayerMap::const_iterator end = layerCloneMap->end();
1198        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1199            CALayer *currLayer = it->second.get();
1200            [currLayer setDoubleSided:m_backfaceVisibility];
1201        }
1202    }
1203}
1204
1205void GraphicsLayerCA::updateStructuralLayer()
1206{
1207    ensureStructuralLayer(structuralLayerPurpose());
1208}
1209
1210void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose)
1211{
1212    if (purpose == NoStructuralLayer) {
1213        if (m_structuralLayer) {
1214            // Replace the transformLayer in the parent with this layer.
1215            [m_layer.get() removeFromSuperlayer];
1216            [[m_structuralLayer.get() superlayer] replaceSublayer:m_structuralLayer.get() with:m_layer.get()];
1217
1218            moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get());
1219            moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_structuralLayer.get(), m_layer.get());
1220
1221            // Release the structural layer.
1222            m_structuralLayer = 0;
1223
1224            // Update the properties of m_layer now that we no loner have a structural layer.
1225            updateLayerPosition();
1226            updateLayerSize();
1227            updateAnchorPoint();
1228            updateTransform();
1229            updateChildrenTransform();
1230
1231            updateSublayerList();
1232            updateOpacityOnLayer();
1233        }
1234        return;
1235    }
1236
1237    bool structuralLayerChanged = false;
1238
1239    if (purpose == StructuralLayerForPreserves3D) {
1240        Class transformLayerClass = NSClassFromString(@"CATransformLayer");
1241        if (!transformLayerClass)
1242            return;
1243
1244        if (m_structuralLayer && ![m_structuralLayer.get() isKindOfClass:transformLayerClass])
1245            m_structuralLayer = 0;
1246
1247        if (!m_structuralLayer) {
1248            m_structuralLayer.adoptNS([[transformLayerClass alloc] init]);
1249            structuralLayerChanged = true;
1250        }
1251    } else {
1252        if (m_structuralLayer && ![m_structuralLayer.get() isMemberOfClass:[CALayer self]])
1253            m_structuralLayer = 0;
1254
1255        if (!m_structuralLayer) {
1256            m_structuralLayer.adoptNS([[CALayer alloc] init]);
1257            structuralLayerChanged = true;
1258        }
1259    }
1260
1261    if (!structuralLayerChanged)
1262        return;
1263
1264    // Turn off default animations.
1265    [m_structuralLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
1266
1267    updateLayerNames();
1268
1269    // Update the properties of the structural layer.
1270    updateLayerPosition();
1271    updateLayerSize();
1272    updateAnchorPoint();
1273    updateTransform();
1274    updateChildrenTransform();
1275
1276    // Set properties of m_layer to their default values, since these are expressed on on the structural layer.
1277    CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
1278    [m_layer.get() setPosition:point];
1279    [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)];
1280    [m_layer.get() setTransform:CATransform3DIdentity];
1281    [m_layer.get() setOpacity:1];
1282
1283    // Move this layer to be a child of the transform layer.
1284    [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_structuralLayer.get()];
1285    [m_structuralLayer.get() addSublayer:m_layer.get()];
1286
1287    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get());
1288    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_layer.get(), m_structuralLayer.get());
1289
1290    updateSublayerList();
1291    updateOpacityOnLayer();
1292}
1293
1294GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose() const
1295{
1296    if (preserves3D())
1297        return StructuralLayerForPreserves3D;
1298
1299    if (isReplicated())
1300        return StructuralLayerForReplicaFlattening;
1301
1302    return NoStructuralLayer;
1303}
1304
1305void GraphicsLayerCA::updateLayerDrawsContent()
1306{
1307    bool needTiledLayer = requiresTiledLayer(m_size);
1308    if (needTiledLayer != m_usingTiledLayer)
1309        swapFromOrToTiledLayer(needTiledLayer);
1310
1311    if (m_drawsContent)
1312        [m_layer.get() setNeedsDisplay];
1313    else
1314        [m_layer.get() setContents:nil];
1315
1316    updateDebugIndicators();
1317}
1318
1319void GraphicsLayerCA::updateLayerBackgroundColor()
1320{
1321    if (!m_contentsLayer)
1322        return;
1323
1324    // We never create the contents layer just for background color yet.
1325    if (m_backgroundColorSet)
1326        setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
1327    else
1328        clearLayerBackgroundColor(m_contentsLayer.get());
1329}
1330
1331void GraphicsLayerCA::updateContentsImage()
1332{
1333    if (m_pendingContentsImage) {
1334        if (!m_contentsLayer.get()) {
1335            WebLayer* imageLayer = [WebLayer layer];
1336#ifndef NDEBUG
1337            [imageLayer setName:@"Image Layer"];
1338#endif
1339            setupContentsLayer(imageLayer);
1340            m_contentsLayer.adoptNS([imageLayer retain]);
1341            // m_contentsLayer will be parented by updateSublayerList
1342        }
1343
1344        // FIXME: maybe only do trilinear if the image is being scaled down,
1345        // but then what if the layer size changes?
1346#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1347        [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
1348#endif
1349        [m_contentsLayer.get() setContents:(id)m_pendingContentsImage.get()];
1350        m_pendingContentsImage = 0;
1351
1352        if (m_contentsLayerClones) {
1353            LayerMap::const_iterator end = m_contentsLayerClones->end();
1354            for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
1355                [it->second.get() setContents:[m_contentsLayer.get() contents]];
1356        }
1357
1358        updateContentsRect();
1359    } else {
1360        // No image.
1361        // m_contentsLayer will be removed via updateSublayerList.
1362        m_contentsLayer = 0;
1363    }
1364}
1365
1366void GraphicsLayerCA::updateContentsMediaLayer()
1367{
1368    // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList().
1369    if (m_contentsLayer) {
1370        setupContentsLayer(m_contentsLayer.get());
1371        updateContentsRect();
1372    }
1373}
1374
1375#if ENABLE(3D_CANVAS)
1376void GraphicsLayerCA::updateContentsGraphicsContext3D()
1377{
1378    // Canvas3D layer was set as m_contentsLayer, and will get parented in updateSublayerList().
1379    if (m_contentsLayer) {
1380        setupContentsLayer(m_contentsLayer.get());
1381        [m_contentsLayer.get() setNeedsDisplay];
1382        updateContentsRect();
1383    }
1384}
1385#endif
1386
1387void GraphicsLayerCA::updateContentsRect()
1388{
1389    if (!m_contentsLayer)
1390        return;
1391
1392    CGPoint point = CGPointMake(m_contentsRect.x(),
1393                                m_contentsRect.y());
1394    CGRect rect = CGRectMake(0.0f,
1395                             0.0f,
1396                             m_contentsRect.width(),
1397                             m_contentsRect.height());
1398
1399    [m_contentsLayer.get() setPosition:point];
1400    [m_contentsLayer.get() setBounds:rect];
1401
1402    if (m_contentsLayerClones) {
1403        LayerMap::const_iterator end = m_contentsLayerClones->end();
1404        for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) {
1405            CALayer *currLayer = it->second.get();
1406            [currLayer setPosition:point];
1407            [currLayer setBounds:rect];
1408        }
1409    }
1410}
1411
1412void GraphicsLayerCA::updateGeometryOrientation()
1413{
1414#if HAVE_MODERN_QUARTZCORE
1415    switch (geometryOrientation()) {
1416        case CompositingCoordinatesTopDown:
1417            [m_layer.get() setGeometryFlipped:NO];
1418            break;
1419
1420        case CompositingCoordinatesBottomUp:
1421            [m_layer.get() setGeometryFlipped:YES];
1422            break;
1423    }
1424    // Geometry orientation is mapped onto children transform in older QuartzCores,
1425    // so is handled via setGeometryOrientation().
1426#endif
1427}
1428
1429void GraphicsLayerCA::updateMaskLayer()
1430{
1431    CALayer *maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0;
1432    [m_layer.get() setMask:maskCALayer];
1433
1434    LayerMap* maskLayerCloneMap = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayerClones() : 0;
1435
1436    if (LayerMap* layerCloneMap = m_layerClones.get()) {
1437        LayerMap::const_iterator end = layerCloneMap->end();
1438        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1439            CALayer *currLayer = it->second.get();
1440
1441            CALayer *maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->first).get() : 0;
1442            [currLayer setMask:maskClone];
1443        }
1444    }
1445}
1446
1447void GraphicsLayerCA::updateReplicatedLayers()
1448{
1449    // Clone the descendants of the replicated layer, and parent under us.
1450    ReplicaState replicaState(ReplicaState::ReplicaBranch);
1451
1452    CALayer *replicaRoot = replicatedLayerRoot(replicaState);
1453    if (!replicaRoot)
1454        return;
1455
1456    if (m_structuralLayer)
1457        [m_structuralLayer.get() insertSublayer:replicaRoot atIndex:0];
1458    else
1459        [m_layer.get() insertSublayer:replicaRoot atIndex:0];
1460}
1461
1462// For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1.
1463GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const
1464{
1465    size_t depth = m_replicaBranches.size();
1466
1467    const size_t bitsPerUChar = sizeof(UChar) * 8;
1468    size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar;
1469
1470    Vector<UChar> result(vectorSize);
1471    result.fill(0);
1472
1473    // Create a string from the bit sequence which we can use to identify the clone.
1474    // Note that the string may contain embedded nulls, but that's OK.
1475    for (size_t i = 0; i < depth; ++i) {
1476        UChar& currChar = result[i / bitsPerUChar];
1477        currChar = (currChar << 1) | m_replicaBranches[i];
1478    }
1479
1480    return String::adopt(result);
1481}
1482
1483CALayer *GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState)
1484{
1485    // Limit replica nesting, to avoid 2^N explosion of replica layers.
1486    if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth)
1487        return nil;
1488
1489    GraphicsLayerCA* replicatedLayer = static_cast<GraphicsLayerCA*>(m_replicatedLayer);
1490
1491    CALayer *clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel);
1492    FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer();
1493
1494    // Replica root has no offset or transform
1495    [clonedLayerRoot setPosition:cloneRootPosition];
1496    [clonedLayerRoot setTransform:CATransform3DIdentity];
1497
1498    return clonedLayerRoot;
1499}
1500
1501void GraphicsLayerCA::updateLayerAnimations()
1502{
1503    if (m_transitionPropertiesToRemove.size()) {
1504        HashSet<int>::const_iterator end = m_transitionPropertiesToRemove.end();
1505        for (HashSet<AnimatedProperty>::const_iterator it = m_transitionPropertiesToRemove.begin(); it != end; ++it) {
1506            AnimatedPropertyID currProperty = static_cast<AnimatedPropertyID>(*it);
1507            // Remove all animations with this property in the key.
1508            for (int index = 0; ; ++index) {
1509                if (!removeAnimationFromLayer(currProperty, "", index))
1510                    break;
1511            }
1512        }
1513
1514        m_transitionPropertiesToRemove.clear();
1515    }
1516
1517    if (m_keyframeAnimationsToProcess.size()) {
1518        AnimationsToProcessMap::const_iterator end = m_keyframeAnimationsToProcess.end();
1519        for (AnimationsToProcessMap::const_iterator it = m_keyframeAnimationsToProcess.begin(); it != end; ++it) {
1520            const String& currKeyframeName = it->first;
1521            KeyframeAnimationsMap::iterator animationIt = m_runningKeyframeAnimations.find(currKeyframeName);
1522            if (animationIt == m_runningKeyframeAnimations.end())
1523                continue;
1524
1525            const AnimationProcessingAction& processingInfo = it->second;
1526            const Vector<AnimationPair>& animations = animationIt->second;
1527            for (size_t i = 0; i < animations.size(); ++i) {
1528                const AnimationPair& currPair = animations[i];
1529                switch (processingInfo.action) {
1530                    case Remove:
1531                        removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second);
1532                        break;
1533                    case Pause:
1534                        pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second, processingInfo.timeOffset);
1535                        break;
1536                }
1537            }
1538
1539            if (processingInfo.action == Remove)
1540                m_runningKeyframeAnimations.remove(currKeyframeName);
1541        }
1542
1543        m_keyframeAnimationsToProcess.clear();
1544    }
1545
1546    size_t numAnimations;
1547    if ((numAnimations = m_uncomittedAnimations.size())) {
1548        for (size_t i = 0; i < numAnimations; ++i) {
1549            const LayerAnimation& pendingAnimation = m_uncomittedAnimations[i];
1550            setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_keyframesName, pendingAnimation.m_index, pendingAnimation.m_timeOffset);
1551
1552            if (!pendingAnimation.m_keyframesName.isEmpty()) {
1553                // If this is a keyframe anim, we have to remember the association of keyframes name to property/index pairs,
1554                // so we can remove the animations later if needed.
1555                // For transitions, we can just generate animation names with property and index.
1556                KeyframeAnimationsMap::iterator it = m_runningKeyframeAnimations.find(pendingAnimation.m_keyframesName);
1557                if (it == m_runningKeyframeAnimations.end()) {
1558                    Vector<AnimationPair> firstPair;
1559                    firstPair.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index));
1560                    m_runningKeyframeAnimations.add(pendingAnimation.m_keyframesName, firstPair);
1561                } else {
1562                    Vector<AnimationPair>& animPairs = it->second;
1563                    animPairs.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index));
1564                }
1565            }
1566        }
1567
1568        m_uncomittedAnimations.clear();
1569    }
1570}
1571
1572void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset)
1573{
1574    PlatformLayer* layer = animatedLayer(property);
1575
1576    [caAnim setTimeOffset:timeOffset];
1577
1578    String animationName = animationIdentifier(property, keyframesName, index);
1579
1580    [layer removeAnimationForKey:animationName];
1581    [layer addAnimation:caAnim forKey:animationName];
1582
1583    if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
1584        LayerMap::const_iterator end = layerCloneMap->end();
1585        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1586            // Skip immediate replicas, since they move with the original.
1587            if (m_replicaLayer && isReplicatedRootClone(it->first))
1588                continue;
1589            CALayer *currLayer = it->second.get();
1590            [currLayer removeAnimationForKey:animationName];
1591            [currLayer addAnimation:caAnim forKey:animationName];
1592        }
1593    }
1594}
1595
1596// Workaround for <rdar://problem/7311367>
1597static void bug7311367Workaround(CALayer* transformLayer, const TransformationMatrix& transform)
1598{
1599    if (!transformLayer)
1600        return;
1601
1602    CATransform3D caTransform;
1603    copyTransform(caTransform, transform);
1604    caTransform.m41 += 1;
1605    [transformLayer setTransform:caTransform];
1606
1607    caTransform.m41 -= 1;
1608    [transformLayer setTransform:caTransform];
1609}
1610
1611bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, const String& keyframesName, int index)
1612{
1613    PlatformLayer* layer = animatedLayer(property);
1614
1615    String animationName = animationIdentifier(property, keyframesName, index);
1616
1617    if (![layer animationForKey:animationName])
1618        return false;
1619
1620    [layer removeAnimationForKey:animationName];
1621    bug7311367Workaround(m_structuralLayer.get(), m_transform);
1622
1623    if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
1624        LayerMap::const_iterator end = layerCloneMap->end();
1625        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1626            // Skip immediate replicas, since they move with the original.
1627            if (m_replicaLayer && isReplicatedRootClone(it->first))
1628                continue;
1629
1630            CALayer *currLayer = it->second.get();
1631            [currLayer removeAnimationForKey:animationName];
1632        }
1633    }
1634    return true;
1635}
1636
1637static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimation* to)
1638{
1639    [to setBeginTime:[from beginTime]];
1640    [to setDuration:[from duration]];
1641    [to setRepeatCount:[from repeatCount]];
1642    [to setAutoreverses:[from autoreverses]];
1643    [to setFillMode:[from fillMode]];
1644    [to setRemovedOnCompletion:[from isRemovedOnCompletion]];
1645    [to setAdditive:[from isAdditive]];
1646    [to setTimingFunction:[from timingFunction]];
1647
1648#if HAVE_MODERN_QUARTZCORE
1649    [to setValueFunction:[from valueFunction]];
1650#endif
1651}
1652
1653void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset)
1654{
1655    PlatformLayer* layer = animatedLayer(property);
1656
1657    String animationName = animationIdentifier(property, keyframesName, index);
1658
1659    CAAnimation* caAnim = [layer animationForKey:animationName];
1660    if (!caAnim)
1661        return;
1662
1663    // Animations on the layer are immutable, so we have to clone and modify.
1664    CAPropertyAnimation* pausedAnim = nil;
1665    if ([caAnim isKindOfClass:[CAKeyframeAnimation class]]) {
1666        CAKeyframeAnimation* existingKeyframeAnim = static_cast<CAKeyframeAnimation*>(caAnim);
1667        CAKeyframeAnimation* newAnim = [CAKeyframeAnimation animationWithKeyPath:[existingKeyframeAnim keyPath]];
1668        copyAnimationProperties(existingKeyframeAnim, newAnim);
1669        [newAnim setValues:[existingKeyframeAnim values]];
1670        [newAnim setKeyTimes:[existingKeyframeAnim keyTimes]];
1671        [newAnim setTimingFunctions:[existingKeyframeAnim timingFunctions]];
1672        pausedAnim = newAnim;
1673    } else if ([caAnim isKindOfClass:[CABasicAnimation class]]) {
1674        CABasicAnimation* existingPropertyAnim = static_cast<CABasicAnimation*>(caAnim);
1675        CABasicAnimation* newAnim = [CABasicAnimation animationWithKeyPath:[existingPropertyAnim keyPath]];
1676        copyAnimationProperties(existingPropertyAnim, newAnim);
1677        [newAnim setFromValue:[existingPropertyAnim fromValue]];
1678        [newAnim setToValue:[existingPropertyAnim toValue]];
1679        pausedAnim = newAnim;
1680    }
1681
1682    // pausedAnim has the beginTime of caAnim already.
1683    [pausedAnim setSpeed:0];
1684    [pausedAnim setTimeOffset:timeOffset];
1685
1686    [layer addAnimation:pausedAnim forKey:animationName];  // This will replace the running animation.
1687
1688    // Pause the animations on the clones too.
1689    if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
1690        LayerMap::const_iterator end = layerCloneMap->end();
1691        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
1692            // Skip immediate replicas, since they move with the original.
1693            if (m_replicaLayer && isReplicatedRootClone(it->first))
1694                continue;
1695            CALayer *currLayer = it->second.get();
1696            [currLayer addAnimation:pausedAnim forKey:animationName];
1697        }
1698    }
1699}
1700
1701#if ENABLE(3D_CANVAS)
1702void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* graphicsContext3D)
1703{
1704    PlatformGraphicsContext3D context = graphicsContext3D->platformGraphicsContext3D();
1705    Platform3DObject texture = graphicsContext3D->platformTexture();
1706
1707    if (context == m_platformGraphicsContext3D && texture == m_platformTexture)
1708        return;
1709
1710    m_platformGraphicsContext3D = context;
1711    m_platformTexture = texture;
1712
1713    noteSublayersChanged();
1714
1715    BEGIN_BLOCK_OBJC_EXCEPTIONS
1716
1717    if (m_platformGraphicsContext3D != NullPlatformGraphicsContext3D && m_platformTexture != NullPlatform3DObject) {
1718        // create the inner 3d layer
1719        m_contentsLayer.adoptNS([[Canvas3DLayer alloc] initWithContext:static_cast<CGLContextObj>(m_platformGraphicsContext3D) texture:static_cast<GLuint>(m_platformTexture)]);
1720#ifndef NDEBUG
1721        [m_contentsLayer.get() setName:@"3D Layer"];
1722#endif
1723        [m_contentsLayer.get() setLayerOwner:this];
1724    } else {
1725        // remove the inner layer
1726        [m_contentsLayer.get() setLayerOwner:0];
1727        m_contentsLayer = 0;
1728    }
1729
1730    END_BLOCK_OBJC_EXCEPTIONS
1731
1732    noteLayerPropertyChanged(ContentsGraphicsContext3DChanged);
1733    m_contentsLayerPurpose = m_contentsLayer ? ContentsLayerForGraphicsLayer3D : NoContentsLayer;
1734}
1735#endif
1736
1737void GraphicsLayerCA::repaintLayerDirtyRects()
1738{
1739    if (!m_dirtyRects.size())
1740        return;
1741
1742    for (size_t i = 0; i < m_dirtyRects.size(); ++i)
1743        [m_layer.get() setNeedsDisplayInRect:m_dirtyRects[i]];
1744
1745    m_dirtyRects.clear();
1746}
1747
1748bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset)
1749{
1750    ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
1751
1752    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1753
1754    bool isKeyframe = valueList.size() > 2;
1755    bool valuesOK;
1756
1757    bool additive = false;
1758    int animationIndex = 0;
1759
1760    CAPropertyAnimation* caAnimation;
1761    if (isKeyframe) {
1762        CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive);
1763        valuesOK = setAnimationKeyframes(valueList, animation, keyframeAnim);
1764        caAnimation = keyframeAnim;
1765    } else {
1766        CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive);
1767        valuesOK = setAnimationEndpoints(valueList, animation, basicAnim);
1768        caAnimation = basicAnim;
1769    }
1770
1771    if (!valuesOK)
1772        return false;
1773
1774    m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset));
1775
1776    END_BLOCK_OBJC_EXCEPTIONS;
1777
1778    return true;
1779}
1780
1781bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset, const IntSize& boxSize)
1782{
1783    ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
1784
1785    TransformOperationList functionList;
1786    bool listsMatch, hasBigRotation;
1787    fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation);
1788
1789    // We need to fall back to software animation if we don't have setValueFunction:, and
1790    // we would need to animate each incoming transform function separately. This is the
1791    // case if we have a rotation >= 180 or we have more than one transform function.
1792    if ((hasBigRotation || functionList.size() > 1) && !caValueFunctionSupported())
1793        return false;
1794
1795    bool validMatrices = true;
1796
1797    BEGIN_BLOCK_OBJC_EXCEPTIONS;
1798
1799    // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation.
1800    // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation
1801    // if that's not true as well.
1802    bool isMatrixAnimation = !listsMatch || !caValueFunctionSupported();
1803
1804    size_t numAnimations = isMatrixAnimation ? 1 : functionList.size();
1805    bool isKeyframe = valueList.size() > 2;
1806
1807    // Iterate through the transform functions, sending an animation for each one.
1808    for (size_t animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
1809        TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex];
1810        CAPropertyAnimation* caAnimation;
1811
1812        // CA applies animations in reverse order (<rdar://problem/7095638>) so we need the last one we add (per property)
1813        // to be non-additive.
1814        bool additive = animationIndex < (numAnimations - 1);
1815        if (isKeyframe) {
1816            CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive);
1817            validMatrices = setTransformAnimationKeyframes(valueList, animation, keyframeAnim, animationIndex, transformOp, isMatrixAnimation, boxSize);
1818            caAnimation = keyframeAnim;
1819        } else {
1820            CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive);
1821            validMatrices = setTransformAnimationEndpoints(valueList, animation, basicAnim, animationIndex, transformOp, isMatrixAnimation, boxSize);
1822            caAnimation = basicAnim;
1823        }
1824
1825        if (!validMatrices)
1826            break;
1827
1828        m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset));
1829    }
1830
1831    END_BLOCK_OBJC_EXCEPTIONS;
1832
1833    return validMatrices;
1834}
1835
1836CABasicAnimation* GraphicsLayerCA::createBasicAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
1837{
1838    CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:propertyIdToString(property)];
1839    setupAnimation(basicAnim, anim, additive);
1840    return basicAnim;
1841}
1842
1843CAKeyframeAnimation* GraphicsLayerCA::createKeyframeAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
1844{
1845    CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:propertyIdToString(property)];
1846    setupAnimation(keyframeAnim, anim, additive);
1847    return keyframeAnim;
1848}
1849
1850void GraphicsLayerCA::setupAnimation(CAPropertyAnimation* propertyAnim, const Animation* anim, bool additive)
1851{
1852    double duration = anim->duration();
1853    if (duration <= 0)
1854        duration = cAnimationAlmostZeroDuration;
1855
1856    float repeatCount = anim->iterationCount();
1857    if (repeatCount == Animation::IterationCountInfinite)
1858        repeatCount = FLT_MAX;
1859    else if (anim->direction() == Animation::AnimationDirectionAlternate)
1860        repeatCount /= 2;
1861
1862    [propertyAnim setDuration:duration];
1863    [propertyAnim setRepeatCount:repeatCount];
1864    [propertyAnim setAutoreverses:anim->direction()];
1865    [propertyAnim setRemovedOnCompletion:NO];
1866    [propertyAnim setAdditive:additive];
1867    [propertyAnim setFillMode:@"extended"];
1868
1869    [propertyAnim setDelegate:m_animationDelegate.get()];
1870}
1871
1872CAMediaTimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim)
1873{
1874    const TimingFunction* tf = 0;
1875    if (animValue->timingFunction())
1876        tf = animValue->timingFunction();
1877    else if (anim->isTimingFunctionSet())
1878        tf = &anim->timingFunction();
1879
1880    return getCAMediaTimingFunction(tf ? *tf : TimingFunction());
1881}
1882
1883bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, CABasicAnimation* basicAnim)
1884{
1885    id fromValue = nil;
1886    id toValue = nil;
1887
1888    switch (valueList.property()) {
1889        case AnimatedPropertyOpacity: {
1890            const FloatAnimationValue* startVal = static_cast<const FloatAnimationValue*>(valueList.at(0));
1891            const FloatAnimationValue* endVal = static_cast<const FloatAnimationValue*>(valueList.at(1));
1892            fromValue = [NSNumber numberWithFloat:startVal->value()];
1893            toValue = [NSNumber numberWithFloat:endVal->value()];
1894            break;
1895        }
1896        default:
1897            ASSERT_NOT_REACHED();     // we don't animate color yet
1898            break;
1899    }
1900
1901    // This codepath is used for 2-keyframe animations, so we still need to look in the start
1902    // for a timing function.
1903    CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
1904    [basicAnim setTimingFunction:timingFunction];
1905
1906    [basicAnim setFromValue:fromValue];
1907    [basicAnim setToValue:toValue];
1908
1909    return true;
1910}
1911
1912bool GraphicsLayerCA::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* anim, CAKeyframeAnimation* keyframeAnim)
1913{
1914    RetainPtr<NSMutableArray> keyTimes(AdoptNS, [[NSMutableArray alloc] init]);
1915    RetainPtr<NSMutableArray> values(AdoptNS, [[NSMutableArray alloc] init]);
1916    RetainPtr<NSMutableArray> timingFunctions(AdoptNS, [[NSMutableArray alloc] init]);
1917
1918    for (unsigned i = 0; i < valueList.size(); ++i) {
1919        const AnimationValue* curValue = valueList.at(i);
1920        [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue->keyTime()]];
1921
1922        switch (valueList.property()) {
1923            case AnimatedPropertyOpacity: {
1924                const FloatAnimationValue* floatValue = static_cast<const FloatAnimationValue*>(curValue);
1925                [values.get() addObject:[NSNumber numberWithFloat:floatValue->value()]];
1926                break;
1927            }
1928            default:
1929                ASSERT_NOT_REACHED();     // we don't animate color yet
1930                break;
1931        }
1932
1933        CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, anim);
1934        [timingFunctions.get() addObject:timingFunction];
1935    }
1936
1937    // We toss the last tfArray value because it has to one shorter than the others.
1938    [timingFunctions.get() removeLastObject];
1939
1940    [keyframeAnim setKeyTimes:keyTimes.get()];
1941    [keyframeAnim setValues:values.get()];
1942    [keyframeAnim setTimingFunctions:timingFunctions.get()];
1943
1944    return true;
1945}
1946
1947bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, CABasicAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOp, bool isMatrixAnimation, const IntSize& boxSize)
1948{
1949    id fromValue;
1950    id toValue;
1951
1952    ASSERT(valueList.size() == 2);
1953    const TransformAnimationValue* startValue = static_cast<const TransformAnimationValue*>(valueList.at(0));
1954    const TransformAnimationValue* endValue = static_cast<const TransformAnimationValue*>(valueList.at(1));
1955
1956    if (isMatrixAnimation) {
1957        TransformationMatrix fromTransform, toTransform;
1958        startValue->value()->apply(boxSize, fromTransform);
1959        endValue->value()->apply(boxSize, toTransform);
1960
1961        // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
1962        if (!fromTransform.isInvertible() || !toTransform.isInvertible())
1963            return false;
1964
1965        CATransform3D caTransform;
1966        copyTransform(caTransform, fromTransform);
1967        fromValue = [NSValue valueWithCATransform3D:caTransform];
1968
1969        copyTransform(caTransform, toTransform);
1970        toValue = [NSValue valueWithCATransform3D:caTransform];
1971    } else {
1972        fromValue = getTransformFunctionValue(startValue->value()->at(functionIndex), transformOp, boxSize);
1973        toValue = getTransformFunctionValue(endValue->value()->at(functionIndex), transformOp, boxSize);
1974    }
1975
1976    // This codepath is used for 2-keyframe animations, so we still need to look in the start
1977    // for a timing function.
1978    CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
1979    [basicAnim setTimingFunction:timingFunction];
1980
1981    [basicAnim setFromValue:fromValue];
1982    [basicAnim setToValue:toValue];
1983
1984#if HAVE_MODERN_QUARTZCORE
1985    if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOp))
1986        [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
1987#endif
1988
1989    return true;
1990}
1991
1992bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, CAKeyframeAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
1993{
1994    RetainPtr<NSMutableArray> keyTimes(AdoptNS, [[NSMutableArray alloc] init]);
1995    RetainPtr<NSMutableArray> values(AdoptNS, [[NSMutableArray alloc] init]);
1996    RetainPtr<NSMutableArray> timingFunctions(AdoptNS, [[NSMutableArray alloc] init]);
1997
1998    for (unsigned i = 0; i < valueList.size(); ++i) {
1999        const TransformAnimationValue* curValue = static_cast<const TransformAnimationValue*>(valueList.at(i));
2000        [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue->keyTime()]];
2001
2002        if (isMatrixAnimation) {
2003            TransformationMatrix transform;
2004            curValue->value()->apply(boxSize, transform);
2005
2006            // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
2007            if (!transform.isInvertible())
2008                return false;
2009
2010            CATransform3D caTransform;
2011            copyTransform(caTransform, transform);
2012            [values.get() addObject:[NSValue valueWithCATransform3D:caTransform]];
2013        } else {
2014            const TransformOperation* transformOp = curValue->value()->at(functionIndex);
2015            [values.get() addObject:getTransformFunctionValue(transformOp, transformOpType, boxSize)];
2016        }
2017
2018        CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, animation);
2019        [timingFunctions.get() addObject:timingFunction];
2020    }
2021
2022    // We toss the last tfArray value because it has to one shorter than the others.
2023    [timingFunctions.get() removeLastObject];
2024
2025    [keyframeAnim setKeyTimes:keyTimes.get()];
2026    [keyframeAnim setValues:values.get()];
2027    [keyframeAnim setTimingFunctions:timingFunctions.get()];
2028
2029#if HAVE_MODERN_QUARTZCORE
2030    if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType))
2031        [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
2032#endif
2033    return true;
2034}
2035
2036void GraphicsLayerCA::suspendAnimations(double time)
2037{
2038    double t = currentTimeToMediaTime(time ? time : currentTime());
2039    [primaryLayer() setSpeed:0];
2040    [primaryLayer() setTimeOffset:t];
2041
2042    // Suspend the animations on the clones too.
2043    if (LayerMap* layerCloneMap = primaryLayerClones()) {
2044        LayerMap::const_iterator end = layerCloneMap->end();
2045        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
2046            CALayer *currLayer = it->second.get();
2047            [currLayer setSpeed:0 ];
2048            [currLayer setTimeOffset:t];
2049        }
2050    }
2051}
2052
2053void GraphicsLayerCA::resumeAnimations()
2054{
2055    [primaryLayer() setSpeed:1];
2056    [primaryLayer() setTimeOffset:0];
2057
2058    // Resume the animations on the clones too.
2059    if (LayerMap* layerCloneMap = primaryLayerClones()) {
2060        LayerMap::const_iterator end = layerCloneMap->end();
2061        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
2062            CALayer *currLayer = it->second.get();
2063            [currLayer setSpeed:1];
2064            [currLayer setTimeOffset:0];
2065        }
2066    }
2067}
2068
2069CALayer* GraphicsLayerCA::hostLayerForSublayers() const
2070{
2071    return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get();
2072}
2073
2074CALayer* GraphicsLayerCA::layerForSuperlayer() const
2075{
2076    return m_structuralLayer ? m_structuralLayer.get() : m_layer.get();
2077}
2078
2079CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
2080{
2081    return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
2082}
2083
2084GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const
2085{
2086    return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones();
2087}
2088
2089PlatformLayer* GraphicsLayerCA::platformLayer() const
2090{
2091    return primaryLayer();
2092}
2093
2094void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
2095{
2096    BEGIN_BLOCK_OBJC_EXCEPTIONS
2097
2098    if (color.isValid())
2099        setLayerBackgroundColor(m_layer.get(), color);
2100    else
2101        clearLayerBackgroundColor(m_layer.get());
2102
2103    END_BLOCK_OBJC_EXCEPTIONS
2104}
2105
2106void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
2107{
2108    BEGIN_BLOCK_OBJC_EXCEPTIONS
2109
2110    if (color.isValid()) {
2111        setLayerBorderColor(m_layer.get(), color);
2112        [m_layer.get() setBorderWidth:borderWidth];
2113    } else {
2114        clearBorderColor(m_layer.get());
2115        [m_layer.get() setBorderWidth:0];
2116    }
2117
2118    END_BLOCK_OBJC_EXCEPTIONS
2119}
2120
2121bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
2122{
2123    if (!m_drawsContent)
2124        return false;
2125
2126    // FIXME: catch zero-size height or width here (or earlier)?
2127    return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
2128}
2129
2130void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
2131{
2132    if (useTiledLayer == m_usingTiledLayer)
2133        return;
2134
2135    CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
2136
2137    RetainPtr<CALayer> oldLayer = m_layer.get();
2138
2139    Class layerClass = useTiledLayer ? [WebTiledLayer self] : [WebLayer self];
2140    m_layer.adoptNS([[layerClass alloc] init]);
2141
2142    m_usingTiledLayer = useTiledLayer;
2143
2144    if (useTiledLayer) {
2145        WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get();
2146        [tiledLayer setTileSize:tileSize];
2147        [tiledLayer setLevelsOfDetail:1];
2148        [tiledLayer setLevelsOfDetailBias:0];
2149
2150        if (GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp)
2151            [tiledLayer setContentsGravity:@"bottomLeft"];
2152        else
2153            [tiledLayer setContentsGravity:@"topLeft"];
2154
2155#if !HAVE_MODERN_QUARTZCORE
2156        // Tiled layer has issues with flipped coordinates.
2157        setContentsOrientation(CompositingCoordinatesTopDown);
2158#endif
2159    } else {
2160#if !HAVE_MODERN_QUARTZCORE
2161        setContentsOrientation(defaultContentsOrientation());
2162#endif
2163    }
2164
2165    [m_layer.get() setLayerOwner:this];
2166    safeSetSublayers(m_layer.get(), [oldLayer.get() sublayers]);
2167
2168    [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
2169
2170    updateContentsTransform();
2171
2172    updateLayerPosition();
2173    updateLayerSize();
2174    updateAnchorPoint();
2175    updateTransform();
2176    updateChildrenTransform();
2177    updateMasksToBounds();
2178    updateContentsOpaque();
2179    updateBackfaceVisibility();
2180    updateLayerBackgroundColor();
2181
2182    updateOpacityOnLayer();
2183
2184#ifndef NDEBUG
2185    String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name;
2186    [m_layer.get() setName:name];
2187#endif
2188
2189    // move over animations
2190    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
2191    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
2192    moveOrCopyAnimationsForProperty(Move, AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
2193
2194    // need to tell new layer to draw itself
2195    setNeedsDisplay();
2196
2197    updateDebugIndicators();
2198}
2199
2200GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const
2201{
2202#if !HAVE_MODERN_QUARTZCORE
2203    // Older QuartzCore does not support -geometryFlipped, so we manually flip the root
2204    // layer geometry, and then flip the contents of each layer back so that the CTM for CG
2205    // is unflipped, allowing it to do the correct font auto-hinting.
2206    return CompositingCoordinatesBottomUp;
2207#else
2208    return CompositingCoordinatesTopDown;
2209#endif
2210}
2211
2212void GraphicsLayerCA::updateContentsTransform()
2213{
2214#if !HAVE_MODERN_QUARTZCORE
2215    if (contentsOrientation() == CompositingCoordinatesBottomUp) {
2216        CGAffineTransform contentsTransform = CGAffineTransformMakeScale(1, -1);
2217        contentsTransform = CGAffineTransformTranslate(contentsTransform, 0, -[m_layer.get() bounds].size.height);
2218        [m_layer.get() setContentsTransform:contentsTransform];
2219    }
2220#else
2221    ASSERT(contentsOrientation() == CompositingCoordinatesTopDown);
2222#endif
2223}
2224
2225void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer)
2226{
2227    // Turn off implicit animations on the inner layer.
2228    [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
2229
2230    if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
2231        CATransform3D flipper = {
2232            1.0f, 0.0f, 0.0f, 0.0f,
2233            0.0f, -1.0f, 0.0f, 0.0f,
2234            0.0f, 0.0f, 1.0f, 0.0f,
2235            0.0f, 0.0f, 0.0f, 1.0f};
2236        [contentsLayer setTransform:flipper];
2237        [contentsLayer setAnchorPoint:CGPointMake(0.0f, 1.0f)];
2238    } else
2239        [contentsLayer setAnchorPoint:CGPointZero];
2240
2241    if (showDebugBorders()) {
2242        setLayerBorderColor(contentsLayer, Color(0, 0, 128, 180));
2243        [contentsLayer setBorderWidth:1.0f];
2244    }
2245}
2246
2247CALayer *GraphicsLayerCA::findOrMakeClone(CloneID cloneID, CALayer *sourceLayer, LayerMap* clones, CloneLevel cloneLevel)
2248{
2249    if (!sourceLayer)
2250        return 0;
2251
2252    CALayer *resultLayer;
2253
2254    // Add with a dummy value to get an iterator for the insertion position, and a boolean that tells
2255    // us whether there's an item there. This technique avoids two hash lookups.
2256    RetainPtr<CALayer> dummy;
2257    pair<LayerMap::iterator, bool> addResult = clones->add(cloneID, dummy);
2258    if (!addResult.second) {
2259        // Value was not added, so it exists already.
2260        resultLayer = addResult.first->second.get();
2261    } else {
2262        resultLayer = cloneLayer(sourceLayer, cloneLevel);
2263#ifndef NDEBUG
2264        [resultLayer setName:[NSString stringWithFormat:@"Clone %d of layer %@", cloneID[0U], sourceLayer]];
2265#endif
2266        addResult.first->second = resultLayer;
2267    }
2268
2269    return resultLayer;
2270}
2271
2272void GraphicsLayerCA::ensureCloneLayers(CloneID cloneID, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel cloneLevel)
2273{
2274    structuralLayer = nil;
2275    contentsLayer = nil;
2276
2277    if (!m_layerClones)
2278        m_layerClones = new LayerMap;
2279
2280    if (!m_structuralLayerClones && m_structuralLayer)
2281        m_structuralLayerClones = new LayerMap;
2282
2283    if (!m_contentsLayerClones && m_contentsLayer)
2284        m_contentsLayerClones = new LayerMap;
2285
2286    primaryLayer = findOrMakeClone(cloneID, m_layer.get(), m_layerClones.get(), cloneLevel);
2287    structuralLayer = findOrMakeClone(cloneID, m_structuralLayer.get(), m_structuralLayerClones.get(), cloneLevel);
2288    contentsLayer = findOrMakeClone(cloneID, m_contentsLayer.get(), m_contentsLayerClones.get(), cloneLevel);
2289}
2290
2291void GraphicsLayerCA::removeCloneLayers()
2292{
2293    m_layerClones = 0;
2294    m_structuralLayerClones = 0;
2295    m_contentsLayerClones = 0;
2296}
2297
2298FloatPoint GraphicsLayerCA::positionForCloneRootLayer() const
2299{
2300    // This can get called during a sync when we've just removed the m_replicaLayer.
2301    if (!m_replicaLayer)
2302        return FloatPoint();
2303
2304    FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition();
2305    return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(),
2306                      replicaPosition.y() + m_anchorPoint.y() * m_size.height());
2307}
2308
2309void GraphicsLayerCA::propagateLayerChangeToReplicas()
2310{
2311    for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
2312        GraphicsLayerCA* currLayerCA = static_cast<GraphicsLayerCA*>(currLayer);
2313        if (!currLayerCA->hasCloneLayers())
2314            break;
2315
2316        if (currLayerCA->replicaLayer())
2317            static_cast<GraphicsLayerCA*>(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged);
2318    }
2319}
2320
2321CALayer *GraphicsLayerCA::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel)
2322{
2323    CALayer *primaryLayer;
2324    CALayer *structuralLayer;
2325    CALayer *contentsLayer;
2326    ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, cloneLevel);
2327
2328    if (m_maskLayer) {
2329        CALayer *maskClone = static_cast<GraphicsLayerCA*>(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
2330        [primaryLayer setMask:maskClone];
2331    }
2332
2333    if (m_replicatedLayer) {
2334        // We are a replica being asked for clones of our layers.
2335        CALayer *replicaRoot = replicatedLayerRoot(replicaState);
2336        if (!replicaRoot)
2337            return nil;
2338
2339        if (structuralLayer) {
2340            [structuralLayer insertSublayer:replicaRoot atIndex:0];
2341            return structuralLayer;
2342        }
2343
2344        [primaryLayer insertSublayer:replicaRoot atIndex:0];
2345        return primaryLayer;
2346    }
2347
2348    const Vector<GraphicsLayer*>& childLayers = children();
2349    NSMutableArray* clonalSublayers = nil;
2350
2351    CALayer *replicaLayer = nil;
2352    if (m_replicaLayer && m_replicaLayer != replicaRoot) {
2353        // We have nested replicas. Ask the replica layer for a clone of its contents.
2354        replicaState.setBranchType(ReplicaState::ReplicaBranch);
2355        replicaLayer = static_cast<GraphicsLayerCA*>(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel);
2356        replicaState.setBranchType(ReplicaState::ChildBranch);
2357    }
2358
2359    if (replicaLayer || structuralLayer || contentsLayer || childLayers.size() > 0) {
2360        clonalSublayers = [[NSMutableArray alloc] init];
2361
2362        if (structuralLayer) {
2363            // Replicas render behind the actual layer content.
2364            if (replicaLayer)
2365                [clonalSublayers addObject:replicaLayer];
2366
2367            // Add the primary layer next. Even if we have negative z-order children, the primary layer always comes behind.
2368            [clonalSublayers addObject:primaryLayer];
2369        } else if (contentsLayer) {
2370            // FIXME: add the contents layer in the correct order with negative z-order children.
2371            // This does not cause visible rendering issues because currently contents layers are only used
2372            // for replaced elements that don't have children.
2373            [clonalSublayers addObject:contentsLayer];
2374        }
2375
2376        replicaState.push(ReplicaState::ChildBranch);
2377
2378        size_t numChildren = childLayers.size();
2379        for (size_t i = 0; i < numChildren; ++i) {
2380            GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
2381
2382            CALayer *childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
2383            if (childLayer)
2384                [clonalSublayers addObject:childLayer];
2385        }
2386
2387        replicaState.pop();
2388
2389        [clonalSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
2390    }
2391
2392    CALayer *result;
2393    if (structuralLayer) {
2394        [structuralLayer setSublayers:clonalSublayers];
2395
2396        if (contentsLayer) {
2397            // If we have a transform layer, then the contents layer is parented in the
2398            // primary layer (which is itself a child of the transform layer).
2399            [primaryLayer setSublayers:nil];
2400            [primaryLayer addSublayer:contentsLayer];
2401        }
2402
2403        result = structuralLayer;
2404    } else {
2405        [primaryLayer setSublayers:clonalSublayers];
2406        result = primaryLayer;
2407    }
2408
2409    [clonalSublayers release];
2410    return result;
2411}
2412
2413CALayer *GraphicsLayerCA::cloneLayer(CALayer *layer, CloneLevel cloneLevel)
2414{
2415    static Class transformLayerClass = NSClassFromString(@"CATransformLayer");
2416    CALayer *newLayer = nil;
2417    if ([layer isKindOfClass:transformLayerClass])
2418        newLayer = [transformLayerClass layer];
2419    else
2420        newLayer = [CALayer layer];
2421
2422    [newLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
2423
2424    [newLayer setPosition:[layer position]];
2425    [newLayer setBounds:[layer bounds]];
2426    [newLayer setAnchorPoint:[layer anchorPoint]];
2427#if HAVE_MODERN_QUARTZCORE
2428    [newLayer setAnchorPointZ:[layer anchorPointZ]];
2429#endif
2430    [newLayer setTransform:[layer transform]];
2431    [newLayer setSublayerTransform:[layer sublayerTransform]];
2432    [newLayer setContents:[layer contents]];
2433    [newLayer setMasksToBounds:[layer masksToBounds]];
2434    [newLayer setDoubleSided:[layer isDoubleSided]];
2435    [newLayer setOpaque:[layer isOpaque]];
2436    [newLayer setBackgroundColor:[layer backgroundColor]];
2437
2438    if (cloneLevel == IntermediateCloneLevel) {
2439        [newLayer setOpacity:[layer opacity]];
2440        moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyWebkitTransform, layer, newLayer);
2441        moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyOpacity, layer, newLayer);
2442    }
2443
2444    if (showDebugBorders()) {
2445        setLayerBorderColor(newLayer, Color(255, 122, 251));
2446        [newLayer setBorderWidth:2];
2447    }
2448
2449    return newLayer;
2450}
2451
2452void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
2453{
2454    LayerMap* layerCloneMap = 0;
2455
2456    if (preserves3D()) {
2457        [m_layer.get() setOpacity:accumulatedOpacity];
2458        layerCloneMap = m_layerClones.get();
2459    } else {
2460        [primaryLayer() setOpacity:accumulatedOpacity];
2461        layerCloneMap = primaryLayerClones();
2462    }
2463
2464    if (layerCloneMap) {
2465        LayerMap::const_iterator end = layerCloneMap->end();
2466        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
2467            if (m_replicaLayer && isReplicatedRootClone(it->first))
2468                continue;
2469            CALayer *currLayer = it->second.get();
2470            [currLayer setOpacity:m_opacity];
2471        }
2472    }
2473}
2474
2475void GraphicsLayerCA::updateOpacityOnLayer()
2476{
2477#if !HAVE_MODERN_QUARTZCORE
2478    // Distribute opacity either to our own layer or to our children. We pass in the
2479    // contribution from our parent(s).
2480    distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1);
2481#else
2482    [primaryLayer() setOpacity:m_opacity];
2483
2484    if (LayerMap* layerCloneMap = primaryLayerClones()) {
2485        LayerMap::const_iterator end = layerCloneMap->end();
2486        for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
2487            if (m_replicaLayer && isReplicatedRootClone(it->first))
2488                continue;
2489
2490            CALayer *currLayer = it->second.get();
2491            [currLayer setOpacity:m_opacity];
2492        }
2493
2494    }
2495#endif
2496}
2497
2498void GraphicsLayerCA::noteSublayersChanged()
2499{
2500    noteLayerPropertyChanged(ChildrenChanged);
2501    propagateLayerChangeToReplicas();
2502}
2503
2504void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
2505{
2506    if (!m_uncommittedChanges && m_client)
2507        m_client->notifySyncRequired(this);
2508
2509    m_uncommittedChanges |= flags;
2510}
2511
2512#if ENABLE(3D_CANVAS)
2513void GraphicsLayerCA::setGraphicsContext3DNeedsDisplay()
2514{
2515    if (m_contentsLayerPurpose == ContentsLayerForGraphicsLayer3D)
2516        [m_contentsLayer.get() setNeedsDisplay];
2517}
2518#endif
2519
2520} // namespace WebCore
2521
2522#endif // USE(ACCELERATED_COMPOSITING)
2523