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