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 #include "config.h"
27
28 #if USE(ACCELERATED_COMPOSITING)
29
30 #include "WKCACFLayer.h"
31
32 #include "CString.h"
33 #include "WKCACFContextFlusher.h"
34 #include "WKCACFLayerRenderer.h"
35
36 #include <stdio.h>
37 #include <QuartzCore/CACFContext.h>
38 #include <QuartzCore/CARender.h>
39 #include <QuartzCoreInterface/QuartzCoreInterface.h>
40
41 #ifndef NDEBUG
42 #include <wtf/CurrentTime.h>
43 #endif
44
45 #ifdef DEBUG_ALL
46 #pragma comment(lib, "QuartzCore_debug")
47 #pragma comment(lib, "QuartzCoreInterface_debug")
48 #else
49 #pragma comment(lib, "QuartzCore")
50 #pragma comment(lib, "QuartzCoreInterface")
51 #endif
52
53 namespace WebCore {
54
55 using namespace std;
56
displayInContext(CACFLayerRef layer,CGContextRef context)57 static void displayInContext(CACFLayerRef layer, CGContextRef context)
58 {
59 ASSERT_ARG(layer, WKCACFLayer::layer(layer));
60 WKCACFLayer::layer(layer)->display(context);
61 }
62
63 #define STATIC_CACF_STRING(name) \
64 static CFStringRef name() \
65 { \
66 static CFStringRef name = wkqcCFStringRef(wkqc##name); \
67 return name; \
68 }
69
70 STATIC_CACF_STRING(kCACFLayer)
STATIC_CACF_STRING(kCACFTransformLayer)71 STATIC_CACF_STRING(kCACFTransformLayer)
72 STATIC_CACF_STRING(kCACFGravityCenter)
73 STATIC_CACF_STRING(kCACFGravityTop)
74 STATIC_CACF_STRING(kCACFGravityBottom)
75 STATIC_CACF_STRING(kCACFGravityLeft)
76 STATIC_CACF_STRING(kCACFGravityRight)
77 STATIC_CACF_STRING(kCACFGravityTopLeft)
78 STATIC_CACF_STRING(kCACFGravityTopRight)
79 STATIC_CACF_STRING(kCACFGravityBottomLeft)
80 STATIC_CACF_STRING(kCACFGravityBottomRight)
81 STATIC_CACF_STRING(kCACFGravityResize)
82 STATIC_CACF_STRING(kCACFGravityResizeAspect)
83 STATIC_CACF_STRING(kCACFGravityResizeAspectFill)
84 STATIC_CACF_STRING(kCACFFilterLinear)
85 STATIC_CACF_STRING(kCACFFilterNearest)
86 STATIC_CACF_STRING(kCACFFilterTrilinear)
87 STATIC_CACF_STRING(kCACFFilterLanczos)
88
89 static CFStringRef toCACFLayerType(WKCACFLayer::LayerType type)
90 {
91 switch (type) {
92 case WKCACFLayer::Layer: return kCACFLayer();
93 case WKCACFLayer::TransformLayer: return kCACFTransformLayer();
94 default: return 0;
95 }
96 }
97
toCACFContentsGravityType(WKCACFLayer::ContentsGravityType type)98 static CFStringRef toCACFContentsGravityType(WKCACFLayer::ContentsGravityType type)
99 {
100 switch (type) {
101 case WKCACFLayer::Center: return kCACFGravityCenter();
102 case WKCACFLayer::Top: return kCACFGravityTop();
103 case WKCACFLayer::Bottom: return kCACFGravityBottom();
104 case WKCACFLayer::Left: return kCACFGravityLeft();
105 case WKCACFLayer::Right: return kCACFGravityRight();
106 case WKCACFLayer::TopLeft: return kCACFGravityTopLeft();
107 case WKCACFLayer::TopRight: return kCACFGravityTopRight();
108 case WKCACFLayer::BottomLeft: return kCACFGravityBottomLeft();
109 case WKCACFLayer::BottomRight: return kCACFGravityBottomRight();
110 case WKCACFLayer::Resize: return kCACFGravityResize();
111 case WKCACFLayer::ResizeAspect: return kCACFGravityResizeAspect();
112 case WKCACFLayer::ResizeAspectFill: return kCACFGravityResizeAspectFill();
113 default: return 0;
114 }
115 }
116
fromCACFContentsGravityType(CFStringRef string)117 static WKCACFLayer::ContentsGravityType fromCACFContentsGravityType(CFStringRef string)
118 {
119 if (CFEqual(string, kCACFGravityTop()))
120 return WKCACFLayer::Top;
121
122 if (CFEqual(string, kCACFGravityBottom()))
123 return WKCACFLayer::Bottom;
124
125 if (CFEqual(string, kCACFGravityLeft()))
126 return WKCACFLayer::Left;
127
128 if (CFEqual(string, kCACFGravityRight()))
129 return WKCACFLayer::Right;
130
131 if (CFEqual(string, kCACFGravityTopLeft()))
132 return WKCACFLayer::TopLeft;
133
134 if (CFEqual(string, kCACFGravityTopRight()))
135 return WKCACFLayer::TopRight;
136
137 if (CFEqual(string, kCACFGravityBottomLeft()))
138 return WKCACFLayer::BottomLeft;
139
140 if (CFEqual(string, kCACFGravityBottomRight()))
141 return WKCACFLayer::BottomRight;
142
143 if (CFEqual(string, kCACFGravityResize()))
144 return WKCACFLayer::Resize;
145
146 if (CFEqual(string, kCACFGravityResizeAspect()))
147 return WKCACFLayer::ResizeAspect;
148
149 if (CFEqual(string, kCACFGravityResizeAspectFill()))
150 return WKCACFLayer::ResizeAspectFill;
151
152 return WKCACFLayer::Center;
153 }
154
toCACFFilterType(WKCACFLayer::FilterType type)155 static CFStringRef toCACFFilterType(WKCACFLayer::FilterType type)
156 {
157 switch (type) {
158 case WKCACFLayer::Linear: return kCACFFilterLinear();
159 case WKCACFLayer::Nearest: return kCACFFilterNearest();
160 case WKCACFLayer::Trilinear: return kCACFFilterTrilinear();
161 case WKCACFLayer::Lanczos: return kCACFFilterLanczos();
162 default: return 0;
163 }
164 }
165
fromCACFFilterType(CFStringRef string)166 static WKCACFLayer::FilterType fromCACFFilterType(CFStringRef string)
167 {
168 if (CFEqual(string, kCACFFilterNearest()))
169 return WKCACFLayer::Nearest;
170
171 if (CFEqual(string, kCACFFilterTrilinear()))
172 return WKCACFLayer::Trilinear;
173
174 if (CFEqual(string, kCACFFilterLanczos()))
175 return WKCACFLayer::Lanczos;
176
177 return WKCACFLayer::Linear;
178 }
179
create(LayerType type,GraphicsLayerCACF * owner)180 PassRefPtr<WKCACFLayer> WKCACFLayer::create(LayerType type, GraphicsLayerCACF* owner)
181 {
182 if (!WKCACFLayerRenderer::acceleratedCompositingAvailable())
183 return 0;
184 return adoptRef(new WKCACFLayer(type, owner));
185 }
186
187 // FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually
188 // get destroyed in debug builds. A static counter could accomplish this pretty easily.
189
WKCACFLayer(LayerType type,GraphicsLayerCACF * owner)190 WKCACFLayer::WKCACFLayer(LayerType type, GraphicsLayerCACF* owner)
191 : m_layer(AdoptCF, CACFLayerCreate(toCACFLayerType(type)))
192 , m_needsDisplayOnBoundsChange(false)
193 , m_owner(owner)
194 {
195 CACFLayerSetUserData(layer(), this);
196 CACFLayerSetDisplayCallback(layer(), displayInContext);
197 }
198
~WKCACFLayer()199 WKCACFLayer::~WKCACFLayer()
200 {
201 // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer.
202 ASSERT(!superlayer());
203
204 CACFLayerSetUserData(layer(), 0);
205 CACFLayerSetDisplayCallback(layer(), 0);
206 }
207
display(PlatformGraphicsContext * context)208 void WKCACFLayer::display(PlatformGraphicsContext* context)
209 {
210 if (!m_owner)
211 return;
212
213 CGContextSaveGState(context);
214
215 CGRect layerBounds = bounds();
216 if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
217 CGContextScaleCTM(context, 1, -1);
218 CGContextTranslateCTM(context, 0, -layerBounds.size.height);
219 }
220
221 if (m_owner->client()) {
222 GraphicsContext graphicsContext(context);
223
224 // It's important to get the clip from the context, because it may be significantly
225 // smaller than the layer bounds (e.g. tiled layers)
226 CGRect clipBounds = CGContextGetClipBoundingBox(context);
227 IntRect clip(enclosingIntRect(clipBounds));
228 m_owner->paintGraphicsLayerContents(graphicsContext, clip);
229 }
230 #ifndef NDEBUG
231 else {
232 ASSERT_NOT_REACHED();
233
234 // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
235 // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
236 CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
237 CGContextFillRect(context, layerBounds);
238 }
239 #endif
240
241 if (m_owner->showRepaintCounter()) {
242 char text[16]; // that's a lot of repaints
243 _snprintf(text, sizeof(text), "%d", m_owner->incrementRepaintCount());
244
245 CGContextSaveGState(context);
246 CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
247
248 CGRect aBounds = layerBounds;
249
250 aBounds.size.width = 10 + 12 * strlen(text);
251 aBounds.size.height = 25;
252 CGContextFillRect(context, aBounds);
253
254 CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f);
255
256 CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
257 CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman);
258 CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text));
259
260 CGContextRestoreGState(context);
261 }
262
263 CGContextRestoreGState(context);
264 }
265
becomeRootLayerForContext(CACFContextRef context)266 void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context)
267 {
268 CACFContextSetLayer(context, layer());
269 setNeedsCommit();
270 }
271
setNeedsCommit()272 void WKCACFLayer::setNeedsCommit()
273 {
274 CACFContextRef context = CACFLayerGetContext(rootLayer()->layer());
275
276 // The context might now be set yet. This happens if a property gets set
277 // before placing the layer in the tree. In this case we don't need to
278 // worry about remembering the context because we will when the layer is
279 // added to the tree.
280 if (context)
281 WKCACFContextFlusher::shared().addContext(context);
282
283 // Call notifySyncRequired(), which in this implementation plumbs through to
284 // call setRootLayerNeedsDisplay() on the WebView, which causes the CACFRenderer
285 // to render a frame.
286 if (m_owner)
287 m_owner->notifySyncRequired();
288 }
289
isTransformLayer() const290 bool WKCACFLayer::isTransformLayer() const
291 {
292 return CACFLayerGetClass(layer()) == kCACFTransformLayer();
293 }
294
addSublayer(PassRefPtr<WKCACFLayer> sublayer)295 void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer)
296 {
297 insertSublayer(sublayer, numSublayers());
298 }
299
insertSublayer(PassRefPtr<WKCACFLayer> sublayer,size_t index)300 void WKCACFLayer::insertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index)
301 {
302 index = min(index, numSublayers());
303 CACFLayerInsertSublayer(layer(), sublayer->layer(), index);
304 setNeedsCommit();
305 }
306
insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer,const WKCACFLayer * reference)307 void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
308 {
309 if (!reference) {
310 insertSublayer(sublayer, 0);
311 return;
312 }
313
314 int referenceIndex = indexOfSublayer(reference);
315 if (referenceIndex == -1) {
316 addSublayer(sublayer);
317 return;
318 }
319
320 insertSublayer(sublayer, referenceIndex + 1);
321 }
322
insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer,const WKCACFLayer * reference)323 void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
324 {
325 if (!reference) {
326 insertSublayer(sublayer, 0);
327 return;
328 }
329
330 int referenceIndex = indexOfSublayer(reference);
331 if (referenceIndex == -1) {
332 addSublayer(sublayer);
333 return;
334 }
335
336 insertSublayer(sublayer, referenceIndex);
337 }
338
replaceSublayer(WKCACFLayer * reference,PassRefPtr<WKCACFLayer> newLayer)339 void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer> newLayer)
340 {
341 ASSERT_ARG(reference, reference);
342 ASSERT_ARG(reference, reference->superlayer() == this);
343
344 if (reference == newLayer)
345 return;
346
347 if (!newLayer) {
348 removeSublayer(reference);
349 return;
350 }
351
352 newLayer->removeFromSuperlayer();
353
354 int referenceIndex = indexOfSublayer(reference);
355 ASSERT(referenceIndex != -1);
356 if (referenceIndex == -1)
357 return;
358
359 // FIXME: Can we make this more efficient? The current CACF API doesn't seem to give us a way to do so.
360 reference->removeFromSuperlayer();
361 insertSublayer(newLayer, referenceIndex);
362 }
363
removeFromSuperlayer()364 void WKCACFLayer::removeFromSuperlayer()
365 {
366 WKCACFLayer* superlayer = this->superlayer();
367 if (!superlayer)
368 return;
369
370 superlayer->removeSublayer(this);
371 CACFLayerRemoveFromSuperlayer(layer());
372 superlayer->setNeedsCommit();
373 }
374
removeSublayer(const WKCACFLayer * sublayer)375 void WKCACFLayer::removeSublayer(const WKCACFLayer* sublayer)
376 {
377 int foundIndex = indexOfSublayer(sublayer);
378 if (foundIndex == -1)
379 return;
380
381 CACFLayerRemoveFromSuperlayer(sublayer->layer());
382 setNeedsCommit();
383 }
384
sublayerAtIndex(int index) const385 const WKCACFLayer* WKCACFLayer::sublayerAtIndex(int index) const
386 {
387 CFArrayRef sublayers = CACFLayerGetSublayers(layer());
388 if (index < 0 || CFArrayGetCount(sublayers) <= index)
389 return 0;
390
391 return layer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))));
392 }
393
indexOfSublayer(const WKCACFLayer * reference)394 int WKCACFLayer::indexOfSublayer(const WKCACFLayer* reference)
395 {
396 CACFLayerRef ref = reference->layer();
397 if (!ref)
398 return -1;
399
400 CFArrayRef sublayers = CACFLayerGetSublayers(layer());
401 size_t n = CFArrayGetCount(sublayers);
402
403 for (size_t i = 0; i < n; ++i)
404 if (CFArrayGetValueAtIndex(sublayers, i) == ref)
405 return i;
406
407 return -1;
408 }
409
ancestorOrSelfWithSuperlayer(WKCACFLayer * superlayer) const410 WKCACFLayer* WKCACFLayer::ancestorOrSelfWithSuperlayer(WKCACFLayer* superlayer) const
411 {
412 WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
413 for (WKCACFLayer* ancestor = this->superlayer(); ancestor; layer = ancestor, ancestor = ancestor->superlayer()) {
414 if (ancestor == superlayer)
415 return layer;
416 }
417 return 0;
418 }
419
setBounds(const CGRect & rect)420 void WKCACFLayer::setBounds(const CGRect& rect)
421 {
422 if (CGRectEqualToRect(rect, bounds()))
423 return;
424
425 CACFLayerSetBounds(layer(), rect);
426 setNeedsCommit();
427
428 if (m_needsDisplayOnBoundsChange)
429 setNeedsDisplay();
430 }
431
setFrame(const CGRect & rect)432 void WKCACFLayer::setFrame(const CGRect& rect)
433 {
434 CGRect oldFrame = frame();
435 if (CGRectEqualToRect(rect, oldFrame))
436 return;
437
438 CACFLayerSetFrame(layer(), rect);
439 setNeedsCommit();
440
441 if (m_needsDisplayOnBoundsChange)
442 setNeedsDisplay();
443 }
444
setContentsGravity(ContentsGravityType type)445 void WKCACFLayer::setContentsGravity(ContentsGravityType type)
446 {
447 CACFLayerSetContentsGravity(layer(), toCACFContentsGravityType(type));
448 setNeedsCommit();
449 }
450
contentsGravity() const451 WKCACFLayer::ContentsGravityType WKCACFLayer::contentsGravity() const
452 {
453 return fromCACFContentsGravityType(CACFLayerGetContentsGravity(layer()));
454 }
455
setMagnificationFilter(FilterType type)456 void WKCACFLayer::setMagnificationFilter(FilterType type)
457 {
458 CACFLayerSetMagnificationFilter(layer(), toCACFFilterType(type));
459 setNeedsCommit();
460 }
461
magnificationFilter() const462 WKCACFLayer::FilterType WKCACFLayer::magnificationFilter() const
463 {
464 return fromCACFFilterType(CACFLayerGetMagnificationFilter(layer()));
465 }
466
setMinificationFilter(FilterType type)467 void WKCACFLayer::setMinificationFilter(FilterType type)
468 {
469 CACFLayerSetMinificationFilter(layer(), toCACFFilterType(type));
470 setNeedsCommit();
471 }
472
minificationFilter() const473 WKCACFLayer::FilterType WKCACFLayer::minificationFilter() const
474 {
475 return fromCACFFilterType(CACFLayerGetMinificationFilter(layer()));
476 }
477
rootLayer() const478 WKCACFLayer* WKCACFLayer::rootLayer() const
479 {
480 WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
481 for (WKCACFLayer* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
482 return layer;
483 }
484
removeAllSublayers()485 void WKCACFLayer::removeAllSublayers()
486 {
487 CACFLayerSetSublayers(layer(), 0);
488 setNeedsCommit();
489 }
490
setSublayers(const Vector<RefPtr<WKCACFLayer>> & sublayers)491 void WKCACFLayer::setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
492 {
493 if (sublayers.isEmpty())
494 CACFLayerSetSublayers(layer(), 0);
495 else {
496 // Create a vector of CACFLayers.
497 Vector<const void*> layers;
498 for (size_t i = 0; i < sublayers.size(); i++)
499 layers.append(sublayers[i]->layer());
500
501 RetainPtr<CFArrayRef> layersArray(AdoptCF, CFArrayCreate(0, layers.data(), layers.size(), 0));
502 CACFLayerSetSublayers(layer(), layersArray.get());
503 }
504
505 setNeedsCommit();
506 }
507
moveSublayers(WKCACFLayer * fromLayer,WKCACFLayer * toLayer)508 void WKCACFLayer::moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer)
509 {
510 if (!fromLayer || !toLayer)
511 return;
512
513 CACFLayerSetSublayers(toLayer->layer(), CACFLayerGetSublayers(fromLayer->layer()));
514 fromLayer->setNeedsCommit();
515 toLayer->setNeedsCommit();
516 }
517
superlayer() const518 WKCACFLayer* WKCACFLayer::superlayer() const
519 {
520 CACFLayerRef super = CACFLayerGetSuperlayer(layer());
521 if (!super)
522 return 0;
523 return WKCACFLayer::layer(super);
524 }
525
setNeedsDisplay(const CGRect & dirtyRect)526 void WKCACFLayer::setNeedsDisplay(const CGRect& dirtyRect)
527 {
528 if (m_owner)
529 CACFLayerSetNeedsDisplay(layer(), &dirtyRect);
530 setNeedsCommit();
531 }
532
setNeedsDisplay()533 void WKCACFLayer::setNeedsDisplay()
534 {
535 if (m_owner)
536 CACFLayerSetNeedsDisplay(layer(), 0);
537 setNeedsCommit();
538 }
539
540 #ifndef NDEBUG
printIndent(int indent)541 static void printIndent(int indent)
542 {
543 for ( ; indent > 0; --indent)
544 fprintf(stderr, " ");
545 }
546
printTransform(const CATransform3D & transform)547 static void printTransform(const CATransform3D& transform)
548 {
549 fprintf(stderr, "[%g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g]",
550 transform.m11, transform.m12, transform.m13, transform.m14,
551 transform.m21, transform.m22, transform.m23, transform.m24,
552 transform.m31, transform.m32, transform.m33, transform.m34,
553 transform.m41, transform.m42, transform.m43, transform.m44);
554 }
555
printTree() const556 void WKCACFLayer::printTree() const
557 {
558 // Print heading info
559 CGRect rootBounds = bounds();
560 fprintf(stderr, "\n\n** Render tree at time %g (bounds %g, %g %gx%g) **\n\n",
561 currentTime(), rootBounds.origin.x, rootBounds.origin.y, rootBounds.size.width, rootBounds.size.height);
562
563 // Print layer tree from the root
564 printLayer(0);
565 }
566
printLayer(int indent) const567 void WKCACFLayer::printLayer(int indent) const
568 {
569 CGPoint layerPosition = position();
570 CGPoint layerAnchorPoint = anchorPoint();
571 CGRect layerBounds = bounds();
572 printIndent(indent);
573 fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g]\n",
574 isTransformLayer() ? "transform-layer" : "layer",
575 layerPosition.x, layerPosition.y, zPosition(),
576 layerBounds.origin.x, layerBounds.origin.y, layerBounds.size.width, layerBounds.size.height,
577 layerAnchorPoint.x, layerAnchorPoint.y, anchorPointZ());
578
579 // Print name if needed
580 String layerName = name();
581 if (!layerName.isEmpty()) {
582 printIndent(indent + 1);
583 fprintf(stderr, "(name %s)\n", layerName.utf8().data());
584 }
585
586 // Print masksToBounds if needed
587 bool layerMasksToBounds = masksToBounds();
588 if (layerMasksToBounds) {
589 printIndent(indent + 1);
590 fprintf(stderr, "(masksToBounds true)\n");
591 }
592
593 // Print opacity if needed
594 float layerOpacity = opacity();
595 if (layerOpacity != 1) {
596 printIndent(indent + 1);
597 fprintf(stderr, "(opacity %hf)\n", layerOpacity);
598 }
599
600 // Print sublayerTransform if needed
601 CATransform3D layerTransform = sublayerTransform();
602 if (!CATransform3DIsIdentity(layerTransform)) {
603 printIndent(indent + 1);
604 fprintf(stderr, "(sublayerTransform ");
605 printTransform(layerTransform);
606 fprintf(stderr, ")\n");
607 }
608
609 // Print transform if needed
610 layerTransform = transform();
611 if (!CATransform3DIsIdentity(layerTransform)) {
612 printIndent(indent + 1);
613 fprintf(stderr, "(transform ");
614 printTransform(layerTransform);
615 fprintf(stderr, ")\n");
616 }
617
618 // Print contents if needed
619 CGImageRef layerContents = contents();
620 if (layerContents) {
621 printIndent(indent + 1);
622 fprintf(stderr, "(contents (image [%d %d]))\n",
623 CGImageGetWidth(layerContents), CGImageGetHeight(layerContents));
624 }
625
626 // Print sublayers if needed
627 int n = numSublayers();
628 if (n > 0) {
629 printIndent(indent + 1);
630 fprintf(stderr, "(sublayers\n");
631 for (int i = 0; i < n; ++i)
632 sublayerAtIndex(i)->printLayer(indent + 2);
633
634 printIndent(indent + 1);
635 fprintf(stderr, ")\n");
636 }
637
638 printIndent(indent);
639 fprintf(stderr, ")\n");
640 }
641 #endif // #ifndef NDEBUG
642 }
643
644 #endif // USE(ACCELERATED_COMPOSITING)
645