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