2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #if USE(ACCELERATED_COMPOSITING)
30 #include "WKCACFLayer.h"
32 #include "WKCACFLayerRenderer.h"
33 #include <wtf/text/CString.h>
36 #include <QuartzCore/CACFContext.h>
37 #include <QuartzCore/CARender.h>
40 #include <wtf/CurrentTime.h>
48 void WKCACFLayer::internalCheckLayerConsistency()
51 size_t n = sublayerCount();
52 for (size_t i = 0; i < n; ++i) {
53 // This will ASSERT in internalSublayerAtIndex if this entry doesn't have proper user data
54 WKCACFLayer* sublayer = internalSublayerAtIndex(i);
56 // Make sure we don't have any null entries in the list
59 // Make sure the each layer has a corresponding CACFLayer
60 ASSERT(sublayer->layer());
65 static void displayCallback(CACFLayerRef layer, CGContextRef context)
67 ASSERT_ARG(layer, WKCACFLayer::layer(layer));
68 WKCACFLayer::layer(layer)->drawInContext(context);
71 static CFStringRef toCACFLayerType(WKCACFLayer::LayerType type)
74 case WKCACFLayer::Layer: return kCACFLayer;
75 case WKCACFLayer::TransformLayer: return kCACFTransformLayer;
80 static CFStringRef toCACFContentsGravityType(WKCACFLayer::ContentsGravityType type)
83 case WKCACFLayer::Center: return kCACFGravityCenter;
84 case WKCACFLayer::Top: return kCACFGravityTop;
85 case WKCACFLayer::Bottom: return kCACFGravityBottom;
86 case WKCACFLayer::Left: return kCACFGravityLeft;
87 case WKCACFLayer::Right: return kCACFGravityRight;
88 case WKCACFLayer::TopLeft: return kCACFGravityTopLeft;
89 case WKCACFLayer::TopRight: return kCACFGravityTopRight;
90 case WKCACFLayer::BottomLeft: return kCACFGravityBottomLeft;
91 case WKCACFLayer::BottomRight: return kCACFGravityBottomRight;
92 case WKCACFLayer::Resize: return kCACFGravityResize;
93 case WKCACFLayer::ResizeAspect: return kCACFGravityResizeAspect;
94 case WKCACFLayer::ResizeAspectFill: return kCACFGravityResizeAspectFill;
99 static WKCACFLayer::ContentsGravityType fromCACFContentsGravityType(CFStringRef string)
101 if (CFEqual(string, kCACFGravityTop))
102 return WKCACFLayer::Top;
104 if (CFEqual(string, kCACFGravityBottom))
105 return WKCACFLayer::Bottom;
107 if (CFEqual(string, kCACFGravityLeft))
108 return WKCACFLayer::Left;
110 if (CFEqual(string, kCACFGravityRight))
111 return WKCACFLayer::Right;
113 if (CFEqual(string, kCACFGravityTopLeft))
114 return WKCACFLayer::TopLeft;
116 if (CFEqual(string, kCACFGravityTopRight))
117 return WKCACFLayer::TopRight;
119 if (CFEqual(string, kCACFGravityBottomLeft))
120 return WKCACFLayer::BottomLeft;
122 if (CFEqual(string, kCACFGravityBottomRight))
123 return WKCACFLayer::BottomRight;
125 if (CFEqual(string, kCACFGravityResize))
126 return WKCACFLayer::Resize;
128 if (CFEqual(string, kCACFGravityResizeAspect))
129 return WKCACFLayer::ResizeAspect;
131 if (CFEqual(string, kCACFGravityResizeAspectFill))
132 return WKCACFLayer::ResizeAspectFill;
134 return WKCACFLayer::Center;
137 static CFStringRef toCACFFilterType(WKCACFLayer::FilterType type)
140 case WKCACFLayer::Linear: return kCACFFilterLinear;
141 case WKCACFLayer::Nearest: return kCACFFilterNearest;
142 case WKCACFLayer::Trilinear: return kCACFFilterTrilinear;
147 static WKCACFLayer::FilterType fromCACFFilterType(CFStringRef string)
149 if (CFEqual(string, kCACFFilterNearest))
150 return WKCACFLayer::Nearest;
152 if (CFEqual(string, kCACFFilterTrilinear))
153 return WKCACFLayer::Trilinear;
155 return WKCACFLayer::Linear;
158 PassRefPtr<WKCACFLayer> WKCACFLayer::create(LayerType type)
160 if (!WKCACFLayerRenderer::acceleratedCompositingAvailable())
162 return adoptRef(new WKCACFLayer(type));
165 // FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually
166 // get destroyed in debug builds. A static counter could accomplish this pretty easily.
168 WKCACFLayer::WKCACFLayer(LayerType type)
169 : m_layer(AdoptCF, CACFLayerCreate(toCACFLayerType(type)))
171 , m_needsDisplayOnBoundsChange(false)
173 CACFLayerSetUserData(layer(), this);
174 CACFLayerSetDisplayCallback(layer(), displayCallback);
177 WKCACFLayer::~WKCACFLayer()
179 // 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.
180 ASSERT(!superlayer());
182 // Get rid of the children so we don't have any dangling references around
183 removeAllSublayers();
186 CACFLayerSetUserData(layer(), reinterpret_cast<void*>(0xDEADBEEF));
188 CACFLayerSetUserData(layer(), 0);
190 CACFLayerSetDisplayCallback(layer(), 0);
193 void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context)
195 CACFContextSetLayer(context, layer());
199 void WKCACFLayer::setNeedsCommit()
201 WKCACFLayer* root = rootLayer();
203 // Call setNeedsRender on the root layer, which will cause a render to
204 // happen in WKCACFLayerRenderer
205 root->setNeedsRender();
208 bool WKCACFLayer::isTransformLayer() const
210 return CACFLayerGetClass(layer()) == kCACFTransformLayer;
213 void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer)
215 insertSublayer(sublayer, sublayerCount());
218 void WKCACFLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index)
220 index = min(index, sublayerCount() + 1);
221 sublayer->removeFromSuperlayer();
222 CACFLayerInsertSublayer(layer(), sublayer->layer(), index);
224 checkLayerConsistency();
227 void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
230 insertSublayer(sublayer, 0);
234 int referenceIndex = internalIndexOfSublayer(reference);
235 if (referenceIndex == -1) {
236 addSublayer(sublayer);
240 insertSublayer(sublayer, referenceIndex + 1);
243 void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
246 insertSublayer(sublayer, 0);
250 int referenceIndex = internalIndexOfSublayer(reference);
251 if (referenceIndex == -1) {
252 addSublayer(sublayer);
256 insertSublayer(sublayer, referenceIndex);
259 void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer> newLayer)
261 ASSERT_ARG(reference, reference);
262 ASSERT_ARG(reference, reference->superlayer() == this);
264 if (reference == newLayer)
267 int referenceIndex = internalIndexOfSublayer(reference);
268 ASSERT(referenceIndex != -1);
269 if (referenceIndex == -1)
272 reference->removeFromSuperlayer();
275 newLayer->removeFromSuperlayer();
276 insertSublayer(newLayer, referenceIndex);
280 size_t WKCACFLayer::internalSublayerCount() const
282 CFArrayRef sublayers = CACFLayerGetSublayers(layer());
283 return sublayers ? CFArrayGetCount(sublayers) : 0;
286 void WKCACFLayer::adoptSublayers(WKCACFLayer* source)
288 // We will use setSublayers() because it properly nulls
289 // out the superlayer pointer.
290 Vector<RefPtr<WKCACFLayer> > sublayers;
291 size_t n = source->sublayerCount();
293 for (size_t i = 0; i < n; ++i)
294 sublayers.append(source->internalSublayerAtIndex(i));
296 setSublayers(sublayers);
297 source->checkLayerConsistency();
300 void WKCACFLayer::removeFromSuperlayer()
302 WKCACFLayer* superlayer = this->superlayer();
303 CACFLayerRemoveFromSuperlayer(layer());
304 checkLayerConsistency();
307 superlayer->setNeedsCommit();
310 WKCACFLayer* WKCACFLayer::internalSublayerAtIndex(int index) const
312 CFArrayRef sublayers = CACFLayerGetSublayers(layer());
313 if (!sublayers || index < 0 || CFArrayGetCount(sublayers) <= index)
316 return layer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))));
319 int WKCACFLayer::internalIndexOfSublayer(const WKCACFLayer* reference)
321 CACFLayerRef ref = reference->layer();
325 CFArrayRef sublayers = CACFLayerGetSublayers(layer());
329 size_t n = CFArrayGetCount(sublayers);
331 for (size_t i = 0; i < n; ++i)
332 if (CFArrayGetValueAtIndex(sublayers, i) == ref)
338 WKCACFLayer* WKCACFLayer::ancestorOrSelfWithSuperlayer(WKCACFLayer* superlayer) const
340 WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
341 for (WKCACFLayer* ancestor = this->superlayer(); ancestor; layer = ancestor, ancestor = ancestor->superlayer()) {
342 if (ancestor == superlayer)
348 void WKCACFLayer::setBounds(const CGRect& rect)
350 if (CGRectEqualToRect(rect, bounds()))
353 CACFLayerSetBounds(layer(), rect);
356 if (m_needsDisplayOnBoundsChange)
363 void WKCACFLayer::setFrame(const CGRect& rect)
365 CGRect oldFrame = frame();
366 if (CGRectEqualToRect(rect, oldFrame))
369 CACFLayerSetFrame(layer(), rect);
372 if (m_needsDisplayOnBoundsChange && !CGSizeEqualToSize(rect.size, oldFrame.size))
379 void WKCACFLayer::setContentsGravity(ContentsGravityType type)
381 CACFLayerSetContentsGravity(layer(), toCACFContentsGravityType(type));
385 WKCACFLayer::ContentsGravityType WKCACFLayer::contentsGravity() const
387 return fromCACFContentsGravityType(CACFLayerGetContentsGravity(layer()));
390 void WKCACFLayer::setMagnificationFilter(FilterType type)
392 CACFLayerSetMagnificationFilter(layer(), toCACFFilterType(type));
396 WKCACFLayer::FilterType WKCACFLayer::magnificationFilter() const
398 return fromCACFFilterType(CACFLayerGetMagnificationFilter(layer()));
401 void WKCACFLayer::setMinificationFilter(FilterType type)
403 CACFLayerSetMinificationFilter(layer(), toCACFFilterType(type));
407 WKCACFLayer::FilterType WKCACFLayer::minificationFilter() const
409 return fromCACFFilterType(CACFLayerGetMinificationFilter(layer()));
412 WKCACFLayer* WKCACFLayer::rootLayer() const
414 WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
415 for (WKCACFLayer* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
419 void WKCACFLayer::internalRemoveAllSublayers()
421 CACFLayerSetSublayers(layer(), 0);
425 void WKCACFLayer::internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
427 // Remove all the current sublayers and add the passed layers
428 CACFLayerSetSublayers(layer(), 0);
430 // Perform removeFromSuperLayer in a separate pass. CACF requires superlayer to
431 // be null or CACFLayerInsertSublayer silently fails.
432 for (size_t i = 0; i < sublayers.size(); i++)
433 CACFLayerRemoveFromSuperlayer(sublayers[i]->layer());
435 for (size_t i = 0; i < sublayers.size(); i++)
436 CACFLayerInsertSublayer(layer(), sublayers[i]->layer(), i);
441 WKCACFLayer* WKCACFLayer::superlayer() const
443 CACFLayerRef super = CACFLayerGetSuperlayer(layer());
446 return WKCACFLayer::layer(super);
449 void WKCACFLayer::internalSetNeedsDisplay(const CGRect* dirtyRect)
451 CACFLayerSetNeedsDisplay(layer(), dirtyRect);
454 void WKCACFLayer::setLayoutClient(WKCACFLayerLayoutClient* layoutClient)
456 if (layoutClient == m_layoutClient)
459 m_layoutClient = layoutClient;
460 CACFLayerSetLayoutCallback(layer(), m_layoutClient ? layoutSublayersProc : 0);
463 void WKCACFLayer::layoutSublayersProc(CACFLayerRef caLayer)
465 WKCACFLayer* layer = WKCACFLayer::layer(caLayer);
466 if (layer && layer->m_layoutClient)
467 layer->m_layoutClient->layoutSublayersOfLayer(layer);
471 static void printIndent(int indent)
473 for ( ; indent > 0; --indent)
474 fprintf(stderr, " ");
477 static void printTransform(const CATransform3D& transform)
479 fprintf(stderr, "[%g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g]",
480 transform.m11, transform.m12, transform.m13, transform.m14,
481 transform.m21, transform.m22, transform.m23, transform.m24,
482 transform.m31, transform.m32, transform.m33, transform.m34,
483 transform.m41, transform.m42, transform.m43, transform.m44);
486 void WKCACFLayer::printTree() const
488 // Print heading info
489 CGRect rootBounds = bounds();
490 fprintf(stderr, "\n\n** Render tree at time %g (bounds %g, %g %gx%g) **\n\n",
491 currentTime(), rootBounds.origin.x, rootBounds.origin.y, rootBounds.size.width, rootBounds.size.height);
493 // Print layer tree from the root
497 void WKCACFLayer::printLayer(int indent) const
499 CGPoint layerPosition = position();
500 CGPoint layerAnchorPoint = anchorPoint();
501 CGRect layerBounds = bounds();
503 fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g] superlayer=%p\n",
504 isTransformLayer() ? "transform-layer" : "layer",
505 layerPosition.x, layerPosition.y, zPosition(),
506 layerBounds.origin.x, layerBounds.origin.y, layerBounds.size.width, layerBounds.size.height,
507 layerAnchorPoint.x, layerAnchorPoint.y, anchorPointZ(), superlayer());
509 // Print name if needed
510 String layerName = name();
511 if (!layerName.isEmpty()) {
512 printIndent(indent + 1);
513 fprintf(stderr, "(name %s)\n", layerName.utf8().data());
516 // Print masksToBounds if needed
517 bool layerMasksToBounds = masksToBounds();
518 if (layerMasksToBounds) {
519 printIndent(indent + 1);
520 fprintf(stderr, "(masksToBounds true)\n");
523 // Print opacity if needed
524 float layerOpacity = opacity();
525 if (layerOpacity != 1) {
526 printIndent(indent + 1);
527 fprintf(stderr, "(opacity %hf)\n", layerOpacity);
530 // Print sublayerTransform if needed
531 CATransform3D layerTransform = sublayerTransform();
532 if (!CATransform3DIsIdentity(layerTransform)) {
533 printIndent(indent + 1);
534 fprintf(stderr, "(sublayerTransform ");
535 printTransform(layerTransform);
536 fprintf(stderr, ")\n");
539 // Print transform if needed
540 layerTransform = transform();
541 if (!CATransform3DIsIdentity(layerTransform)) {
542 printIndent(indent + 1);
543 fprintf(stderr, "(transform ");
544 printTransform(layerTransform);
545 fprintf(stderr, ")\n");
548 // Print contents if needed
549 CFTypeRef layerContents = contents();
551 if (CFGetTypeID(layerContents) == CGImageGetTypeID()) {
552 CGImageRef imageContents = static_cast<CGImageRef>(const_cast<void*>(layerContents));
553 printIndent(indent + 1);
554 fprintf(stderr, "(contents (image [%d %d]))\n",
555 CGImageGetWidth(imageContents), CGImageGetHeight(imageContents));
559 // Print sublayers if needed
560 int n = sublayerCount();
562 printIndent(indent + 1);
563 fprintf(stderr, "(sublayers\n");
564 for (int i = 0; i < n; ++i)
565 internalSublayerAtIndex(i)->printLayer(indent + 2);
567 printIndent(indent + 1);
568 fprintf(stderr, ")\n");
572 fprintf(stderr, ")\n");
574 #endif // #ifndef NDEBUG
577 #endif // USE(ACCELERATED_COMPOSITING)