2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #include "GraphicsLayer.h"
30 #include "FloatPoint.h"
31 #include "FloatRect.h"
32 #include "GraphicsContext.h"
33 #include "LayoutRect.h"
34 #include "RotateTransformOperation.h"
35 #include "TextStream.h"
36 #include <wtf/HashMap.h>
37 #include <wtf/text/CString.h>
38 #include <wtf/text/StringBuilder.h>
39 #include <wtf/text/WTFString.h>
47 typedef HashMap<const GraphicsLayer*, Vector<FloatRect>> RepaintMap;
48 static RepaintMap& repaintRectMap()
50 DEPRECATED_DEFINE_STATIC_LOCAL(RepaintMap, map, ());
54 void KeyframeValueList::insert(std::unique_ptr<const AnimationValue> value)
56 for (size_t i = 0; i < m_values.size(); ++i) {
57 const AnimationValue* curValue = m_values[i].get();
58 if (curValue->keyTime() == value->keyTime()) {
61 m_values.insert(i + 1, WTF::move(value));
64 if (curValue->keyTime() > value->keyTime()) {
66 m_values.insert(i, WTF::move(value));
71 m_values.append(WTF::move(value));
75 bool GraphicsLayer::supportsLayerType(Type type)
79 case Type::PageTiledBacking:
89 bool GraphicsLayer::supportsBackgroundColorContent()
91 #if USE(TEXTURE_MAPPER)
99 #if !USE(COORDINATED_GRAPHICS)
100 bool GraphicsLayer::supportsContentsTiling()
102 // FIXME: Enable the feature on different ports.
107 GraphicsLayer::GraphicsLayer(Type type, GraphicsLayerClient& client)
109 , m_anchorPoint(0.5f, 0.5f, 0)
112 #if ENABLE(CSS_COMPOSITING)
113 , m_blendMode(BlendModeNormal)
116 , m_contentsOpaque(false)
117 , m_preserves3D(false)
118 , m_backfaceVisibility(true)
119 , m_usingTiledBacking(false)
120 , m_masksToBounds(false)
121 , m_drawsContent(false)
122 , m_contentsVisible(true)
123 , m_acceleratesDrawing(false)
124 , m_appliesPageScale(false)
125 , m_showDebugBorder(false)
126 , m_showRepaintCounter(false)
127 , m_isMaskLayer(false)
128 , m_paintingPhase(GraphicsLayerPaintAllWithOverflowClip)
129 , m_contentsOrientation(CompositingCoordinatesTopDown)
131 , m_maskLayer(nullptr)
132 , m_replicaLayer(nullptr)
133 , m_replicatedLayer(nullptr)
135 , m_customAppearance(NoCustomAppearance)
138 m_client.verifyNotPainting();
142 GraphicsLayer::~GraphicsLayer()
144 resetTrackedRepaints();
145 ASSERT(!m_parent); // willBeDestroyed should have been called already.
148 void GraphicsLayer::willBeDestroyed()
151 m_client.verifyNotPainting();
154 m_replicaLayer->setReplicatedLayer(0);
156 if (m_replicatedLayer)
157 m_replicatedLayer->setReplicatedByLayer(0);
163 void GraphicsLayer::setParent(GraphicsLayer* layer)
165 ASSERT(!layer || !layer->hasAncestor(this));
169 bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const
171 for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) {
172 if (curr == ancestor)
179 bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren)
181 // If the contents of the arrays are the same, nothing to do.
182 if (newChildren == m_children)
187 size_t listSize = newChildren.size();
188 for (size_t i = 0; i < listSize; ++i)
189 addChild(newChildren[i]);
194 void GraphicsLayer::addChild(GraphicsLayer* childLayer)
196 ASSERT(childLayer != this);
198 if (childLayer->parent())
199 childLayer->removeFromParent();
201 childLayer->setParent(this);
202 m_children.append(childLayer);
205 void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index)
207 ASSERT(childLayer != this);
209 if (childLayer->parent())
210 childLayer->removeFromParent();
212 childLayer->setParent(this);
213 m_children.insert(index, childLayer);
216 void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
218 ASSERT(childLayer != this);
219 childLayer->removeFromParent();
222 for (unsigned i = 0; i < m_children.size(); i++) {
223 if (sibling == m_children[i]) {
224 m_children.insert(i, childLayer);
230 childLayer->setParent(this);
233 m_children.append(childLayer);
236 void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
238 childLayer->removeFromParent();
239 ASSERT(childLayer != this);
242 for (unsigned i = 0; i < m_children.size(); i++) {
243 if (sibling == m_children[i]) {
244 m_children.insert(i+1, childLayer);
250 childLayer->setParent(this);
253 m_children.append(childLayer);
256 bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
258 ASSERT(!newChild->parent());
260 for (unsigned i = 0; i < m_children.size(); i++) {
261 if (oldChild == m_children[i]) {
262 m_children[i] = newChild;
268 oldChild->setParent(0);
270 newChild->removeFromParent();
271 newChild->setParent(this);
277 void GraphicsLayer::removeAllChildren()
279 while (m_children.size()) {
280 GraphicsLayer* curLayer = m_children[0];
281 ASSERT(curLayer->parent());
282 curLayer->removeFromParent();
286 void GraphicsLayer::removeFromParent()
289 m_parent->m_children.removeFirst(this);
294 void GraphicsLayer::setMaskLayer(GraphicsLayer* layer)
296 if (layer == m_maskLayer)
300 layer->removeFromParent();
301 layer->setParent(this);
302 layer->setIsMaskLayer(true);
303 } else if (m_maskLayer) {
304 m_maskLayer->setParent(nullptr);
305 m_maskLayer->setIsMaskLayer(false);
311 Path GraphicsLayer::shapeLayerPath() const
314 return m_shapeLayerPath;
320 void GraphicsLayer::setShapeLayerPath(const Path& path)
323 m_shapeLayerPath = path;
329 WindRule GraphicsLayer::shapeLayerWindRule() const
332 return m_shapeLayerWindRule;
338 void GraphicsLayer::setShapeLayerWindRule(WindRule windRule)
341 m_shapeLayerWindRule = windRule;
343 UNUSED_PARAM(windRule);
347 void GraphicsLayer::noteDeviceOrPageScaleFactorChangedIncludingDescendants()
349 deviceOrPageScaleFactorChanged();
352 m_maskLayer->deviceOrPageScaleFactorChanged();
355 m_replicaLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
357 const Vector<GraphicsLayer*>& childLayers = children();
358 size_t numChildren = childLayers.size();
359 for (size_t i = 0; i < numChildren; ++i)
360 childLayers[i]->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
363 void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
365 if (m_replicaLayer == layer)
369 m_replicaLayer->setReplicatedLayer(0);
372 layer->setReplicatedLayer(this);
374 m_replicaLayer = layer;
377 void GraphicsLayer::setOffsetFromRenderer(const FloatSize& offset, ShouldSetNeedsDisplay shouldSetNeedsDisplay)
379 if (offset == m_offsetFromRenderer)
382 m_offsetFromRenderer = offset;
384 // If the compositing layer offset changes, we need to repaint.
385 if (shouldSetNeedsDisplay == SetNeedsDisplay)
389 void GraphicsLayer::setSize(const FloatSize& size)
396 if (shouldRepaintOnSizeChange())
400 void GraphicsLayer::setBackgroundColor(const Color& color)
402 m_backgroundColor = color;
405 void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const FloatRect& clip)
407 FloatSize offset = offsetFromRenderer();
408 context.translate(-offset);
410 FloatRect clipRect(clip);
411 clipRect.move(offset);
413 m_client.paintContents(this, context, m_paintingPhase, clipRect);
416 String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
418 // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
420 id.appendLiteral("-|transition");
421 id.appendNumber(static_cast<int>(property));
423 return id.toString();
426 void GraphicsLayer::suspendAnimations(double)
430 void GraphicsLayer::resumeAnimations()
434 void GraphicsLayer::getDebugBorderInfo(Color& color, float& width) const
436 if (drawsContent()) {
437 if (m_usingTiledBacking) {
438 color = Color(255, 128, 0, 128); // tiled layer: orange
443 color = Color(0, 128, 32, 128); // normal layer: green
448 if (usesContentsLayer()) {
449 color = Color(255, 150, 255, 200); // non-painting layer with contents: pink
454 if (masksToBounds()) {
455 color = Color(128, 255, 255, 48); // masking layer: pale blue
460 color = Color(255, 255, 0, 192); // container: yellow
464 void GraphicsLayer::updateDebugIndicators()
466 if (!isShowingDebugBorder())
471 getDebugBorderInfo(borderColor, width);
472 setDebugBorder(borderColor, width);
475 void GraphicsLayer::setZPosition(float position)
477 m_zPosition = position;
480 float GraphicsLayer::accumulatedOpacity() const
485 return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
488 void GraphicsLayer::distributeOpacity(float accumulatedOpacity)
490 // If this is a transform layer we need to distribute our opacity to all our children
492 // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own
493 // opacity to get the total contribution
494 accumulatedOpacity *= m_opacity;
496 setOpacityInternal(accumulatedOpacity);
499 size_t numChildren = children().size();
500 for (size_t i = 0; i < numChildren; ++i)
501 children()[i]->distributeOpacity(accumulatedOpacity);
505 static inline const FilterOperations& filterOperationsAt(const KeyframeValueList& valueList, size_t index)
507 return static_cast<const FilterAnimationValue&>(valueList.at(index)).value();
510 int GraphicsLayer::validateFilterOperations(const KeyframeValueList& valueList)
512 ASSERT(valueList.property() == AnimatedPropertyWebkitFilter);
514 if (valueList.size() < 2)
517 // Empty filters match anything, so find the first non-empty entry as the reference
518 size_t firstIndex = 0;
519 for ( ; firstIndex < valueList.size(); ++firstIndex) {
520 if (!filterOperationsAt(valueList, firstIndex).operations().isEmpty())
524 if (firstIndex >= valueList.size())
527 const FilterOperations& firstVal = filterOperationsAt(valueList, firstIndex);
529 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
530 const FilterOperations& val = filterOperationsAt(valueList, i);
532 // An emtpy filter list matches anything.
533 if (val.operations().isEmpty())
536 if (!firstVal.operationsMatch(val))
543 // An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
544 // The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
545 // true if the rotation between any two keyframes is >= 180 degrees.
547 static inline const TransformOperations& operationsAt(const KeyframeValueList& valueList, size_t index)
549 return static_cast<const TransformAnimationValue&>(valueList.at(index)).value();
552 int GraphicsLayer::validateTransformOperations(const KeyframeValueList& valueList, bool& hasBigRotation)
554 ASSERT(valueList.property() == AnimatedPropertyTransform);
556 hasBigRotation = false;
558 if (valueList.size() < 2)
561 // Empty transforms match anything, so find the first non-empty entry as the reference.
562 size_t firstIndex = 0;
563 for ( ; firstIndex < valueList.size(); ++firstIndex) {
564 if (!operationsAt(valueList, firstIndex).operations().isEmpty())
568 if (firstIndex >= valueList.size())
571 const TransformOperations& firstVal = operationsAt(valueList, firstIndex);
573 // See if the keyframes are valid.
574 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
575 const TransformOperations& val = operationsAt(valueList, i);
577 // An empty transform list matches anything.
578 if (val.operations().isEmpty())
581 if (!firstVal.operationsMatch(val))
585 // Keyframes are valid, check for big rotations.
586 double lastRotationAngle = 0.0;
587 double maxRotationAngle = -1.0;
589 for (size_t j = 0; j < firstVal.operations().size(); ++j) {
590 TransformOperation::OperationType type = firstVal.operations().at(j)->type();
592 // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
593 if (type == TransformOperation::ROTATE_X ||
594 type == TransformOperation::ROTATE_Y ||
595 type == TransformOperation::ROTATE_Z ||
596 type == TransformOperation::ROTATE_3D) {
597 lastRotationAngle = downcast<RotateTransformOperation>(*firstVal.operations().at(j)).angle();
599 if (maxRotationAngle < 0)
600 maxRotationAngle = fabs(lastRotationAngle);
602 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
603 const TransformOperations& val = operationsAt(valueList, i);
604 double rotationAngle = val.operations().isEmpty() ? 0 : downcast<RotateTransformOperation>(*val.operations().at(j)).angle();
605 double diffAngle = fabs(rotationAngle - lastRotationAngle);
606 if (diffAngle > maxRotationAngle)
607 maxRotationAngle = diffAngle;
608 lastRotationAngle = rotationAngle;
613 hasBigRotation = maxRotationAngle >= 180.0;
618 double GraphicsLayer::backingStoreMemoryEstimate() const
623 // Effects of page and device scale are ignored; subclasses should override to take these into account.
624 return static_cast<double>(4 * size().width()) * size().height();
627 void GraphicsLayer::resetTrackedRepaints()
629 repaintRectMap().remove(this);
632 void GraphicsLayer::addRepaintRect(const FloatRect& repaintRect)
634 if (!m_client.isTrackingRepaints())
637 FloatRect largestRepaintRect(FloatPoint(), m_size);
638 largestRepaintRect.intersect(repaintRect);
639 RepaintMap::iterator repaintIt = repaintRectMap().find(this);
640 if (repaintIt == repaintRectMap().end()) {
641 Vector<FloatRect> repaintRects;
642 repaintRects.append(largestRepaintRect);
643 repaintRectMap().set(this, repaintRects);
645 Vector<FloatRect>& repaintRects = repaintIt->value;
646 repaintRects.append(largestRepaintRect);
650 void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
652 writeIndent(ts, indent);
653 ts << "(" << "GraphicsLayer";
655 if (behavior & LayerTreeAsTextDebug) {
656 ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
657 ts << " \"" << m_name << "\"";
661 dumpProperties(ts, indent, behavior);
662 writeIndent(ts, indent);
666 static void dumpChildren(TextStream& ts, const Vector<GraphicsLayer*>& children, unsigned& totalChildCount, int indent, LayerTreeAsTextBehavior behavior)
668 totalChildCount += children.size();
669 for (auto* child : children) {
670 if (!child->client().shouldSkipLayerInDump(child, behavior)) {
671 child->dumpLayer(ts, indent + 2, behavior);
676 dumpChildren(ts, child->children(), totalChildCount, indent, behavior);
680 void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
682 if (m_position != FloatPoint()) {
683 writeIndent(ts, indent + 1);
684 ts << "(position " << m_position.x() << " " << m_position.y() << ")\n";
687 if (m_boundsOrigin != FloatPoint()) {
688 writeIndent(ts, indent + 1);
689 ts << "(bounds origin " << m_boundsOrigin.x() << " " << m_boundsOrigin.y() << ")\n";
692 if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) {
693 writeIndent(ts, indent + 1);
694 ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y();
695 if (m_anchorPoint.z())
696 ts << " " << m_anchorPoint.z();
700 if (m_size != IntSize()) {
701 writeIndent(ts, indent + 1);
702 ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
705 if (m_opacity != 1) {
706 writeIndent(ts, indent + 1);
707 ts << "(opacity " << m_opacity << ")\n";
710 #if ENABLE(CSS_COMPOSITING)
711 if (m_blendMode != BlendModeNormal) {
712 writeIndent(ts, indent + 1);
713 ts << "(blendMode " << compositeOperatorName(CompositeSourceOver, m_blendMode) << ")\n";
717 if (m_usingTiledBacking) {
718 writeIndent(ts, indent + 1);
719 ts << "(usingTiledLayer " << m_usingTiledBacking << ")\n";
722 bool needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack = m_client.needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack(*this);
723 if (m_contentsOpaque || needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack) {
724 writeIndent(ts, indent + 1);
725 ts << "(contentsOpaque " << (m_contentsOpaque || needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack) << ")\n";
729 writeIndent(ts, indent + 1);
730 ts << "(preserves3D " << m_preserves3D << ")\n";
733 if (m_drawsContent && m_client.shouldDumpPropertyForLayer(this, "drawsContent")) {
734 writeIndent(ts, indent + 1);
735 ts << "(drawsContent " << m_drawsContent << ")\n";
738 if (!m_contentsVisible) {
739 writeIndent(ts, indent + 1);
740 ts << "(contentsVisible " << m_contentsVisible << ")\n";
743 if (!m_backfaceVisibility) {
744 writeIndent(ts, indent + 1);
745 ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
748 if (behavior & LayerTreeAsTextDebug) {
749 writeIndent(ts, indent + 1);
750 ts << "(primary-layer-id " << primaryLayerID() << ")\n";
751 writeIndent(ts, indent + 1);
752 ts << "(client " << static_cast<void*>(&m_client) << ")\n";
755 if (m_backgroundColor.isValid() && m_client.shouldDumpPropertyForLayer(this, "backgroundColor")) {
756 writeIndent(ts, indent + 1);
757 ts << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n";
760 if (!m_transform.isIdentity()) {
761 writeIndent(ts, indent + 1);
763 ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] ";
764 ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] ";
765 ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] ";
766 ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n";
769 // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior
770 // differs between platforms.
771 if (parent() && !m_childrenTransform.isIdentity()) {
772 writeIndent(ts, indent + 1);
773 ts << "(childrenTransform ";
774 ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] ";
775 ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] ";
776 ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] ";
777 ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n";
780 if (m_replicaLayer) {
781 writeIndent(ts, indent + 1);
782 ts << "(replica layer";
783 if (behavior & LayerTreeAsTextDebug)
784 ts << " " << m_replicaLayer;
786 m_replicaLayer->dumpLayer(ts, indent + 2, behavior);
789 if (m_replicatedLayer) {
790 writeIndent(ts, indent + 1);
791 ts << "(replicated layer";
792 if (behavior & LayerTreeAsTextDebug)
793 ts << " " << m_replicatedLayer;
797 if (behavior & LayerTreeAsTextIncludeRepaintRects && repaintRectMap().contains(this) && !repaintRectMap().get(this).isEmpty() && m_client.shouldDumpPropertyForLayer(this, "repaintRects")) {
798 writeIndent(ts, indent + 1);
799 ts << "(repaint rects\n";
800 for (size_t i = 0; i < repaintRectMap().get(this).size(); ++i) {
801 if (repaintRectMap().get(this)[i].isEmpty())
803 writeIndent(ts, indent + 2);
805 ts << repaintRectMap().get(this)[i].x() << " ";
806 ts << repaintRectMap().get(this)[i].y() << " ";
807 ts << repaintRectMap().get(this)[i].width() << " ";
808 ts << repaintRectMap().get(this)[i].height();
811 writeIndent(ts, indent + 1);
815 if (behavior & LayerTreeAsTextIncludePaintingPhases && paintingPhase()) {
816 writeIndent(ts, indent + 1);
817 ts << "(paintingPhases\n";
818 if (paintingPhase() & GraphicsLayerPaintBackground) {
819 writeIndent(ts, indent + 2);
820 ts << "GraphicsLayerPaintBackground\n";
822 if (paintingPhase() & GraphicsLayerPaintForeground) {
823 writeIndent(ts, indent + 2);
824 ts << "GraphicsLayerPaintForeground\n";
826 if (paintingPhase() & GraphicsLayerPaintMask) {
827 writeIndent(ts, indent + 2);
828 ts << "GraphicsLayerPaintMask\n";
830 if (paintingPhase() & GraphicsLayerPaintChildClippingMask) {
831 writeIndent(ts, indent + 2);
832 ts << "GraphicsLayerPaintChildClippingMask\n";
834 if (paintingPhase() & GraphicsLayerPaintOverflowContents) {
835 writeIndent(ts, indent + 2);
836 ts << "GraphicsLayerPaintOverflowContents\n";
838 if (paintingPhase() & GraphicsLayerPaintCompositedScroll) {
839 writeIndent(ts, indent + 2);
840 ts << "GraphicsLayerPaintCompositedScroll\n";
842 writeIndent(ts, indent + 1);
846 dumpAdditionalProperties(ts, indent, behavior);
848 if (m_children.size()) {
849 TextStream childrenStream;
851 unsigned totalChildCount = 0;
852 dumpChildren(childrenStream, m_children, totalChildCount, indent, behavior);
854 writeIndent(childrenStream, indent + 1);
855 childrenStream << ")\n";
857 if (totalChildCount) {
858 writeIndent(ts, indent + 1);
859 ts << "(children " << totalChildCount << "\n";
860 ts << childrenStream.release();
865 String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const
869 dumpLayer(ts, 0, behavior);
873 } // namespace WebCore
876 void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer)
881 String output = layer->layerTreeAsText(WebCore::LayerTreeAsTextDebug | WebCore::LayerTreeAsTextIncludeVisibleRects | WebCore::LayerTreeAsTextIncludeTileCaches | WebCore::LayerTreeAsTextIncludeContentLayers);
882 fprintf(stderr, "%s\n", output.utf8().data());