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