66c41f3bc6684226142085ecc0e5b25e0238bb82
[WebKit-https.git] / Source / WebCore / platform / graphics / GraphicsLayer.cpp
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 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 #include "GraphicsLayer.h"
29
30 #include "FloatPoint.h"
31 #include "FloatRect.h"
32 #include "GraphicsContext.h"
33 #include "LayoutRect.h"
34 #include "RotateTransformOperation.h"
35 #include "TextStream.h"
36 #include <wtf/HashMap.h>
37 #include <wtf/text/CString.h>
38 #include <wtf/text/StringBuilder.h>
39 #include <wtf/text/WTFString.h>
40
41 #ifndef NDEBUG
42 #include <stdio.h>
43 #endif
44
45 namespace WebCore {
46
47 typedef HashMap<const GraphicsLayer*, Vector<FloatRect>> RepaintMap;
48 static RepaintMap& repaintRectMap()
49 {
50     DEPRECATED_DEFINE_STATIC_LOCAL(RepaintMap, map, ());
51     return map;
52 }
53
54 void KeyframeValueList::insert(std::unique_ptr<const AnimationValue> value)
55 {
56     for (size_t i = 0; i < m_values.size(); ++i) {
57         const AnimationValue* curValue = m_values[i].get();
58         if (curValue->keyTime() == value->keyTime()) {
59             ASSERT_NOT_REACHED();
60             // insert after
61             m_values.insert(i + 1, WTF::move(value));
62             return;
63         }
64         if (curValue->keyTime() > value->keyTime()) {
65             // insert before
66             m_values.insert(i, WTF::move(value));
67             return;
68         }
69     }
70     
71     m_values.append(WTF::move(value));
72 }
73
74 #if !USE(CA)
75 bool GraphicsLayer::supportsLayerType(Type type)
76 {
77     switch (type) {
78     case Type::Normal:
79     case Type::PageTiledBacking:
80     case Type::Scrolling:
81         return true;
82     case Type::Shape:
83         return false;
84     }
85     ASSERT_NOT_REACHED();
86     return false;
87 }
88
89 bool GraphicsLayer::supportsBackgroundColorContent()
90 {
91 #if USE(TEXTURE_MAPPER)
92     return true;
93 #else
94     return false;
95 #endif
96 }
97 #endif
98
99 #if !USE(COORDINATED_GRAPHICS)
100 bool GraphicsLayer::supportsContentsTiling()
101 {
102     // FIXME: Enable the feature on different ports.
103     return false;
104 }
105 #endif
106
107 GraphicsLayer::GraphicsLayer(Type type, GraphicsLayerClient& client)
108     : m_client(client)
109     , m_anchorPoint(0.5f, 0.5f, 0)
110     , m_opacity(1)
111     , m_zPosition(0)
112 #if ENABLE(CSS_COMPOSITING)
113     , m_blendMode(BlendModeNormal)
114 #endif
115     , m_type(type)
116     , m_contentsOpaque(false)
117     , m_preserves3D(false)
118     , m_backfaceVisibility(true)
119     , m_usingTiledBacking(false)
120     , m_masksToBounds(false)
121     , m_drawsContent(false)
122     , m_contentsVisible(true)
123     , m_acceleratesDrawing(false)
124     , m_appliesPageScale(false)
125     , m_showDebugBorder(false)
126     , m_showRepaintCounter(false)
127     , m_isMaskLayer(false)
128     , m_paintingPhase(GraphicsLayerPaintAllWithOverflowClip)
129     , m_contentsOrientation(CompositingCoordinatesTopDown)
130     , m_parent(nullptr)
131     , m_maskLayer(nullptr)
132     , m_replicaLayer(nullptr)
133     , m_replicatedLayer(nullptr)
134     , m_repaintCount(0)
135     , m_customAppearance(NoCustomAppearance)
136 {
137 #ifndef NDEBUG
138     m_client.verifyNotPainting();
139 #endif
140 }
141
142 GraphicsLayer::~GraphicsLayer()
143 {
144     resetTrackedRepaints();
145     ASSERT(!m_parent); // willBeDestroyed should have been called already.
146 }
147
148 void GraphicsLayer::willBeDestroyed()
149 {
150 #ifndef NDEBUG
151     m_client.verifyNotPainting();
152 #endif
153     if (m_replicaLayer)
154         m_replicaLayer->setReplicatedLayer(0);
155
156     if (m_replicatedLayer)
157         m_replicatedLayer->setReplicatedByLayer(0);
158
159     removeAllChildren();
160     removeFromParent();
161 }
162
163 void GraphicsLayer::setParent(GraphicsLayer* layer)
164 {
165     ASSERT(!layer || !layer->hasAncestor(this));
166     m_parent = layer;
167 }
168
169 bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const
170 {
171     for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) {
172         if (curr == ancestor)
173             return true;
174     }
175     
176     return false;
177 }
178
179 bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren)
180 {
181     // If the contents of the arrays are the same, nothing to do.
182     if (newChildren == m_children)
183         return false;
184
185     removeAllChildren();
186     
187     size_t listSize = newChildren.size();
188     for (size_t i = 0; i < listSize; ++i)
189         addChild(newChildren[i]);
190     
191     return true;
192 }
193
194 void GraphicsLayer::addChild(GraphicsLayer* childLayer)
195 {
196     ASSERT(childLayer != this);
197     
198     if (childLayer->parent())
199         childLayer->removeFromParent();
200
201     childLayer->setParent(this);
202     m_children.append(childLayer);
203 }
204
205 void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index)
206 {
207     ASSERT(childLayer != this);
208
209     if (childLayer->parent())
210         childLayer->removeFromParent();
211
212     childLayer->setParent(this);
213     m_children.insert(index, childLayer);
214 }
215
216 void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
217 {
218     ASSERT(childLayer != this);
219     childLayer->removeFromParent();
220
221     bool found = false;
222     for (unsigned i = 0; i < m_children.size(); i++) {
223         if (sibling == m_children[i]) {
224             m_children.insert(i, childLayer);
225             found = true;
226             break;
227         }
228     }
229
230     childLayer->setParent(this);
231
232     if (!found)
233         m_children.append(childLayer);
234 }
235
236 void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
237 {
238     childLayer->removeFromParent();
239     ASSERT(childLayer != this);
240
241     bool found = false;
242     for (unsigned i = 0; i < m_children.size(); i++) {
243         if (sibling == m_children[i]) {
244             m_children.insert(i+1, childLayer);
245             found = true;
246             break;
247         }
248     }
249
250     childLayer->setParent(this);
251
252     if (!found)
253         m_children.append(childLayer);
254 }
255
256 bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
257 {
258     ASSERT(!newChild->parent());
259     bool found = false;
260     for (unsigned i = 0; i < m_children.size(); i++) {
261         if (oldChild == m_children[i]) {
262             m_children[i] = newChild;
263             found = true;
264             break;
265         }
266     }
267     if (found) {
268         oldChild->setParent(0);
269
270         newChild->removeFromParent();
271         newChild->setParent(this);
272         return true;
273     }
274     return false;
275 }
276
277 void GraphicsLayer::removeAllChildren()
278 {
279     while (m_children.size()) {
280         GraphicsLayer* curLayer = m_children[0];
281         ASSERT(curLayer->parent());
282         curLayer->removeFromParent();
283     }
284 }
285
286 void GraphicsLayer::removeFromParent()
287 {
288     if (m_parent) {
289         m_parent->m_children.removeFirst(this);
290         setParent(nullptr);
291     }
292 }
293
294 void GraphicsLayer::setMaskLayer(GraphicsLayer* layer)
295 {
296     if (layer == m_maskLayer)
297         return;
298
299     if (layer) {
300         layer->removeFromParent();
301         layer->setParent(this);
302         layer->setIsMaskLayer(true);
303     } else if (m_maskLayer) {
304         m_maskLayer->setParent(nullptr);
305         m_maskLayer->setIsMaskLayer(false);
306     }
307     
308     m_maskLayer = layer;
309 }
310
311 Path GraphicsLayer::shapeLayerPath() const
312 {
313 #if USE(CA)
314     return m_shapeLayerPath;
315 #else
316     return Path();
317 #endif
318 }
319
320 void GraphicsLayer::setShapeLayerPath(const Path& path)
321 {
322 #if USE(CA)
323     m_shapeLayerPath = path;
324 #else
325     UNUSED_PARAM(path);
326 #endif
327 }
328
329 WindRule GraphicsLayer::shapeLayerWindRule() const
330 {
331 #if USE(CA)
332     return m_shapeLayerWindRule;
333 #else
334     return RULE_NONZERO;
335 #endif
336 }
337
338 void GraphicsLayer::setShapeLayerWindRule(WindRule windRule)
339 {
340 #if USE(CA)
341     m_shapeLayerWindRule = windRule;
342 #else
343     UNUSED_PARAM(windRule);
344 #endif
345 }
346
347 void GraphicsLayer::noteDeviceOrPageScaleFactorChangedIncludingDescendants()
348 {
349     deviceOrPageScaleFactorChanged();
350
351     if (m_maskLayer)
352         m_maskLayer->deviceOrPageScaleFactorChanged();
353
354     if (m_replicaLayer)
355         m_replicaLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
356
357     const Vector<GraphicsLayer*>& childLayers = children();
358     size_t numChildren = childLayers.size();
359     for (size_t i = 0; i < numChildren; ++i)
360         childLayers[i]->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
361 }
362
363 void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
364 {
365     if (m_replicaLayer == layer)
366         return;
367
368     if (m_replicaLayer)
369         m_replicaLayer->setReplicatedLayer(0);
370
371     if (layer)
372         layer->setReplicatedLayer(this);
373
374     m_replicaLayer = layer;
375 }
376
377 void GraphicsLayer::setOffsetFromRenderer(const FloatSize& offset, ShouldSetNeedsDisplay shouldSetNeedsDisplay)
378 {
379     if (offset == m_offsetFromRenderer)
380         return;
381
382     m_offsetFromRenderer = offset;
383
384     // If the compositing layer offset changes, we need to repaint.
385     if (shouldSetNeedsDisplay == SetNeedsDisplay)
386         setNeedsDisplay();
387 }
388
389 void GraphicsLayer::setSize(const FloatSize& size)
390 {
391     if (size == m_size)
392         return;
393     
394     m_size = size;
395
396     if (shouldRepaintOnSizeChange())
397         setNeedsDisplay();
398 }
399
400 void GraphicsLayer::setBackgroundColor(const Color& color)
401 {
402     m_backgroundColor = color;
403 }
404
405 void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const FloatRect& clip)
406 {
407     FloatSize offset = offsetFromRenderer();
408     context.translate(-offset);
409
410     FloatRect clipRect(clip);
411     clipRect.move(offset);
412
413     m_client.paintContents(this, context, m_paintingPhase, clipRect);
414 }
415
416 String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
417 {
418     // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
419     StringBuilder id;
420     id.appendLiteral("-|transition");
421     id.appendNumber(static_cast<int>(property));
422     id.append('-');
423     return id.toString();
424 }
425
426 void GraphicsLayer::suspendAnimations(double)
427 {
428 }
429
430 void GraphicsLayer::resumeAnimations()
431 {
432 }
433
434 void GraphicsLayer::getDebugBorderInfo(Color& color, float& width) const
435 {
436     if (drawsContent()) {
437         if (m_usingTiledBacking) {
438             color = Color(255, 128, 0, 128); // tiled layer: orange
439             width = 2;
440             return;
441         }
442
443         color = Color(0, 128, 32, 128); // normal layer: green
444         width = 2;
445         return;
446     }
447
448     if (usesContentsLayer()) {
449         color = Color(255, 150, 255, 200); // non-painting layer with contents: pink
450         width = 2;
451         return;
452     }
453     
454     if (masksToBounds()) {
455         color = Color(128, 255, 255, 48); // masking layer: pale blue
456         width = 20;
457         return;
458     }
459
460     color = Color(255, 255, 0, 192); // container: yellow
461     width = 2;
462 }
463
464 void GraphicsLayer::updateDebugIndicators()
465 {
466     if (!isShowingDebugBorder())
467         return;
468
469     Color borderColor;
470     float width = 0;
471     getDebugBorderInfo(borderColor, width);
472     setDebugBorder(borderColor, width);
473 }
474
475 void GraphicsLayer::setZPosition(float position)
476 {
477     m_zPosition = position;
478 }
479
480 float GraphicsLayer::accumulatedOpacity() const
481 {
482     if (!preserves3D())
483         return 1;
484         
485     return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
486 }
487
488 void GraphicsLayer::distributeOpacity(float accumulatedOpacity)
489 {
490     // If this is a transform layer we need to distribute our opacity to all our children
491     
492     // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own
493     // opacity to get the total contribution
494     accumulatedOpacity *= m_opacity;
495     
496     setOpacityInternal(accumulatedOpacity);
497     
498     if (preserves3D()) {
499         size_t numChildren = children().size();
500         for (size_t i = 0; i < numChildren; ++i)
501             children()[i]->distributeOpacity(accumulatedOpacity);
502     }
503 }
504
505 static inline const FilterOperations& filterOperationsAt(const KeyframeValueList& valueList, size_t index)
506 {
507     return static_cast<const FilterAnimationValue&>(valueList.at(index)).value();
508 }
509
510 int GraphicsLayer::validateFilterOperations(const KeyframeValueList& valueList)
511 {
512     ASSERT(valueList.property() == AnimatedPropertyWebkitFilter);
513
514     if (valueList.size() < 2)
515         return -1;
516
517     // Empty filters match anything, so find the first non-empty entry as the reference
518     size_t firstIndex = 0;
519     for ( ; firstIndex < valueList.size(); ++firstIndex) {
520         if (!filterOperationsAt(valueList, firstIndex).operations().isEmpty())
521             break;
522     }
523
524     if (firstIndex >= valueList.size())
525         return -1;
526
527     const FilterOperations& firstVal = filterOperationsAt(valueList, firstIndex);
528     
529     for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
530         const FilterOperations& val = filterOperationsAt(valueList, i);
531         
532         // An emtpy filter list matches anything.
533         if (val.operations().isEmpty())
534             continue;
535         
536         if (!firstVal.operationsMatch(val))
537             return -1;
538     }
539     
540     return firstIndex;
541 }
542
543 // An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
544 // The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is 
545 // true if the rotation between any two keyframes is >= 180 degrees.
546
547 static inline const TransformOperations& operationsAt(const KeyframeValueList& valueList, size_t index)
548 {
549     return static_cast<const TransformAnimationValue&>(valueList.at(index)).value();
550 }
551
552 int GraphicsLayer::validateTransformOperations(const KeyframeValueList& valueList, bool& hasBigRotation)
553 {
554     ASSERT(valueList.property() == AnimatedPropertyTransform);
555
556     hasBigRotation = false;
557     
558     if (valueList.size() < 2)
559         return -1;
560     
561     // Empty transforms match anything, so find the first non-empty entry as the reference.
562     size_t firstIndex = 0;
563     for ( ; firstIndex < valueList.size(); ++firstIndex) {
564         if (!operationsAt(valueList, firstIndex).operations().isEmpty())
565             break;
566     }
567     
568     if (firstIndex >= valueList.size())
569         return -1;
570         
571     const TransformOperations& firstVal = operationsAt(valueList, firstIndex);
572     
573     // See if the keyframes are valid.
574     for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
575         const TransformOperations& val = operationsAt(valueList, i);
576         
577         // An empty transform list matches anything.
578         if (val.operations().isEmpty())
579             continue;
580             
581         if (!firstVal.operationsMatch(val))
582             return -1;
583     }
584
585     // Keyframes are valid, check for big rotations.    
586     double lastRotationAngle = 0.0;
587     double maxRotationAngle = -1.0;
588         
589     for (size_t j = 0; j < firstVal.operations().size(); ++j) {
590         TransformOperation::OperationType type = firstVal.operations().at(j)->type();
591         
592         // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
593         if (type == TransformOperation::ROTATE_X ||
594             type == TransformOperation::ROTATE_Y ||
595             type == TransformOperation::ROTATE_Z ||
596             type == TransformOperation::ROTATE_3D) {
597             lastRotationAngle = downcast<RotateTransformOperation>(*firstVal.operations().at(j)).angle();
598             
599             if (maxRotationAngle < 0)
600                 maxRotationAngle = fabs(lastRotationAngle);
601             
602             for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
603                 const TransformOperations& val = operationsAt(valueList, i);
604                 double rotationAngle = val.operations().isEmpty() ? 0 : downcast<RotateTransformOperation>(*val.operations().at(j)).angle();
605                 double diffAngle = fabs(rotationAngle - lastRotationAngle);
606                 if (diffAngle > maxRotationAngle)
607                     maxRotationAngle = diffAngle;
608                 lastRotationAngle = rotationAngle;
609             }
610         }
611     }
612     
613     hasBigRotation = maxRotationAngle >= 180.0;
614     
615     return firstIndex;
616 }
617
618 double GraphicsLayer::backingStoreMemoryEstimate() const
619 {
620     if (!drawsContent())
621         return 0;
622     
623     // Effects of page and device scale are ignored; subclasses should override to take these into account.
624     return static_cast<double>(4 * size().width()) * size().height();
625 }
626
627 void GraphicsLayer::resetTrackedRepaints()
628 {
629     repaintRectMap().remove(this);
630 }
631
632 void GraphicsLayer::addRepaintRect(const FloatRect& repaintRect)
633 {
634     if (!m_client.isTrackingRepaints())
635         return;
636
637     FloatRect largestRepaintRect(FloatPoint(), m_size);
638     largestRepaintRect.intersect(repaintRect);
639     RepaintMap::iterator repaintIt = repaintRectMap().find(this);
640     if (repaintIt == repaintRectMap().end()) {
641         Vector<FloatRect> repaintRects;
642         repaintRects.append(largestRepaintRect);
643         repaintRectMap().set(this, repaintRects);
644     } else {
645         Vector<FloatRect>& repaintRects = repaintIt->value;
646         repaintRects.append(largestRepaintRect);
647     }
648 }
649
650 void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
651 {
652     writeIndent(ts, indent);
653     ts << "(" << "GraphicsLayer";
654
655     if (behavior & LayerTreeAsTextDebug) {
656         ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
657         ts << " \"" << m_name << "\"";
658     }
659
660     ts << "\n";
661     dumpProperties(ts, indent, behavior);
662     writeIndent(ts, indent);
663     ts << ")\n";
664 }
665
666 static void dumpChildren(TextStream& ts, const Vector<GraphicsLayer*>& children, unsigned& totalChildCount, int indent, LayerTreeAsTextBehavior behavior)
667 {
668     totalChildCount += children.size();
669     for (auto* child : children) {
670         if (!child->client().shouldSkipLayerInDump(child, behavior)) {
671             child->dumpLayer(ts, indent + 2, behavior);
672             continue;
673         }
674
675         totalChildCount--;
676         dumpChildren(ts, child->children(), totalChildCount, indent, behavior);
677     }
678 }
679
680 void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
681 {
682     if (m_position != FloatPoint()) {
683         writeIndent(ts, indent + 1);
684         ts << "(position " << m_position.x() << " " << m_position.y() << ")\n";
685     }
686
687     if (m_boundsOrigin != FloatPoint()) {
688         writeIndent(ts, indent + 1);
689         ts << "(bounds origin " << m_boundsOrigin.x() << " " << m_boundsOrigin.y() << ")\n";
690     }
691
692     if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) {
693         writeIndent(ts, indent + 1);
694         ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n";
695     }
696
697     if (m_size != IntSize()) {
698         writeIndent(ts, indent + 1);
699         ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
700     }
701
702     if (m_opacity != 1) {
703         writeIndent(ts, indent + 1);
704         ts << "(opacity " << m_opacity << ")\n";
705     }
706
707 #if ENABLE(CSS_COMPOSITING)
708     if (m_blendMode != BlendModeNormal) {
709         writeIndent(ts, indent + 1);
710         ts << "(blendMode " << compositeOperatorName(CompositeSourceOver, m_blendMode) << ")\n";
711     }
712 #endif
713
714     if (m_usingTiledBacking) {
715         writeIndent(ts, indent + 1);
716         ts << "(usingTiledLayer " << m_usingTiledBacking << ")\n";
717     }
718
719     bool needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack = m_client.needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack(*this);
720     if (m_contentsOpaque || needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack) {
721         writeIndent(ts, indent + 1);
722         ts << "(contentsOpaque " << (m_contentsOpaque || needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack) << ")\n";
723     }
724
725     if (m_preserves3D) {
726         writeIndent(ts, indent + 1);
727         ts << "(preserves3D " << m_preserves3D << ")\n";
728     }
729
730     if (m_drawsContent && m_client.shouldDumpPropertyForLayer(this, "drawsContent")) {
731         writeIndent(ts, indent + 1);
732         ts << "(drawsContent " << m_drawsContent << ")\n";
733     }
734
735     if (!m_contentsVisible) {
736         writeIndent(ts, indent + 1);
737         ts << "(contentsVisible " << m_contentsVisible << ")\n";
738     }
739
740     if (!m_backfaceVisibility) {
741         writeIndent(ts, indent + 1);
742         ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
743     }
744
745     if (behavior & LayerTreeAsTextDebug) {
746         writeIndent(ts, indent + 1);
747         ts << "(primary-layer-id " << primaryLayerID() << ")\n";
748         writeIndent(ts, indent + 1);
749         ts << "(client " << static_cast<void*>(&m_client) << ")\n";
750     }
751
752     if (m_backgroundColor.isValid() && m_client.shouldDumpPropertyForLayer(this, "backgroundColor")) {
753         writeIndent(ts, indent + 1);
754         ts << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n";
755     }
756
757     if (!m_transform.isIdentity()) {
758         writeIndent(ts, indent + 1);
759         ts << "(transform ";
760         ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] ";
761         ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] ";
762         ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] ";
763         ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n";
764     }
765
766     // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior
767     // differs between platforms.
768     if (parent() && !m_childrenTransform.isIdentity()) {
769         writeIndent(ts, indent + 1);
770         ts << "(childrenTransform ";
771         ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] ";
772         ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] ";
773         ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] ";
774         ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n";
775     }
776
777     if (m_replicaLayer) {
778         writeIndent(ts, indent + 1);
779         ts << "(replica layer";
780         if (behavior & LayerTreeAsTextDebug)
781             ts << " " << m_replicaLayer;
782         ts << ")\n";
783         m_replicaLayer->dumpLayer(ts, indent + 2, behavior);
784     }
785
786     if (m_replicatedLayer) {
787         writeIndent(ts, indent + 1);
788         ts << "(replicated layer";
789         if (behavior & LayerTreeAsTextDebug)
790             ts << " " << m_replicatedLayer;
791         ts << ")\n";
792     }
793
794     if (behavior & LayerTreeAsTextIncludeRepaintRects && repaintRectMap().contains(this) && !repaintRectMap().get(this).isEmpty() && m_client.shouldDumpPropertyForLayer(this, "repaintRects")) {
795         writeIndent(ts, indent + 1);
796         ts << "(repaint rects\n";
797         for (size_t i = 0; i < repaintRectMap().get(this).size(); ++i) {
798             if (repaintRectMap().get(this)[i].isEmpty())
799                 continue;
800             writeIndent(ts, indent + 2);
801             ts << "(rect ";
802             ts << repaintRectMap().get(this)[i].x() << " ";
803             ts << repaintRectMap().get(this)[i].y() << " ";
804             ts << repaintRectMap().get(this)[i].width() << " ";
805             ts << repaintRectMap().get(this)[i].height();
806             ts << ")\n";
807         }
808         writeIndent(ts, indent + 1);
809         ts << ")\n";
810     }
811
812     if (behavior & LayerTreeAsTextIncludePaintingPhases && paintingPhase()) {
813         writeIndent(ts, indent + 1);
814         ts << "(paintingPhases\n";
815         if (paintingPhase() & GraphicsLayerPaintBackground) {
816             writeIndent(ts, indent + 2);
817             ts << "GraphicsLayerPaintBackground\n";
818         }
819         if (paintingPhase() & GraphicsLayerPaintForeground) {
820             writeIndent(ts, indent + 2);
821             ts << "GraphicsLayerPaintForeground\n";
822         }
823         if (paintingPhase() & GraphicsLayerPaintMask) {
824             writeIndent(ts, indent + 2);
825             ts << "GraphicsLayerPaintMask\n";
826         }
827         if (paintingPhase() & GraphicsLayerPaintChildClippingMask) {
828             writeIndent(ts, indent + 2);
829             ts << "GraphicsLayerPaintChildClippingMask\n";
830         }
831         if (paintingPhase() & GraphicsLayerPaintOverflowContents) {
832             writeIndent(ts, indent + 2);
833             ts << "GraphicsLayerPaintOverflowContents\n";
834         }
835         if (paintingPhase() & GraphicsLayerPaintCompositedScroll) {
836             writeIndent(ts, indent + 2);
837             ts << "GraphicsLayerPaintCompositedScroll\n";
838         }
839         writeIndent(ts, indent + 1);
840         ts << ")\n";
841     }
842
843     dumpAdditionalProperties(ts, indent, behavior);
844     
845     if (m_children.size()) {
846         TextStream childrenStream;
847
848         unsigned totalChildCount = 0;
849         dumpChildren(childrenStream, m_children, totalChildCount, indent, behavior);
850
851         writeIndent(childrenStream, indent + 1);
852         childrenStream << ")\n";
853
854         if (totalChildCount) {
855             writeIndent(ts, indent + 1);
856             ts << "(children " << totalChildCount << "\n";
857             ts << childrenStream.release();
858         }
859     }
860 }
861
862 String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const
863 {
864     TextStream ts;
865
866     dumpLayer(ts, 0, behavior);
867     return ts.release();
868 }
869
870 } // namespace WebCore
871
872 #ifndef NDEBUG
873 void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer)
874 {
875     if (!layer)
876         return;
877
878     String output = layer->layerTreeAsText(WebCore::LayerTreeAsTextDebug | WebCore::LayerTreeAsTextIncludeVisibleRects | WebCore::LayerTreeAsTextIncludeTileCaches | WebCore::LayerTreeAsTextIncludeContentLayers);
879     fprintf(stderr, "%s\n", output.utf8().data());
880 }
881 #endif