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 <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>
48 typedef HashMap<const GraphicsLayer*, Vector<FloatRect>> RepaintMap;
49 static RepaintMap& repaintRectMap()
51 static NeverDestroyed<RepaintMap> map;
55 void KeyframeValueList::insert(std::unique_ptr<const AnimationValue> value)
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()) {
62 m_values.insert(i + 1, WTFMove(value));
65 if (curValue->keyTime() > value->keyTime()) {
67 m_values.insert(i, WTFMove(value));
72 m_values.append(WTFMove(value));
76 bool GraphicsLayer::supportsLayerType(Type type)
80 case Type::PageTiledBacking:
90 bool GraphicsLayer::supportsBackgroundColorContent()
92 #if USE(TEXTURE_MAPPER)
99 bool GraphicsLayer::supportsSubpixelAntialiasedLayerText()
105 #if !USE(COORDINATED_GRAPHICS)
106 bool GraphicsLayer::supportsContentsTiling()
108 // FIXME: Enable the feature on different ports.
113 // Singleton client used for layers on which clearClient has been called.
114 class EmptyGraphicsLayerClient : public GraphicsLayerClient {
116 static EmptyGraphicsLayerClient& singleton();
119 EmptyGraphicsLayerClient& EmptyGraphicsLayerClient::singleton()
121 static NeverDestroyed<EmptyGraphicsLayerClient> client;
125 GraphicsLayer::GraphicsLayer(Type type, GraphicsLayerClient& layerClient)
126 : m_client(&layerClient)
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)
147 client().verifyNotPainting();
151 GraphicsLayer::~GraphicsLayer()
153 resetTrackedRepaints();
154 ASSERT(!m_parent); // willBeDestroyed should have been called already.
157 void GraphicsLayer::unparentAndClear(RefPtr<GraphicsLayer>& layer)
160 layer->removeFromParent();
161 layer->clearClient();
166 void GraphicsLayer::clear(RefPtr<GraphicsLayer>& layer)
169 layer->clearClient();
174 void GraphicsLayer::willBeDestroyed()
176 m_beingDestroyed = true;
178 client().verifyNotPainting();
181 m_replicaLayer->setReplicatedLayer(nullptr);
183 if (m_replicatedLayer)
184 m_replicatedLayer->setReplicatedByLayer(nullptr);
187 m_maskLayer->setParent(nullptr);
188 m_maskLayer->setIsMaskLayer(false);
195 void GraphicsLayer::clearClient()
197 m_client = &EmptyGraphicsLayerClient::singleton();
200 void GraphicsLayer::setClient(GraphicsLayerClient& client)
205 void GraphicsLayer::setParent(GraphicsLayer* layer)
207 ASSERT(!layer || !layer->hasAncestor(this));
211 bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const
213 for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) {
214 if (curr == ancestor)
221 bool GraphicsLayer::setChildren(Vector<Ref<GraphicsLayer>>&& newChildren)
223 // If the contents of the arrays are the same, nothing to do.
224 if (newChildren == m_children)
229 size_t listSize = newChildren.size();
230 for (size_t i = 0; i < listSize; ++i)
231 addChild(WTFMove(newChildren[i]));
236 void GraphicsLayer::addChild(Ref<GraphicsLayer>&& childLayer)
238 ASSERT(childLayer.ptr() != this);
240 childLayer->removeFromParent();
241 childLayer->setParent(this);
242 m_children.append(WTFMove(childLayer));
245 void GraphicsLayer::addChildAtIndex(Ref<GraphicsLayer>&& childLayer, int index)
247 ASSERT(childLayer.ptr() != this);
249 childLayer->removeFromParent();
250 childLayer->setParent(this);
251 m_children.insert(index, WTFMove(childLayer));
254 void GraphicsLayer::addChildBelow(Ref<GraphicsLayer>&& childLayer, GraphicsLayer* sibling)
256 ASSERT(childLayer.ptr() != this);
257 childLayer->removeFromParent();
259 childLayer->setParent(this);
261 for (unsigned i = 0; i < m_children.size(); i++) {
262 if (sibling == m_children[i].ptr()) {
263 m_children.insert(i, WTFMove(childLayer));
268 m_children.append(WTFMove(childLayer));
271 void GraphicsLayer::addChildAbove(Ref<GraphicsLayer>&& childLayer, GraphicsLayer* sibling)
273 childLayer->removeFromParent();
274 ASSERT(childLayer.ptr() != this);
276 childLayer->setParent(this);
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));
285 m_children.append(WTFMove(childLayer));
288 bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, Ref<GraphicsLayer>&& newChild)
290 ASSERT(!newChild->parent());
292 GraphicsLayer* rawNewChild = newChild.ptr();
295 for (unsigned i = 0; i < m_children.size(); i++) {
296 if (oldChild == m_children[i].ptr()) {
297 m_children[i] = WTFMove(newChild);
303 oldChild->setParent(nullptr);
305 rawNewChild->removeFromParent();
306 rawNewChild->setParent(this);
312 void GraphicsLayer::removeAllChildren()
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.
322 void GraphicsLayer::removeFromParent()
325 GraphicsLayer* parent = m_parent;
327 parent->m_children.removeFirstMatching([this](auto& layer) {
328 return layer.ptr() == this;
330 // |this| may be destroyed here.
334 const TransformationMatrix& GraphicsLayer::transform() const
336 return m_transform ? *m_transform : TransformationMatrix::identity;
339 void GraphicsLayer::setTransform(const TransformationMatrix& matrix)
342 *m_transform = matrix;
344 m_transform = std::make_unique<TransformationMatrix>(matrix);
347 const TransformationMatrix& GraphicsLayer::childrenTransform() const
349 return m_childrenTransform ? *m_childrenTransform : TransformationMatrix::identity;
352 void GraphicsLayer::setChildrenTransform(const TransformationMatrix& matrix)
354 if (m_childrenTransform)
355 *m_childrenTransform = matrix;
357 m_childrenTransform = std::make_unique<TransformationMatrix>(matrix);
360 void GraphicsLayer::setMaskLayer(RefPtr<GraphicsLayer>&& layer)
362 if (layer == m_maskLayer)
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);
374 m_maskLayer = WTFMove(layer);
377 Path GraphicsLayer::shapeLayerPath() const
380 return m_shapeLayerPath;
386 void GraphicsLayer::setShapeLayerPath(const Path& path)
389 m_shapeLayerPath = path;
395 WindRule GraphicsLayer::shapeLayerWindRule() const
398 return m_shapeLayerWindRule;
400 return WindRule::NonZero;
404 void GraphicsLayer::setShapeLayerWindRule(WindRule windRule)
407 m_shapeLayerWindRule = windRule;
409 UNUSED_PARAM(windRule);
413 void GraphicsLayer::noteDeviceOrPageScaleFactorChangedIncludingDescendants()
415 deviceOrPageScaleFactorChanged();
418 m_maskLayer->deviceOrPageScaleFactorChanged();
421 m_replicaLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
423 for (auto& layer : children())
424 layer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
427 void GraphicsLayer::setIsInWindow(bool inWindow)
429 if (TiledBacking* tiledBacking = this->tiledBacking())
430 tiledBacking->setIsInWindow(inWindow);
433 void GraphicsLayer::setReplicatedByLayer(RefPtr<GraphicsLayer>&& layer)
435 if (m_replicaLayer == layer)
439 m_replicaLayer->setReplicatedLayer(nullptr);
442 layer->setReplicatedLayer(this);
444 m_replicaLayer = WTFMove(layer);
447 void GraphicsLayer::setOffsetFromRenderer(const FloatSize& offset, ShouldSetNeedsDisplay shouldSetNeedsDisplay)
449 if (offset == m_offsetFromRenderer)
452 m_offsetFromRenderer = offset;
454 // If the compositing layer offset changes, we need to repaint.
455 if (shouldSetNeedsDisplay == SetNeedsDisplay)
459 void GraphicsLayer::setSize(const FloatSize& size)
466 if (shouldRepaintOnSizeChange())
470 void GraphicsLayer::setBackgroundColor(const Color& color)
472 m_backgroundColor = color;
475 void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const FloatRect& clip, GraphicsLayerPaintBehavior layerPaintBehavior)
477 FloatSize offset = offsetFromRenderer();
478 context.translate(-offset);
480 FloatRect clipRect(clip);
481 clipRect.move(offset);
483 client().paintContents(this, context, m_paintingPhase, clipRect, layerPaintBehavior);
486 String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
488 // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
490 id.appendLiteral("-|transition");
491 id.appendNumber(static_cast<int>(property));
493 return id.toString();
496 void GraphicsLayer::suspendAnimations(MonotonicTime)
500 void GraphicsLayer::resumeAnimations()
504 void GraphicsLayer::getDebugBorderInfo(Color& color, float& width) const
508 if (needsBackdrop()) {
509 color = Color(255, 0, 255, 128); // has backdrop: magenta
514 if (drawsContent()) {
515 if (tiledBacking()) {
516 color = Color(255, 128, 0, 128); // tiled layer: orange
520 color = Color(0, 128, 32, 128); // normal layer: green
524 if (usesContentsLayer()) {
525 color = Color(0, 64, 128, 150); // non-painting layer with contents: blue
530 if (masksToBounds()) {
531 color = Color(128, 255, 255, 48); // masking layer: pale blue
536 color = Color(255, 255, 0, 192); // container: yellow
539 void GraphicsLayer::updateDebugIndicators()
541 if (!isShowingDebugBorder())
546 getDebugBorderInfo(borderColor, width);
547 setDebugBorder(borderColor, width);
550 void GraphicsLayer::setZPosition(float position)
552 m_zPosition = position;
555 float GraphicsLayer::accumulatedOpacity() const
560 return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
563 void GraphicsLayer::distributeOpacity(float accumulatedOpacity)
565 // If this is a transform layer we need to distribute our opacity to all our children
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;
571 setOpacityInternal(accumulatedOpacity);
574 for (auto& layer : children())
575 layer->distributeOpacity(accumulatedOpacity);
579 static inline const FilterOperations& filterOperationsAt(const KeyframeValueList& valueList, size_t index)
581 return static_cast<const FilterAnimationValue&>(valueList.at(index)).value();
584 int GraphicsLayer::validateFilterOperations(const KeyframeValueList& valueList)
586 #if ENABLE(FILTERS_LEVEL_2)
587 ASSERT(valueList.property() == AnimatedPropertyFilter || valueList.property() == AnimatedPropertyWebkitBackdropFilter);
589 ASSERT(valueList.property() == AnimatedPropertyFilter);
592 if (valueList.size() < 2)
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())
602 if (firstIndex >= valueList.size())
605 const FilterOperations& firstVal = filterOperationsAt(valueList, firstIndex);
607 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
608 const FilterOperations& val = filterOperationsAt(valueList, i);
610 // An emtpy filter list matches anything.
611 if (val.operations().isEmpty())
614 if (!firstVal.operationsMatch(val))
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.
625 static inline const TransformOperations& operationsAt(const KeyframeValueList& valueList, size_t index)
627 return static_cast<const TransformAnimationValue&>(valueList.at(index)).value();
630 int GraphicsLayer::validateTransformOperations(const KeyframeValueList& valueList, bool& hasBigRotation)
632 ASSERT(valueList.property() == AnimatedPropertyTransform);
634 hasBigRotation = false;
636 if (valueList.size() < 2)
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())
646 if (firstIndex >= valueList.size())
649 const TransformOperations& firstVal = operationsAt(valueList, firstIndex);
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);
655 // An empty transform list matches anything.
656 if (val.operations().isEmpty())
659 if (!firstVal.operationsMatch(val))
663 // Keyframes are valid, check for big rotations.
664 double lastRotationAngle = 0.0;
665 double maxRotationAngle = -1.0;
667 for (size_t j = 0; j < firstVal.operations().size(); ++j) {
668 TransformOperation::OperationType type = firstVal.operations().at(j)->type();
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();
677 if (maxRotationAngle < 0)
678 maxRotationAngle = fabs(lastRotationAngle);
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;
691 hasBigRotation = maxRotationAngle >= 180.0;
696 double GraphicsLayer::backingStoreMemoryEstimate() const
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();
705 void GraphicsLayer::resetTrackedRepaints()
707 repaintRectMap().remove(this);
710 void GraphicsLayer::addRepaintRect(const FloatRect& repaintRect)
712 if (!client().isTrackingRepaints())
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);
723 Vector<FloatRect>& repaintRects = repaintIt->value;
724 repaintRects.append(largestRepaintRect);
728 void GraphicsLayer::traverse(GraphicsLayer& layer, const WTF::Function<void (GraphicsLayer&)>& traversalFunc)
730 traversalFunc(layer);
732 for (auto& childLayer : layer.children())
733 traverse(childLayer.get(), traversalFunc);
735 if (auto* replicaLayer = layer.replicaLayer())
736 traverse(*replicaLayer, traversalFunc);
738 if (auto* maskLayer = layer.maskLayer())
739 traverse(*maskLayer, traversalFunc);
742 void GraphicsLayer::dumpLayer(TextStream& ts, LayerTreeAsTextBehavior behavior) const
744 ts << indent << "(" << "GraphicsLayer";
746 if (behavior & LayerTreeAsTextDebug) {
747 ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
748 ts << " \"" << m_name << "\"";
752 dumpProperties(ts, behavior);
753 ts << indent << ")\n";
756 static void dumpChildren(TextStream& ts, const Vector<Ref<GraphicsLayer>>& children, unsigned& totalChildCount, LayerTreeAsTextBehavior behavior)
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);
767 dumpChildren(ts, child->children(), totalChildCount, behavior);
771 void GraphicsLayer::dumpProperties(TextStream& ts, LayerTreeAsTextBehavior behavior) const
773 TextStream::IndentScope indentScope(ts);
774 if (!m_offsetFromRenderer.isZero())
775 ts << indent << "(offsetFromRenderer " << m_offsetFromRenderer << ")\n";
777 if (m_position != FloatPoint())
778 ts << indent << "(position " << m_position.x() << " " << m_position.y() << ")\n";
780 if (m_approximatePosition)
781 ts << indent << "(approximate position " << m_approximatePosition.value().x() << " " << m_approximatePosition.value().y() << ")\n";
783 if (m_boundsOrigin != FloatPoint())
784 ts << indent << "(bounds origin " << m_boundsOrigin.x() << " " << m_boundsOrigin.y() << ")\n";
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();
793 if (m_size != IntSize())
794 ts << indent << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
797 ts << indent << "(opacity " << m_opacity << ")\n";
799 #if ENABLE(CSS_COMPOSITING)
800 if (m_blendMode != BlendMode::Normal)
801 ts << indent << "(blendMode " << compositeOperatorName(CompositeSourceOver, m_blendMode) << ")\n";
804 if (type() == Type::Normal && tiledBacking())
805 ts << indent << "(usingTiledLayer 1)\n";
807 bool needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack = client().needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack(*this);
808 if (m_contentsOpaque || needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack)
809 ts << indent << "(contentsOpaque " << (m_contentsOpaque || needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack) << ")\n";
811 if (m_supportsSubpixelAntialiasedText)
812 ts << indent << "(supports subpixel antialiased text " << m_supportsSubpixelAntialiasedText << ")\n";
815 ts << indent << "(preserves3D " << m_preserves3D << ")\n";
817 if (m_drawsContent && client().shouldDumpPropertyForLayer(this, "drawsContent"))
818 ts << indent << "(drawsContent " << m_drawsContent << ")\n";
820 if (!m_contentsVisible)
821 ts << indent << "(contentsVisible " << m_contentsVisible << ")\n";
823 if (!m_backfaceVisibility)
824 ts << indent << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
826 if (behavior & LayerTreeAsTextDebug) {
827 ts << indent << "(primary-layer-id " << primaryLayerID() << ")\n";
828 ts << indent << "(client " << static_cast<void*>(m_client) << ")\n";
831 if (m_backgroundColor.isValid() && client().shouldDumpPropertyForLayer(this, "backgroundColor"))
832 ts << indent << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n";
834 if (behavior & LayerTreeAsTextIncludeAcceleratesDrawing && m_acceleratesDrawing)
835 ts << indent << "(acceleratesDrawing " << m_acceleratesDrawing << ")\n";
837 if (behavior & LayerTreeAsTextIncludeBackingStoreAttached)
838 ts << indent << "(backingStoreAttached " << backingStoreAttachedForTesting() << ")\n";
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";
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";
859 ts << indent << "(mask layer";
860 if (behavior & LayerTreeAsTextDebug)
861 ts << " " << m_maskLayer;
864 TextStream::IndentScope indentScope(ts);
865 m_maskLayer->dumpLayer(ts, behavior);
868 if (m_replicaLayer) {
869 ts << indent << "(replica layer";
870 if (behavior & LayerTreeAsTextDebug)
871 ts << " " << m_replicaLayer;
874 TextStream::IndentScope indentScope(ts);
875 m_replicaLayer->dumpLayer(ts, behavior);
878 if (m_replicatedLayer) {
879 ts << indent << "(replicated layer";
880 if (behavior & LayerTreeAsTextDebug)
881 ts << " " << m_replicatedLayer;
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())
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();
899 ts << indent << ")\n";
902 if (behavior & LayerTreeAsTextIncludePaintingPhases && paintingPhase()) {
903 ts << indent << "(paintingPhases\n";
904 TextStream::IndentScope indentScope(ts);
905 if (paintingPhase() & GraphicsLayerPaintBackground)
906 ts << indent << "GraphicsLayerPaintBackground\n";
908 if (paintingPhase() & GraphicsLayerPaintForeground)
909 ts << indent << "GraphicsLayerPaintForeground\n";
911 if (paintingPhase() & GraphicsLayerPaintMask)
912 ts << indent << "GraphicsLayerPaintMask\n";
914 if (paintingPhase() & GraphicsLayerPaintChildClippingMask)
915 ts << indent << "GraphicsLayerPaintChildClippingMask\n";
917 if (paintingPhase() & GraphicsLayerPaintOverflowContents)
918 ts << indent << "GraphicsLayerPaintOverflowContents\n";
920 if (paintingPhase() & GraphicsLayerPaintCompositedScroll)
921 ts << indent << "GraphicsLayerPaintCompositedScroll\n";
923 ts << indent << ")\n";
926 dumpAdditionalProperties(ts, behavior);
928 if (m_children.size()) {
929 TextStream childrenStream;
931 childrenStream.increaseIndent(ts.indent());
932 unsigned totalChildCount = 0;
933 dumpChildren(childrenStream, m_children, totalChildCount, behavior);
935 if (totalChildCount) {
936 ts << indent << "(children " << totalChildCount << "\n";
937 ts << childrenStream.release();
938 ts << indent << ")\n";
943 TextStream& operator<<(TextStream& ts, const Vector<GraphicsLayer::PlatformLayerID>& layers)
945 for (size_t i = 0; i < layers.size(); ++i) {
954 TextStream& operator<<(TextStream& ts, const WebCore::GraphicsLayer::CustomAppearance& customAppearance)
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;
966 String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const
968 TextStream ts(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
970 dumpLayer(ts, behavior);
974 } // namespace WebCore
976 #if ENABLE(TREE_DEBUGGING)
977 void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer)
982 String output = layer->layerTreeAsText(WebCore::LayerTreeAsTextShowAll);
983 fprintf(stderr, "%s\n", output.utf8().data());