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/text/CString.h> 38#include <wtf/text/StringBuilder.h> 39#include <wtf/text/WTFString.h> 40 41#ifndef NDEBUG 42#include <stdio.h> 43#endif 44 45namespace WebCore { 46 47typedef HashMap<const GraphicsLayer*, Vector<FloatRect>> RepaintMap; 48static RepaintMap& repaintRectMap() 49{ 50 DEPRECATED_DEFINE_STATIC_LOCAL(RepaintMap, map, ()); 51 return map; 52} 53 54void KeyframeValueList::insert(PassOwnPtr<const AnimationValue> value) 55{ 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()) { 59 ASSERT_NOT_REACHED(); 60 // insert after 61 m_values.insert(i + 1, value); 62 return; 63 } 64 if (curValue->keyTime() > value->keyTime()) { 65 // insert before 66 m_values.insert(i, value); 67 return; 68 } 69 } 70 71 m_values.append(value); 72} 73 74GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client) 75 : m_client(client) 76 , m_anchorPoint(0.5f, 0.5f, 0) 77 , m_opacity(1) 78 , m_zPosition(0) 79#if ENABLE(CSS_COMPOSITING) 80 , m_blendMode(BlendModeNormal) 81#endif 82 , m_contentsOpaque(false) 83 , m_preserves3D(false) 84 , m_backfaceVisibility(true) 85 , m_usingTiledBacking(false) 86 , m_masksToBounds(false) 87 , m_drawsContent(false) 88 , m_contentsVisible(true) 89 , m_acceleratesDrawing(false) 90 , m_appliesPageScale(false) 91 , m_showDebugBorder(false) 92 , m_showRepaintCounter(false) 93 , m_isMaskLayer(false) 94 , m_paintingPhase(GraphicsLayerPaintAllWithOverflowClip) 95 , m_contentsOrientation(CompositingCoordinatesTopDown) 96 , m_parent(0) 97 , m_maskLayer(0) 98 , m_replicaLayer(0) 99 , m_replicatedLayer(0) 100 , m_repaintCount(0) 101 , m_customAppearance(NoCustomAppearance) 102 , m_customBehavior(NoCustomBehavior) 103{ 104#ifndef NDEBUG 105 m_client.verifyNotPainting(); 106#endif 107} 108 109GraphicsLayer::~GraphicsLayer() 110{ 111 resetTrackedRepaints(); 112 ASSERT(!m_parent); // willBeDestroyed should have been called already. 113} 114 115void GraphicsLayer::willBeDestroyed() 116{ 117#ifndef NDEBUG 118 m_client.verifyNotPainting(); 119#endif 120 if (m_replicaLayer) 121 m_replicaLayer->setReplicatedLayer(0); 122 123 if (m_replicatedLayer) 124 m_replicatedLayer->setReplicatedByLayer(0); 125 126 removeAllChildren(); 127 removeFromParent(); 128} 129 130void GraphicsLayer::setParent(GraphicsLayer* layer) 131{ 132 ASSERT(!layer || !layer->hasAncestor(this)); 133 m_parent = layer; 134} 135 136bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const 137{ 138 for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) { 139 if (curr == ancestor) 140 return true; 141 } 142 143 return false; 144} 145 146bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren) 147{ 148 // If the contents of the arrays are the same, nothing to do. 149 if (newChildren == m_children) 150 return false; 151 152 removeAllChildren(); 153 154 size_t listSize = newChildren.size(); 155 for (size_t i = 0; i < listSize; ++i) 156 addChild(newChildren[i]); 157 158 return true; 159} 160 161void GraphicsLayer::addChild(GraphicsLayer* childLayer) 162{ 163 ASSERT(childLayer != this); 164 165 if (childLayer->parent()) 166 childLayer->removeFromParent(); 167 168 childLayer->setParent(this); 169 m_children.append(childLayer); 170} 171 172void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index) 173{ 174 ASSERT(childLayer != this); 175 176 if (childLayer->parent()) 177 childLayer->removeFromParent(); 178 179 childLayer->setParent(this); 180 m_children.insert(index, childLayer); 181} 182 183void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) 184{ 185 ASSERT(childLayer != this); 186 childLayer->removeFromParent(); 187 188 bool found = false; 189 for (unsigned i = 0; i < m_children.size(); i++) { 190 if (sibling == m_children[i]) { 191 m_children.insert(i, childLayer); 192 found = true; 193 break; 194 } 195 } 196 197 childLayer->setParent(this); 198 199 if (!found) 200 m_children.append(childLayer); 201} 202 203void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling) 204{ 205 childLayer->removeFromParent(); 206 ASSERT(childLayer != this); 207 208 bool found = false; 209 for (unsigned i = 0; i < m_children.size(); i++) { 210 if (sibling == m_children[i]) { 211 m_children.insert(i+1, childLayer); 212 found = true; 213 break; 214 } 215 } 216 217 childLayer->setParent(this); 218 219 if (!found) 220 m_children.append(childLayer); 221} 222 223bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) 224{ 225 ASSERT(!newChild->parent()); 226 bool found = false; 227 for (unsigned i = 0; i < m_children.size(); i++) { 228 if (oldChild == m_children[i]) { 229 m_children[i] = newChild; 230 found = true; 231 break; 232 } 233 } 234 if (found) { 235 oldChild->setParent(0); 236 237 newChild->removeFromParent(); 238 newChild->setParent(this); 239 return true; 240 } 241 return false; 242} 243 244void GraphicsLayer::removeAllChildren() 245{ 246 while (m_children.size()) { 247 GraphicsLayer* curLayer = m_children[0]; 248 ASSERT(curLayer->parent()); 249 curLayer->removeFromParent(); 250 } 251} 252 253void GraphicsLayer::removeFromParent() 254{ 255 if (m_parent) { 256 unsigned i; 257 for (i = 0; i < m_parent->m_children.size(); i++) { 258 if (this == m_parent->m_children[i]) { 259 m_parent->m_children.remove(i); 260 break; 261 } 262 } 263 264 setParent(nullptr); 265 } 266} 267 268void GraphicsLayer::setMaskLayer(GraphicsLayer* layer) 269{ 270 if (layer == m_maskLayer) 271 return; 272 273 if (layer) { 274 layer->removeFromParent(); 275 layer->setParent(this); 276 layer->setIsMaskLayer(true); 277 } else if (m_maskLayer) { 278 m_maskLayer->setParent(nullptr); 279 m_maskLayer->setIsMaskLayer(false); 280 } 281 282 m_maskLayer = layer; 283} 284 285void GraphicsLayer::noteDeviceOrPageScaleFactorChangedIncludingDescendants() 286{ 287 deviceOrPageScaleFactorChanged(); 288 289 if (m_maskLayer) 290 m_maskLayer->deviceOrPageScaleFactorChanged(); 291 292 if (m_replicaLayer) 293 m_replicaLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants(); 294 295 const Vector<GraphicsLayer*>& childLayers = children(); 296 size_t numChildren = childLayers.size(); 297 for (size_t i = 0; i < numChildren; ++i) 298 childLayers[i]->noteDeviceOrPageScaleFactorChangedIncludingDescendants(); 299} 300 301void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer) 302{ 303 if (m_replicaLayer == layer) 304 return; 305 306 if (m_replicaLayer) 307 m_replicaLayer->setReplicatedLayer(0); 308 309 if (layer) 310 layer->setReplicatedLayer(this); 311 312 m_replicaLayer = layer; 313} 314 315void GraphicsLayer::setOffsetFromRenderer(const FloatSize& offset, ShouldSetNeedsDisplay shouldSetNeedsDisplay) 316{ 317 if (offset == m_offsetFromRenderer) 318 return; 319 320 m_offsetFromRenderer = offset; 321 322 // If the compositing layer offset changes, we need to repaint. 323 if (shouldSetNeedsDisplay == SetNeedsDisplay) 324 setNeedsDisplay(); 325} 326 327void GraphicsLayer::setSize(const FloatSize& size) 328{ 329 if (size == m_size) 330 return; 331 332 m_size = size; 333 334 if (shouldRepaintOnSizeChange()) 335 setNeedsDisplay(); 336} 337 338void GraphicsLayer::setBackgroundColor(const Color& color) 339{ 340 m_backgroundColor = color; 341} 342 343void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const FloatRect& clip) 344{ 345 FloatSize offset = offsetFromRenderer(); 346 context.translate(-offset); 347 348 FloatRect clipRect(clip); 349 clipRect.move(offset); 350 351 m_client.paintContents(this, context, m_paintingPhase, clipRect); 352} 353 354String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property) 355{ 356 // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier. 357 StringBuilder id; 358 id.appendLiteral("-|transition"); 359 id.appendNumber(static_cast<int>(property)); 360 id.append('-'); 361 return id.toString(); 362} 363 364void GraphicsLayer::suspendAnimations(double) 365{ 366} 367 368void GraphicsLayer::resumeAnimations() 369{ 370} 371 372void GraphicsLayer::getDebugBorderInfo(Color& color, float& width) const 373{ 374 if (drawsContent()) { 375 if (m_usingTiledBacking) { 376 color = Color(255, 128, 0, 128); // tiled layer: orange 377 width = 2; 378 return; 379 } 380 381 color = Color(0, 128, 32, 128); // normal layer: green 382 width = 2; 383 return; 384 } 385 386 if (usesContentsLayer()) { 387 color = Color(255, 150, 255, 200); // non-painting layer with contents: pink 388 width = 2; 389 return; 390 } 391 392 if (masksToBounds()) { 393 color = Color(128, 255, 255, 48); // masking layer: pale blue 394 width = 20; 395 return; 396 } 397 398 color = Color(255, 255, 0, 192); // container: yellow 399 width = 2; 400} 401 402void GraphicsLayer::updateDebugIndicators() 403{ 404 if (!isShowingDebugBorder()) 405 return; 406 407 Color borderColor; 408 float width = 0; 409 getDebugBorderInfo(borderColor, width); 410 setDebugBorder(borderColor, width); 411} 412 413void GraphicsLayer::setZPosition(float position) 414{ 415 m_zPosition = position; 416} 417 418float GraphicsLayer::accumulatedOpacity() const 419{ 420 if (!preserves3D()) 421 return 1; 422 423 return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1); 424} 425 426void GraphicsLayer::distributeOpacity(float accumulatedOpacity) 427{ 428 // If this is a transform layer we need to distribute our opacity to all our children 429 430 // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own 431 // opacity to get the total contribution 432 accumulatedOpacity *= m_opacity; 433 434 setOpacityInternal(accumulatedOpacity); 435 436 if (preserves3D()) { 437 size_t numChildren = children().size(); 438 for (size_t i = 0; i < numChildren; ++i) 439 children()[i]->distributeOpacity(accumulatedOpacity); 440 } 441} 442 443#if ENABLE(CSS_FILTERS) 444static inline const FilterOperations& filterOperationsAt(const KeyframeValueList& valueList, size_t index) 445{ 446 return static_cast<const FilterAnimationValue&>(valueList.at(index)).value(); 447} 448 449int GraphicsLayer::validateFilterOperations(const KeyframeValueList& valueList) 450{ 451 ASSERT(valueList.property() == AnimatedPropertyWebkitFilter); 452 453 if (valueList.size() < 2) 454 return -1; 455 456 // Empty filters match anything, so find the first non-empty entry as the reference 457 size_t firstIndex = 0; 458 for ( ; firstIndex < valueList.size(); ++firstIndex) { 459 if (!filterOperationsAt(valueList, firstIndex).operations().isEmpty()) 460 break; 461 } 462 463 if (firstIndex >= valueList.size()) 464 return -1; 465 466 const FilterOperations& firstVal = filterOperationsAt(valueList, firstIndex); 467 468 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) { 469 const FilterOperations& val = filterOperationsAt(valueList, i); 470 471 // An emtpy filter list matches anything. 472 if (val.operations().isEmpty()) 473 continue; 474 475 if (!firstVal.operationsMatch(val)) 476 return -1; 477 } 478 479 return firstIndex; 480} 481#endif 482 483// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix 484// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is 485// true if the rotation between any two keyframes is >= 180 degrees. 486 487static inline const TransformOperations& operationsAt(const KeyframeValueList& valueList, size_t index) 488{ 489 return static_cast<const TransformAnimationValue&>(valueList.at(index)).value(); 490} 491 492int GraphicsLayer::validateTransformOperations(const KeyframeValueList& valueList, bool& hasBigRotation) 493{ 494 ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); 495 496 hasBigRotation = false; 497 498 if (valueList.size() < 2) 499 return -1; 500 501 // Empty transforms match anything, so find the first non-empty entry as the reference. 502 size_t firstIndex = 0; 503 for ( ; firstIndex < valueList.size(); ++firstIndex) { 504 if (!operationsAt(valueList, firstIndex).operations().isEmpty()) 505 break; 506 } 507 508 if (firstIndex >= valueList.size()) 509 return -1; 510 511 const TransformOperations& firstVal = operationsAt(valueList, firstIndex); 512 513 // See if the keyframes are valid. 514 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) { 515 const TransformOperations& val = operationsAt(valueList, i); 516 517 // An empty transform list matches anything. 518 if (val.operations().isEmpty()) 519 continue; 520 521 if (!firstVal.operationsMatch(val)) 522 return -1; 523 } 524 525 // Keyframes are valid, check for big rotations. 526 double lastRotAngle = 0.0; 527 double maxRotAngle = -1.0; 528 529 for (size_t j = 0; j < firstVal.operations().size(); ++j) { 530 TransformOperation::OperationType type = firstVal.operations().at(j)->type(); 531 532 // if this is a rotation entry, we need to see if any angle differences are >= 180 deg 533 if (type == TransformOperation::ROTATE_X || 534 type == TransformOperation::ROTATE_Y || 535 type == TransformOperation::ROTATE_Z || 536 type == TransformOperation::ROTATE_3D) { 537 lastRotAngle = toRotateTransformOperation(firstVal.operations().at(j).get())->angle(); 538 539 if (maxRotAngle < 0) 540 maxRotAngle = fabs(lastRotAngle); 541 542 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) { 543 const TransformOperations& val = operationsAt(valueList, i); 544 double rotAngle = val.operations().isEmpty() ? 0 : (toRotateTransformOperation(val.operations().at(j).get())->angle()); 545 double diffAngle = fabs(rotAngle - lastRotAngle); 546 if (diffAngle > maxRotAngle) 547 maxRotAngle = diffAngle; 548 lastRotAngle = rotAngle; 549 } 550 } 551 } 552 553 hasBigRotation = maxRotAngle >= 180.0; 554 555 return firstIndex; 556} 557 558double GraphicsLayer::backingStoreMemoryEstimate() const 559{ 560 if (!drawsContent()) 561 return 0; 562 563 // Effects of page and device scale are ignored; subclasses should override to take these into account. 564 return static_cast<double>(4 * size().width()) * size().height(); 565} 566 567void GraphicsLayer::resetTrackedRepaints() 568{ 569 repaintRectMap().remove(this); 570} 571 572void GraphicsLayer::addRepaintRect(const FloatRect& repaintRect) 573{ 574 if (m_client.isTrackingRepaints()) { 575 FloatRect largestRepaintRect(FloatPoint(), m_size); 576 largestRepaintRect.intersect(repaintRect); 577 RepaintMap::iterator repaintIt = repaintRectMap().find(this); 578 if (repaintIt == repaintRectMap().end()) { 579 Vector<FloatRect> repaintRects; 580 repaintRects.append(largestRepaintRect); 581 repaintRectMap().set(this, repaintRects); 582 } else { 583 Vector<FloatRect>& repaintRects = repaintIt->value; 584 repaintRects.append(largestRepaintRect); 585 } 586 } 587} 588 589void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const 590{ 591 writeIndent(ts, indent); 592 ts << "(" << "GraphicsLayer"; 593 594 if (behavior & LayerTreeAsTextDebug) { 595 ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this)); 596 ts << " \"" << m_name << "\""; 597 } 598 599 ts << "\n"; 600 dumpProperties(ts, indent, behavior); 601 writeIndent(ts, indent); 602 ts << ")\n"; 603} 604 605static void dumpChildren(TextStream& ts, const Vector<GraphicsLayer*>& children, unsigned& totalChildCount, int indent, LayerTreeAsTextBehavior behavior) 606{ 607 totalChildCount += children.size(); 608 for (auto* child : children) { 609 if (!child->client().shouldSkipLayerInDump(child)) { 610 child->dumpLayer(ts, indent + 2, behavior); 611 continue; 612 } 613 614 totalChildCount--; 615 dumpChildren(ts, child->children(), totalChildCount, indent, behavior); 616 } 617} 618 619void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const 620{ 621 if (m_position != FloatPoint()) { 622 writeIndent(ts, indent + 1); 623 ts << "(position " << m_position.x() << " " << m_position.y() << ")\n"; 624 } 625 626 if (m_boundsOrigin != FloatPoint()) { 627 writeIndent(ts, indent + 1); 628 ts << "(bounds origin " << m_boundsOrigin.x() << " " << m_boundsOrigin.y() << ")\n"; 629 } 630 631 if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) { 632 writeIndent(ts, indent + 1); 633 ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n"; 634 } 635 636 if (m_size != IntSize()) { 637 writeIndent(ts, indent + 1); 638 ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n"; 639 } 640 641 if (m_opacity != 1) { 642 writeIndent(ts, indent + 1); 643 ts << "(opacity " << m_opacity << ")\n"; 644 } 645 646#if ENABLE(CSS_COMPOSITING) 647 if (m_blendMode != BlendModeNormal) { 648 writeIndent(ts, indent + 1); 649 ts << "(blendMode " << compositeOperatorName(CompositeSourceOver, m_blendMode) << ")\n"; 650 } 651#endif 652 653 if (m_usingTiledBacking) { 654 writeIndent(ts, indent + 1); 655 ts << "(usingTiledLayer " << m_usingTiledBacking << ")\n"; 656 } 657 658 if (m_contentsOpaque) { 659 writeIndent(ts, indent + 1); 660 ts << "(contentsOpaque " << m_contentsOpaque << ")\n"; 661 } 662 663 if (m_preserves3D) { 664 writeIndent(ts, indent + 1); 665 ts << "(preserves3D " << m_preserves3D << ")\n"; 666 } 667 668 if (m_drawsContent && m_client.shouldDumpPropertyForLayer(this, "drawsContent")) { 669 writeIndent(ts, indent + 1); 670 ts << "(drawsContent " << m_drawsContent << ")\n"; 671 } 672 673 if (!m_contentsVisible) { 674 writeIndent(ts, indent + 1); 675 ts << "(contentsVisible " << m_contentsVisible << ")\n"; 676 } 677 678 if (!m_backfaceVisibility) { 679 writeIndent(ts, indent + 1); 680 ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n"; 681 } 682 683 if (behavior & LayerTreeAsTextDebug) { 684 writeIndent(ts, indent + 1); 685 ts << "(client " << static_cast<void*>(&m_client) << ")\n"; 686 } 687 688 if (m_backgroundColor.isValid() && m_client.shouldDumpPropertyForLayer(this, "backgroundColor")) { 689 writeIndent(ts, indent + 1); 690 ts << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n"; 691 } 692 693 if (!m_transform.isIdentity()) { 694 writeIndent(ts, indent + 1); 695 ts << "(transform "; 696 ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] "; 697 ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] "; 698 ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] "; 699 ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n"; 700 } 701 702 // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior 703 // differs between platforms. 704 if (parent() && !m_childrenTransform.isIdentity()) { 705 writeIndent(ts, indent + 1); 706 ts << "(childrenTransform "; 707 ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] "; 708 ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] "; 709 ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] "; 710 ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n"; 711 } 712 713 if (m_replicaLayer) { 714 writeIndent(ts, indent + 1); 715 ts << "(replica layer"; 716 if (behavior & LayerTreeAsTextDebug) 717 ts << " " << m_replicaLayer; 718 ts << ")\n"; 719 m_replicaLayer->dumpLayer(ts, indent + 2, behavior); 720 } 721 722 if (m_replicatedLayer) { 723 writeIndent(ts, indent + 1); 724 ts << "(replicated layer"; 725 if (behavior & LayerTreeAsTextDebug) 726 ts << " " << m_replicatedLayer; 727 ts << ")\n"; 728 } 729 730 if (behavior & LayerTreeAsTextIncludeRepaintRects && repaintRectMap().contains(this) && !repaintRectMap().get(this).isEmpty() && m_client.shouldDumpPropertyForLayer(this, "repaintRects")) { 731 writeIndent(ts, indent + 1); 732 ts << "(repaint rects\n"; 733 for (size_t i = 0; i < repaintRectMap().get(this).size(); ++i) { 734 if (repaintRectMap().get(this)[i].isEmpty()) 735 continue; 736 writeIndent(ts, indent + 2); 737 ts << "(rect "; 738 ts << repaintRectMap().get(this)[i].x() << " "; 739 ts << repaintRectMap().get(this)[i].y() << " "; 740 ts << repaintRectMap().get(this)[i].width() << " "; 741 ts << repaintRectMap().get(this)[i].height(); 742 ts << ")\n"; 743 } 744 writeIndent(ts, indent + 1); 745 ts << ")\n"; 746 } 747 748 if (behavior & LayerTreeAsTextIncludePaintingPhases && paintingPhase()) { 749 writeIndent(ts, indent + 1); 750 ts << "(paintingPhases\n"; 751 if (paintingPhase() & GraphicsLayerPaintBackground) { 752 writeIndent(ts, indent + 2); 753 ts << "GraphicsLayerPaintBackground\n"; 754 } 755 if (paintingPhase() & GraphicsLayerPaintForeground) { 756 writeIndent(ts, indent + 2); 757 ts << "GraphicsLayerPaintForeground\n"; 758 } 759 if (paintingPhase() & GraphicsLayerPaintMask) { 760 writeIndent(ts, indent + 2); 761 ts << "GraphicsLayerPaintMask\n"; 762 } 763 if (paintingPhase() & GraphicsLayerPaintOverflowContents) { 764 writeIndent(ts, indent + 2); 765 ts << "GraphicsLayerPaintOverflowContents\n"; 766 } 767 if (paintingPhase() & GraphicsLayerPaintCompositedScroll) { 768 writeIndent(ts, indent + 2); 769 ts << "GraphicsLayerPaintCompositedScroll\n"; 770 } 771 writeIndent(ts, indent + 1); 772 ts << ")\n"; 773 } 774 775 dumpAdditionalProperties(ts, indent, behavior); 776 777 if (m_children.size()) { 778 TextStream childrenStream; 779 780 unsigned totalChildCount = 0; 781 dumpChildren(childrenStream, m_children, totalChildCount, indent, behavior); 782 783 writeIndent(childrenStream, indent + 1); 784 childrenStream << ")\n"; 785 786 if (totalChildCount) { 787 writeIndent(ts, indent + 1); 788 ts << "(children " << totalChildCount << "\n"; 789 ts << childrenStream.release(); 790 } 791 } 792} 793 794String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const 795{ 796 TextStream ts; 797 798 dumpLayer(ts, 0, behavior); 799 return ts.release(); 800} 801 802} // namespace WebCore 803 804#ifndef NDEBUG 805void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer) 806{ 807 if (!layer) 808 return; 809 810 String output = layer->layerTreeAsText(WebCore::LayerTreeAsTextDebug | WebCore::LayerTreeAsTextIncludeVisibleRects | WebCore::LayerTreeAsTextIncludeTileCaches); 811 fprintf(stderr, "%s\n", output.utf8().data()); 812} 813#endif 814