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