1/*
2 * Copyright (C) 2011 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#include "config.h"
27
28#if USE(ACCELERATED_COMPOSITING)
29
30#include "PlatformCALayer.h"
31
32#include "AbstractCACFLayerTreeHost.h"
33#include "Font.h"
34#include "GraphicsContext.h"
35#include "PlatformCALayerWinInternal.h"
36#include <QuartzCore/CoreAnimationCF.h>
37#include <WebKitSystemInterface/WebKitSystemInterface.h>
38#include <wtf/CurrentTime.h>
39#include <wtf/text/CString.h>
40
41using namespace WebCore;
42
43bool PlatformCALayer::isValueFunctionSupported()
44{
45    return true;
46}
47
48void PlatformCALayer::setOwner(PlatformCALayerClient* owner)
49{
50    m_owner = owner;
51}
52
53static CFStringRef toCACFLayerType(PlatformCALayer::LayerType type)
54{
55    return (type == PlatformCALayer::LayerTypeTransformLayer) ? kCACFTransformLayer : kCACFLayer;
56}
57
58static CFStringRef toCACFFilterType(PlatformCALayer::FilterType type)
59{
60    switch (type) {
61    case PlatformCALayer::Linear: return kCACFFilterLinear;
62    case PlatformCALayer::Nearest: return kCACFFilterNearest;
63    case PlatformCALayer::Trilinear: return kCACFFilterTrilinear;
64    default: return 0;
65    }
66}
67
68static AbstractCACFLayerTreeHost* layerTreeHostForLayer(const PlatformCALayer* layer)
69{
70    // We need the AbstractCACFLayerTreeHost associated with this layer, which is stored in the UserData of the CACFContext
71    void* userData = wkCACFLayerGetContextUserData(layer->platformLayer());
72    if (!userData)
73        return 0;
74
75    return static_cast<AbstractCACFLayerTreeHost*>(userData);
76}
77
78static PlatformCALayerWinInternal* intern(const PlatformCALayer* layer)
79{
80    return static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(layer->platformLayer()));
81}
82
83static PlatformCALayerWinInternal* intern(void* layer)
84{
85    return static_cast<PlatformCALayerWinInternal*>(CACFLayerGetUserData(static_cast<CACFLayerRef>(layer)));
86}
87
88PassRefPtr<PlatformCALayer> PlatformCALayer::create(LayerType layerType, PlatformCALayerClient* owner)
89{
90    return adoptRef(new PlatformCALayer(layerType, 0, owner));
91}
92
93PassRefPtr<PlatformCALayer> PlatformCALayer::create(void* platformLayer, PlatformCALayerClient* owner)
94{
95    return adoptRef(new PlatformCALayer(LayerTypeCustom, static_cast<PlatformLayer*>(platformLayer), owner));
96}
97
98static void displayCallback(CACFLayerRef caLayer, CGContextRef context)
99{
100    ASSERT_ARG(caLayer, CACFLayerGetUserData(caLayer));
101    intern(caLayer)->displayCallback(caLayer, context);
102}
103
104static void layoutSublayersProc(CACFLayerRef caLayer)
105{
106    PlatformCALayer* layer = PlatformCALayer::platformCALayer(caLayer);
107    if (layer && layer->owner())
108        layer->owner()->platformCALayerLayoutSublayersOfLayer(layer);
109}
110
111PlatformCALayer::PlatformCALayer(LayerType layerType, PlatformLayer* layer, PlatformCALayerClient* owner)
112    : m_owner(owner)
113{
114    if (layer) {
115        m_layerType = LayerTypeCustom;
116        m_layer = layer;
117    } else {
118        m_layerType = layerType;
119        ASSERT((layerType != LayerTypeTiledBackingLayer) && (layerType != LayerTypePageTiledBackingLayer));
120        m_layer = adoptCF(CACFLayerCreate(toCACFLayerType(layerType)));
121
122        // Create the PlatformCALayerWinInternal object and point to it in the userdata.
123        PlatformCALayerWinInternal* intern = new PlatformCALayerWinInternal(this);
124        CACFLayerSetUserData(m_layer.get(), intern);
125
126        // Set the display callback
127        CACFLayerSetDisplayCallback(m_layer.get(), displayCallback);
128        CACFLayerSetLayoutCallback(m_layer.get(), layoutSublayersProc);
129    }
130}
131
132PlatformCALayer::~PlatformCALayer()
133{
134    // Toss all the kids
135    removeAllSublayers();
136
137    // Get rid of the user data
138    PlatformCALayerWinInternal* layerIntern = intern(this);
139    CACFLayerSetUserData(m_layer.get(), 0);
140
141    // Clear the owner, which also clears it in the delegate to prevent attempts
142    // to use the GraphicsLayerCA after it has been destroyed.
143    setOwner(0);
144
145    CACFLayerRemoveFromSuperlayer(m_layer.get());
146
147    delete layerIntern;
148}
149
150PlatformCALayer* PlatformCALayer::platformCALayer(void* platformLayer)
151{
152    if (!platformLayer)
153        return 0;
154
155    PlatformCALayerWinInternal* layerIntern = intern(platformLayer);
156    return layerIntern ? layerIntern->owner() : 0;
157}
158
159PassRefPtr<PlatformCALayer> PlatformCALayer::clone(PlatformCALayerClient* owner) const
160{
161    PlatformCALayer::LayerType type = (layerType() == PlatformCALayer::LayerTypeTransformLayer) ?
162        PlatformCALayer::LayerTypeTransformLayer : PlatformCALayer::LayerTypeLayer;
163    RefPtr<PlatformCALayer> newLayer = PlatformCALayer::create(type, owner);
164
165    newLayer->setPosition(position());
166    newLayer->setBounds(bounds());
167    newLayer->setAnchorPoint(anchorPoint());
168    newLayer->setTransform(transform());
169    newLayer->setSublayerTransform(sublayerTransform());
170    newLayer->setContents(contents());
171    newLayer->setMasksToBounds(masksToBounds());
172    newLayer->setDoubleSided(isDoubleSided());
173    newLayer->setOpaque(isOpaque());
174    newLayer->setBackgroundColor(backgroundColor());
175    newLayer->setContentsScale(contentsScale());
176#if ENABLE(CSS_FILTERS)
177    newLayer->copyFiltersFrom(this);
178#endif
179
180    return newLayer;
181}
182
183PlatformLayer* PlatformCALayer::platformLayer() const
184{
185    return m_layer.get();
186}
187
188PlatformCALayer* PlatformCALayer::rootLayer() const
189{
190    AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this);
191    return host ? host->rootLayer() : 0;
192}
193
194void PlatformCALayer::animationStarted(CFTimeInterval beginTime)
195{
196    // Update start time for any animation not yet started
197    CFTimeInterval cacfBeginTime = currentTimeToMediaTime(beginTime);
198
199    HashMap<String, RefPtr<PlatformCAAnimation> >::const_iterator end = m_animations.end();
200    for (HashMap<String, RefPtr<PlatformCAAnimation> >::const_iterator it = m_animations.begin(); it != end; ++it)
201        it->value->setActualStartTimeIfNeeded(cacfBeginTime);
202
203    if (m_owner)
204        m_owner->platformCALayerAnimationStarted(beginTime);
205}
206
207static void resubmitAllAnimations(PlatformCALayer* layer)
208{
209    HashMap<String, RefPtr<PlatformCAAnimation> >::const_iterator end = layer->animations().end();
210    for (HashMap<String, RefPtr<PlatformCAAnimation> >::const_iterator it = layer->animations().begin(); it != end; ++it)
211        CACFLayerAddAnimation(layer->platformLayer(), it->key.createCFString().get(), it->value->platformAnimation());
212}
213
214void PlatformCALayer::ensureAnimationsSubmitted()
215{
216    resubmitAllAnimations(this);
217
218    PlatformCALayerList children;
219    intern(this)->getSublayers(children);
220    for (size_t i = 0; i < children.size(); ++i)
221        children[i]->ensureAnimationsSubmitted();
222}
223
224void PlatformCALayer::setNeedsDisplay(const FloatRect* dirtyRect)
225{
226    intern(this)->setNeedsDisplay(dirtyRect);
227}
228
229void PlatformCALayer::setNeedsCommit()
230{
231    AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this);
232    if (host)
233        host->layerTreeDidChange();
234}
235
236void PlatformCALayer::setContentsChanged()
237{
238    // FIXME: There is no equivalent of setContentsChanged in CACF. For now I will
239    // set contents to 0 and then back to its original value to see if that
240    // kicks CACF into redisplaying.
241    RetainPtr<CFTypeRef> contents = CACFLayerGetContents(m_layer.get());
242    CACFLayerSetContents(m_layer.get(), 0);
243    CACFLayerSetContents(m_layer.get(), contents.get());
244    setNeedsCommit();
245}
246
247void PlatformCALayer::setNeedsLayout()
248{
249    if (!m_owner || !m_owner->platformCALayerRespondsToLayoutChanges())
250        return;
251
252    CACFLayerSetNeedsLayout(m_layer.get());
253    setNeedsCommit();
254}
255
256PlatformCALayer* PlatformCALayer::superlayer() const
257{
258    return platformCALayer(CACFLayerGetSuperlayer(m_layer.get()));
259}
260
261void PlatformCALayer::removeFromSuperlayer()
262{
263    CACFLayerRemoveFromSuperlayer(m_layer.get());
264    setNeedsCommit();
265}
266
267void PlatformCALayer::setSublayers(const PlatformCALayerList& list)
268{
269    intern(this)->setSublayers(list);
270}
271
272void PlatformCALayer::removeAllSublayers()
273{
274    intern(this)->removeAllSublayers();
275}
276
277void PlatformCALayer::appendSublayer(PlatformCALayer* layer)
278{
279    // This must be in terms of insertSublayer instead of a direct call so PlatformCALayerInternal can override.
280    insertSublayer(layer, sublayerCount());
281}
282
283void PlatformCALayer::insertSublayer(PlatformCALayer* layer, size_t index)
284{
285    intern(this)->insertSublayer(layer, index);
286}
287
288void PlatformCALayer::replaceSublayer(PlatformCALayer* reference, PlatformCALayer* newLayer)
289{
290    // This must not use direct calls to allow PlatformCALayerInternal to override.
291    ASSERT_ARG(reference, reference);
292    ASSERT_ARG(reference, reference->superlayer() == this);
293
294    if (reference == newLayer)
295        return;
296
297    int referenceIndex = intern(this)->indexOfSublayer(reference);
298    ASSERT(referenceIndex != -1);
299    if (referenceIndex == -1)
300        return;
301
302    reference->removeFromSuperlayer();
303
304    if (newLayer) {
305        newLayer->removeFromSuperlayer();
306        insertSublayer(newLayer, referenceIndex);
307    }
308}
309
310size_t PlatformCALayer::sublayerCount() const
311{
312    return intern(this)->sublayerCount();
313}
314
315void PlatformCALayer::adoptSublayers(PlatformCALayer* source)
316{
317    PlatformCALayerList sublayers;
318    intern(source)->getSublayers(sublayers);
319
320    // Use setSublayers() because it properly nulls out the superlayer pointers.
321    setSublayers(sublayers);
322}
323
324void PlatformCALayer::addAnimationForKey(const String& key, PlatformCAAnimation* animation)
325{
326    // Add it to the animation list
327    m_animations.add(key, animation);
328
329    CACFLayerAddAnimation(m_layer.get(), key.createCFString().get(), animation->platformAnimation());
330    setNeedsCommit();
331
332    // Tell the host about it so we can fire the start animation event
333    AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this);
334    if (host)
335        host->addPendingAnimatedLayer(this);
336}
337
338void PlatformCALayer::removeAnimationForKey(const String& key)
339{
340    // Remove it from the animation list
341    m_animations.remove(key);
342
343    CACFLayerRemoveAnimation(m_layer.get(), key.createCFString().get());
344
345    // We don't "remove" a layer from AbstractCACFLayerTreeHost when it loses an animation.
346    // There may be other active animations on the layer and if an animation
347    // callback is fired on a layer without any animations no harm is done.
348
349    setNeedsCommit();
350}
351
352PassRefPtr<PlatformCAAnimation> PlatformCALayer::animationForKey(const String& key)
353{
354    HashMap<String, RefPtr<PlatformCAAnimation> >::iterator it = m_animations.find(key);
355    if (it == m_animations.end())
356        return 0;
357
358    return it->value;
359}
360
361PlatformCALayer* PlatformCALayer::mask() const
362{
363    return platformCALayer(CACFLayerGetMask(m_layer.get()));
364}
365
366void PlatformCALayer::setMask(PlatformCALayer* layer)
367{
368    CACFLayerSetMask(m_layer.get(), layer ? layer->platformLayer() : 0);
369    setNeedsCommit();
370}
371
372bool PlatformCALayer::isOpaque() const
373{
374    return CACFLayerIsOpaque(m_layer.get());
375}
376
377void PlatformCALayer::setOpaque(bool value)
378{
379    CACFLayerSetOpaque(m_layer.get(), value);
380    setNeedsCommit();
381}
382
383FloatRect PlatformCALayer::bounds() const
384{
385    return CACFLayerGetBounds(m_layer.get());
386}
387
388void PlatformCALayer::setBounds(const FloatRect& value)
389{
390    intern(this)->setBounds(value);
391    setNeedsLayout();
392}
393
394FloatPoint3D PlatformCALayer::position() const
395{
396    CGPoint point = CACFLayerGetPosition(m_layer.get());
397    return FloatPoint3D(point.x, point.y, CACFLayerGetZPosition(m_layer.get()));
398}
399
400void PlatformCALayer::setPosition(const FloatPoint3D& value)
401{
402    CACFLayerSetPosition(m_layer.get(), CGPointMake(value.x(), value.y()));
403    CACFLayerSetZPosition(m_layer.get(), value.z());
404    setNeedsCommit();
405}
406
407FloatPoint3D PlatformCALayer::anchorPoint() const
408{
409    CGPoint point = CACFLayerGetAnchorPoint(m_layer.get());
410    float z = CACFLayerGetAnchorPointZ(m_layer.get());
411    return FloatPoint3D(point.x, point.y, z);
412}
413
414void PlatformCALayer::setAnchorPoint(const FloatPoint3D& value)
415{
416    CACFLayerSetAnchorPoint(m_layer.get(), CGPointMake(value.x(), value.y()));
417    CACFLayerSetAnchorPointZ(m_layer.get(), value.z());
418    setNeedsCommit();
419}
420
421TransformationMatrix PlatformCALayer::transform() const
422{
423    return CACFLayerGetTransform(m_layer.get());
424}
425
426void PlatformCALayer::setTransform(const TransformationMatrix& value)
427{
428    CACFLayerSetTransform(m_layer.get(), value);
429    setNeedsCommit();
430}
431
432TransformationMatrix PlatformCALayer::sublayerTransform() const
433{
434    return CACFLayerGetSublayerTransform(m_layer.get());
435}
436
437void PlatformCALayer::setSublayerTransform(const TransformationMatrix& value)
438{
439    CACFLayerSetSublayerTransform(m_layer.get(), value);
440    setNeedsCommit();
441}
442
443TransformationMatrix PlatformCALayer::contentsTransform() const
444{
445    // ContentsTransform is not used
446    return TransformationMatrix();
447}
448
449void PlatformCALayer::setContentsTransform(const TransformationMatrix&)
450{
451    // ContentsTransform is not used
452}
453
454bool PlatformCALayer::isHidden() const
455{
456    return CACFLayerIsHidden(m_layer.get());
457}
458
459void PlatformCALayer::setHidden(bool value)
460{
461    CACFLayerSetHidden(m_layer.get(), value);
462    setNeedsCommit();
463}
464
465bool PlatformCALayer::isGeometryFlipped() const
466{
467    return CACFLayerIsGeometryFlipped(m_layer.get());
468}
469
470void PlatformCALayer::setGeometryFlipped(bool value)
471{
472    CACFLayerSetGeometryFlipped(m_layer.get(), value);
473    setNeedsCommit();
474}
475
476bool PlatformCALayer::isDoubleSided() const
477{
478    return CACFLayerIsDoubleSided(m_layer.get());
479}
480
481void PlatformCALayer::setDoubleSided(bool value)
482{
483    CACFLayerSetDoubleSided(m_layer.get(), value);
484    setNeedsCommit();
485}
486
487bool PlatformCALayer::masksToBounds() const
488{
489    return CACFLayerGetMasksToBounds(m_layer.get());
490}
491
492void PlatformCALayer::setMasksToBounds(bool value)
493{
494    CACFLayerSetMasksToBounds(m_layer.get(), value);
495    setNeedsCommit();
496}
497
498bool PlatformCALayer::acceleratesDrawing() const
499{
500    return false;
501}
502
503void PlatformCALayer::setAcceleratesDrawing(bool)
504{
505}
506
507CFTypeRef PlatformCALayer::contents() const
508{
509    return CACFLayerGetContents(m_layer.get());
510}
511
512void PlatformCALayer::setContents(CFTypeRef value)
513{
514    CACFLayerSetContents(m_layer.get(), value);
515    setNeedsCommit();
516}
517
518FloatRect PlatformCALayer::contentsRect() const
519{
520    return CACFLayerGetContentsRect(m_layer.get());
521}
522
523void PlatformCALayer::setContentsRect(const FloatRect& value)
524{
525    CACFLayerSetContentsRect(m_layer.get(), value);
526    setNeedsCommit();
527}
528
529void PlatformCALayer::setMinificationFilter(FilterType value)
530{
531    CACFLayerSetMinificationFilter(m_layer.get(), toCACFFilterType(value));
532}
533
534void PlatformCALayer::setMagnificationFilter(FilterType value)
535{
536    CACFLayerSetMagnificationFilter(m_layer.get(), toCACFFilterType(value));
537    setNeedsCommit();
538}
539
540Color PlatformCALayer::backgroundColor() const
541{
542    return CACFLayerGetBackgroundColor(m_layer.get());
543}
544
545void PlatformCALayer::setBackgroundColor(const Color& value)
546{
547    CGFloat components[4];
548    value.getRGBA(components[0], components[1], components[2], components[3]);
549
550    RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
551    RetainPtr<CGColorRef> color = adoptCF(CGColorCreate(colorSpace.get(), components));
552
553    CACFLayerSetBackgroundColor(m_layer.get(), color.get());
554    setNeedsCommit();
555}
556
557float PlatformCALayer::borderWidth() const
558{
559    return CACFLayerGetBorderWidth(m_layer.get());
560}
561
562void PlatformCALayer::setBorderWidth(float value)
563{
564    CACFLayerSetBorderWidth(m_layer.get(), value);
565    setNeedsCommit();
566}
567
568Color PlatformCALayer::borderColor() const
569{
570    return CACFLayerGetBorderColor(m_layer.get());
571}
572
573void PlatformCALayer::setBorderColor(const Color& value)
574{
575    CGFloat components[4];
576    value.getRGBA(components[0], components[1], components[2], components[3]);
577
578    RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
579    RetainPtr<CGColorRef> color = adoptCF(CGColorCreate(colorSpace.get(), components));
580
581    CACFLayerSetBorderColor(m_layer.get(), color.get());
582    setNeedsCommit();
583}
584
585float PlatformCALayer::opacity() const
586{
587    return CACFLayerGetOpacity(m_layer.get());
588}
589
590void PlatformCALayer::setOpacity(float value)
591{
592    CACFLayerSetOpacity(m_layer.get(), value);
593    setNeedsCommit();
594}
595
596#if ENABLE(CSS_FILTERS)
597
598void PlatformCALayer::setFilters(const FilterOperations&)
599{
600}
601
602void PlatformCALayer::copyFiltersFrom(const PlatformCALayer*)
603{
604}
605
606bool PlatformCALayer::filtersCanBeComposited(const FilterOperations&)
607{
608    return false;
609}
610
611#endif // ENABLE(CSS_FILTERS)
612
613String PlatformCALayer::name() const
614{
615    return CACFLayerGetName(m_layer.get());
616}
617
618void PlatformCALayer::setName(const String& value)
619{
620    CACFLayerSetName(m_layer.get(), value.createCFString().get());
621    setNeedsCommit();
622}
623
624FloatRect PlatformCALayer::frame() const
625{
626    return CACFLayerGetFrame(m_layer.get());
627}
628
629void PlatformCALayer::setFrame(const FloatRect& value)
630{
631    intern(this)->setFrame(value);
632    setNeedsLayout();
633}
634
635float PlatformCALayer::speed() const
636{
637    return CACFLayerGetSpeed(m_layer.get());
638}
639
640void PlatformCALayer::setSpeed(float value)
641{
642    CACFLayerSetSpeed(m_layer.get(), value);
643    setNeedsCommit();
644}
645
646CFTimeInterval PlatformCALayer::timeOffset() const
647{
648    return CACFLayerGetTimeOffset(m_layer.get());
649}
650
651void PlatformCALayer::setTimeOffset(CFTimeInterval value)
652{
653    CACFLayerSetTimeOffset(m_layer.get(), value);
654    setNeedsCommit();
655}
656
657float PlatformCALayer::contentsScale() const
658{
659    return 1;
660}
661
662void PlatformCALayer::setContentsScale(float)
663{
664}
665
666TiledBacking* PlatformCALayer::tiledBacking()
667{
668    return 0;
669}
670
671#ifndef NDEBUG
672static void printIndent(int indent)
673{
674    for ( ; indent > 0; --indent)
675        fprintf(stderr, "  ");
676}
677
678static void printTransform(const CATransform3D& transform)
679{
680    fprintf(stderr, "[%g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g]",
681                    transform.m11, transform.m12, transform.m13, transform.m14,
682                    transform.m21, transform.m22, transform.m23, transform.m24,
683                    transform.m31, transform.m32, transform.m33, transform.m34,
684                    transform.m41, transform.m42, transform.m43, transform.m44);
685}
686
687static void printLayer(const PlatformCALayer* layer, int indent)
688{
689    FloatPoint3D layerPosition = layer->position();
690    FloatPoint3D layerAnchorPoint = layer->anchorPoint();
691    FloatRect layerBounds = layer->bounds();
692    printIndent(indent);
693
694    char* layerTypeName = 0;
695    switch (layer->layerType()) {
696    case PlatformCALayer::LayerTypeLayer: layerTypeName = "layer"; break;
697    case PlatformCALayer::LayerTypeWebLayer: layerTypeName = "web-layer"; break;
698    case PlatformCALayer::LayerTypeTransformLayer: layerTypeName = "transform-layer"; break;
699    case PlatformCALayer::LayerTypeWebTiledLayer: layerTypeName = "web-tiled-layer"; break;
700    case PlatformCALayer::LayerTypeRootLayer: layerTypeName = "root-layer"; break;
701    case PlatformCALayer::LayerTypeCustom: layerTypeName = "custom-layer"; break;
702    }
703
704    fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g] superlayer=%p\n",
705        layerTypeName,
706        layerPosition.x(), layerPosition.y(), layerPosition.z(),
707        layerBounds.x(), layerBounds.y(), layerBounds.width(), layerBounds.height(),
708        layerAnchorPoint.x(), layerAnchorPoint.y(), layerAnchorPoint.z(), layer->superlayer());
709
710    // Print name if needed
711    String layerName = layer->name();
712    if (!layerName.isEmpty()) {
713        printIndent(indent + 1);
714        fprintf(stderr, "(name %s)\n", layerName.utf8().data());
715    }
716
717    // Print masksToBounds if needed
718    bool layerMasksToBounds = layer->masksToBounds();
719    if (layerMasksToBounds) {
720        printIndent(indent + 1);
721        fprintf(stderr, "(masksToBounds true)\n");
722    }
723
724    // Print opacity if needed
725    float layerOpacity = layer->opacity();
726    if (layerOpacity != 1) {
727        printIndent(indent + 1);
728        fprintf(stderr, "(opacity %hf)\n", layerOpacity);
729    }
730
731    // Print sublayerTransform if needed
732    TransformationMatrix layerTransform = layer->sublayerTransform();
733    if (!layerTransform.isIdentity()) {
734        printIndent(indent + 1);
735        fprintf(stderr, "(sublayerTransform ");
736        printTransform(layerTransform);
737        fprintf(stderr, ")\n");
738    }
739
740    // Print transform if needed
741    layerTransform = layer->transform();
742    if (!layerTransform.isIdentity()) {
743        printIndent(indent + 1);
744        fprintf(stderr, "(transform ");
745        printTransform(layerTransform);
746        fprintf(stderr, ")\n");
747    }
748
749    // Print contents if needed
750    CFTypeRef layerContents = layer->contents();
751    if (layerContents) {
752        if (CFGetTypeID(layerContents) == CGImageGetTypeID()) {
753            CGImageRef imageContents = static_cast<CGImageRef>(const_cast<void*>(layerContents));
754            printIndent(indent + 1);
755            fprintf(stderr, "(contents (image [%d %d]))\n",
756                CGImageGetWidth(imageContents), CGImageGetHeight(imageContents));
757        }
758    }
759
760    // Print sublayers if needed
761    int n = layer->sublayerCount();
762    if (n > 0) {
763        printIndent(indent + 1);
764        fprintf(stderr, "(sublayers\n");
765
766        PlatformCALayerList sublayers;
767        intern(layer)->getSublayers(sublayers);
768        ASSERT(n == sublayers.size());
769        for (int i = 0; i < n; ++i)
770            printLayer(sublayers[i].get(), indent + 2);
771
772        printIndent(indent + 1);
773        fprintf(stderr, ")\n");
774    }
775
776    printIndent(indent);
777    fprintf(stderr, ")\n");
778}
779
780void PlatformCALayer::printTree() const
781{
782    // Print heading info
783    CGRect rootBounds = bounds();
784    fprintf(stderr, "\n\n** Render tree at time %g (bounds %g, %g %gx%g) **\n\n",
785        currentTime(), rootBounds.origin.x, rootBounds.origin.y, rootBounds.size.width, rootBounds.size.height);
786
787    // Print layer tree from the root
788    printLayer(this, 0);
789}
790#endif // #ifndef NDEBUG
791
792#endif // USE(ACCELERATED_COMPOSITING)
793