Home | History | Annotate | Download | only in win
      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 
     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)
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    266 void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context)
    267 {
    268     CACFContextSetLayer(context, layer());
    269     setNeedsCommit();
    270 }
    271 
    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 
    290 bool WKCACFLayer::isTransformLayer() const
    291 {
    292     return CACFLayerGetClass(layer()) == kCACFTransformLayer();
    293 }
    294 
    295 void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer)
    296 {
    297     insertSublayer(sublayer, numSublayers());
    298 }
    299 
    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 
    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 
    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 
    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 
    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 
    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 
    385 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 
    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 
    410 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 
    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 
    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 
    445 void WKCACFLayer::setContentsGravity(ContentsGravityType type)
    446 {
    447     CACFLayerSetContentsGravity(layer(), toCACFContentsGravityType(type));
    448     setNeedsCommit();
    449 }
    450 
    451 WKCACFLayer::ContentsGravityType WKCACFLayer::contentsGravity() const
    452 {
    453     return fromCACFContentsGravityType(CACFLayerGetContentsGravity(layer()));
    454 }
    455 
    456 void WKCACFLayer::setMagnificationFilter(FilterType type)
    457 {
    458     CACFLayerSetMagnificationFilter(layer(), toCACFFilterType(type));
    459     setNeedsCommit();
    460 }
    461 
    462 WKCACFLayer::FilterType WKCACFLayer::magnificationFilter() const
    463 {
    464     return fromCACFFilterType(CACFLayerGetMagnificationFilter(layer()));
    465 }
    466 
    467 void WKCACFLayer::setMinificationFilter(FilterType type)
    468 {
    469     CACFLayerSetMinificationFilter(layer(), toCACFFilterType(type));
    470     setNeedsCommit();
    471 }
    472 
    473 WKCACFLayer::FilterType WKCACFLayer::minificationFilter() const
    474 {
    475     return fromCACFFilterType(CACFLayerGetMinificationFilter(layer()));
    476 }
    477 
    478 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 
    485 void WKCACFLayer::removeAllSublayers()
    486 {
    487     CACFLayerSetSublayers(layer(), 0);
    488     setNeedsCommit();
    489 }
    490 
    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 
    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 
    518 WKCACFLayer* WKCACFLayer::superlayer() const
    519 {
    520     CACFLayerRef super = CACFLayerGetSuperlayer(layer());
    521     if (!super)
    522         return 0;
    523     return WKCACFLayer::layer(super);
    524 }
    525 
    526 void WKCACFLayer::setNeedsDisplay(const CGRect& dirtyRect)
    527 {
    528     if (m_owner)
    529         CACFLayerSetNeedsDisplay(layer(), &dirtyRect);
    530     setNeedsCommit();
    531 }
    532 
    533 void WKCACFLayer::setNeedsDisplay()
    534 {
    535     if (m_owner)
    536         CACFLayerSetNeedsDisplay(layer(), 0);
    537     setNeedsCommit();
    538 }
    539 
    540 #ifndef NDEBUG
    541 static void printIndent(int indent)
    542 {
    543     for ( ; indent > 0; --indent)
    544         fprintf(stderr, "  ");
    545 }
    546 
    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 
    556 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 
    567 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