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