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