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 "RotateTransformOperation.h" 34#include "TextStream.h" 35#include <wtf/text/CString.h> 36#include <wtf/text/StringConcatenate.h> 37 38#ifndef NDEBUG 39#include <stdio.h> 40#endif 41 42namespace WebCore { 43 44void KeyframeValueList::insert(const AnimationValue* value) 45{ 46 for (size_t i = 0; i < m_values.size(); ++i) { 47 const AnimationValue* curValue = m_values[i]; 48 if (curValue->keyTime() == value->keyTime()) { 49 ASSERT_NOT_REACHED(); 50 // insert after 51 m_values.insert(i + 1, value); 52 return; 53 } 54 if (curValue->keyTime() > value->keyTime()) { 55 // insert before 56 m_values.insert(i, value); 57 return; 58 } 59 } 60 61 m_values.append(value); 62} 63 64GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) 65 : m_client(client) 66 , m_anchorPoint(0.5f, 0.5f, 0) 67 , m_opacity(1) 68 , m_zPosition(0) 69 , m_backgroundColorSet(false) 70 , m_contentsOpaque(false) 71 , m_preserves3D(false) 72 , m_backfaceVisibility(true) 73 , m_usingTiledLayer(false) 74 , m_masksToBounds(false) 75 , m_drawsContent(false) 76 , m_acceleratesDrawing(false) 77 , m_paintingPhase(GraphicsLayerPaintAll) 78 , m_contentsOrientation(CompositingCoordinatesTopDown) 79 , m_parent(0) 80 , m_maskLayer(0) 81 , m_replicaLayer(0) 82 , m_replicatedLayer(0) 83 , m_repaintCount(0) 84{ 85} 86 87GraphicsLayer::~GraphicsLayer() 88{ 89 removeAllChildren(); 90 removeFromParent(); 91} 92 93bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const 94{ 95 for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) { 96 if (curr == ancestor) 97 return true; 98 } 99 100 return false; 101} 102 103bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren) 104{ 105 // If the contents of the arrays are the same, nothing to do. 106 if (newChildren == m_children) 107 return false; 108 109 removeAllChildren(); 110 111 size_t listSize = newChildren.size(); 112 for (size_t i = 0; i < listSize; ++i) 113 addChild(newChildren[i]); 114 115 return true; 116} 117 118void GraphicsLayer::addChild(GraphicsLayer* childLayer) 119{ 120 ASSERT(childLayer != this); 121 122 if (childLayer->parent()) 123 childLayer->removeFromParent(); 124 125 childLayer->setParent(this); 126 m_children.append(childLayer); 127} 128 129void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index) 130{ 131 ASSERT(childLayer != this); 132 133 if (childLayer->parent()) 134 childLayer->removeFromParent(); 135 136 childLayer->setParent(this); 137 m_children.insert(index, childLayer); 138} 139 140void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) 141{ 142 ASSERT(childLayer != this); 143 childLayer->removeFromParent(); 144 145 bool found = false; 146 for (unsigned i = 0; i < m_children.size(); i++) { 147 if (sibling == m_children[i]) { 148 m_children.insert(i, childLayer); 149 found = true; 150 break; 151 } 152 } 153 154 childLayer->setParent(this); 155 156 if (!found) 157 m_children.append(childLayer); 158} 159 160void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling) 161{ 162 childLayer->removeFromParent(); 163 ASSERT(childLayer != this); 164 165 bool found = false; 166 for (unsigned i = 0; i < m_children.size(); i++) { 167 if (sibling == m_children[i]) { 168 m_children.insert(i+1, childLayer); 169 found = true; 170 break; 171 } 172 } 173 174 childLayer->setParent(this); 175 176 if (!found) 177 m_children.append(childLayer); 178} 179 180bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) 181{ 182 ASSERT(!newChild->parent()); 183 bool found = false; 184 for (unsigned i = 0; i < m_children.size(); i++) { 185 if (oldChild == m_children[i]) { 186 m_children[i] = newChild; 187 found = true; 188 break; 189 } 190 } 191 if (found) { 192 oldChild->setParent(0); 193 194 newChild->removeFromParent(); 195 newChild->setParent(this); 196 return true; 197 } 198 return false; 199} 200 201void GraphicsLayer::removeAllChildren() 202{ 203 while (m_children.size()) { 204 GraphicsLayer* curLayer = m_children[0]; 205 ASSERT(curLayer->parent()); 206 curLayer->removeFromParent(); 207 } 208} 209 210void GraphicsLayer::removeFromParent() 211{ 212 if (m_parent) { 213 unsigned i; 214 for (i = 0; i < m_parent->m_children.size(); i++) { 215 if (this == m_parent->m_children[i]) { 216 m_parent->m_children.remove(i); 217 break; 218 } 219 } 220 221 setParent(0); 222 } 223} 224 225void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer) 226{ 227 if (layer) 228 layer->setReplicatedLayer(this); 229 230 m_replicaLayer = layer; 231} 232 233void GraphicsLayer::setBackgroundColor(const Color& color) 234{ 235 m_backgroundColor = color; 236 m_backgroundColorSet = true; 237} 238 239void GraphicsLayer::clearBackgroundColor() 240{ 241 m_backgroundColor = Color(); 242 m_backgroundColorSet = false; 243} 244 245void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip) 246{ 247 if (m_client) 248 m_client->paintContents(this, context, m_paintingPhase, clip); 249} 250 251String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property) 252{ 253 // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier. 254 return makeString("-|transition", static_cast<char>(property), '-'); 255} 256 257void GraphicsLayer::suspendAnimations(double) 258{ 259} 260 261void GraphicsLayer::resumeAnimations() 262{ 263} 264 265void GraphicsLayer::updateDebugIndicators() 266{ 267 if (GraphicsLayer::showDebugBorders()) { 268 if (drawsContent()) { 269 if (m_usingTiledLayer) 270 setDebugBorder(Color(0, 255, 0, 204), 2.0f); // tiled layer: green 271 else 272 setDebugBorder(Color(255, 0, 0, 204), 2.0f); // normal layer: red 273 } else if (masksToBounds()) { 274 setDebugBorder(Color(128, 255, 255, 178), 2.0f); // masking layer: pale blue 275 if (GraphicsLayer::showDebugBorders()) 276 setDebugBackgroundColor(Color(128, 255, 255, 52)); 277 } else 278 setDebugBorder(Color(255, 255, 0, 204), 2.0f); // container: yellow 279 } 280} 281 282void GraphicsLayer::setZPosition(float position) 283{ 284 m_zPosition = position; 285} 286 287float GraphicsLayer::accumulatedOpacity() const 288{ 289 if (!preserves3D()) 290 return 1; 291 292 return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1); 293} 294 295void GraphicsLayer::distributeOpacity(float accumulatedOpacity) 296{ 297 // If this is a transform layer we need to distribute our opacity to all our children 298 299 // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own 300 // opacity to get the total contribution 301 accumulatedOpacity *= m_opacity; 302 303 setOpacityInternal(accumulatedOpacity); 304 305 if (preserves3D()) { 306 size_t numChildren = children().size(); 307 for (size_t i = 0; i < numChildren; ++i) 308 children()[i]->distributeOpacity(accumulatedOpacity); 309 } 310} 311 312// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix 313// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is 314// true if the rotation between any two keyframes is >= 180 degrees. 315 316static inline const TransformOperations* operationsAt(const KeyframeValueList& valueList, size_t index) 317{ 318 return static_cast<const TransformAnimationValue*>(valueList.at(index))->value(); 319} 320 321void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueList, TransformOperationList& list, bool& isValid, bool& hasBigRotation) 322{ 323 ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); 324 325 list.clear(); 326 isValid = false; 327 hasBigRotation = false; 328 329 if (valueList.size() < 2) 330 return; 331 332 // Empty transforms match anything, so find the first non-empty entry as the reference. 333 size_t firstIndex = 0; 334 for ( ; firstIndex < valueList.size(); ++firstIndex) { 335 if (operationsAt(valueList, firstIndex)->operations().size() > 0) 336 break; 337 } 338 339 if (firstIndex >= valueList.size()) 340 return; 341 342 const TransformOperations* firstVal = operationsAt(valueList, firstIndex); 343 344 // See if the keyframes are valid. 345 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) { 346 const TransformOperations* val = operationsAt(valueList, i); 347 348 // a null transform matches anything 349 if (val->operations().isEmpty()) 350 continue; 351 352 if (firstVal->operations().size() != val->operations().size()) 353 return; 354 355 for (size_t j = 0; j < firstVal->operations().size(); ++j) { 356 if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j))) 357 return; 358 } 359 } 360 361 // Keyframes are valid, fill in the list. 362 isValid = true; 363 364 double lastRotAngle = 0.0; 365 double maxRotAngle = -1.0; 366 367 list.resize(firstVal->operations().size()); 368 for (size_t j = 0; j < firstVal->operations().size(); ++j) { 369 TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType(); 370 list[j] = type; 371 372 // if this is a rotation entry, we need to see if any angle differences are >= 180 deg 373 if (type == TransformOperation::ROTATE_X || 374 type == TransformOperation::ROTATE_Y || 375 type == TransformOperation::ROTATE_Z || 376 type == TransformOperation::ROTATE_3D) { 377 lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle(); 378 379 if (maxRotAngle < 0) 380 maxRotAngle = fabs(lastRotAngle); 381 382 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) { 383 const TransformOperations* val = operationsAt(valueList, i); 384 double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle()); 385 double diffAngle = fabs(rotAngle - lastRotAngle); 386 if (diffAngle > maxRotAngle) 387 maxRotAngle = diffAngle; 388 lastRotAngle = rotAngle; 389 } 390 } 391 } 392 393 hasBigRotation = maxRotAngle >= 180.0; 394} 395 396 397static void writeIndent(TextStream& ts, int indent) 398{ 399 for (int i = 0; i != indent; ++i) 400 ts << " "; 401} 402 403void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const 404{ 405 writeIndent(ts, indent); 406 ts << "(" << "GraphicsLayer"; 407 408 if (behavior & LayerTreeAsTextDebug) { 409 ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this)); 410 ts << " \"" << m_name << "\""; 411 } 412 413 ts << "\n"; 414 dumpProperties(ts, indent, behavior); 415 writeIndent(ts, indent); 416 ts << ")\n"; 417} 418 419void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const 420{ 421 if (m_position != FloatPoint()) { 422 writeIndent(ts, indent + 1); 423 ts << "(position " << m_position.x() << " " << m_position.y() << ")\n"; 424 } 425 426 if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) { 427 writeIndent(ts, indent + 1); 428 ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n"; 429 } 430 431 if (m_size != IntSize()) { 432 writeIndent(ts, indent + 1); 433 ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n"; 434 } 435 436 if (m_opacity != 1) { 437 writeIndent(ts, indent + 1); 438 ts << "(opacity " << m_opacity << ")\n"; 439 } 440 441 if (m_usingTiledLayer) { 442 writeIndent(ts, indent + 1); 443 ts << "(usingTiledLayer " << m_usingTiledLayer << ")\n"; 444 } 445 446 if (m_preserves3D) { 447 writeIndent(ts, indent + 1); 448 ts << "(preserves3D " << m_preserves3D << ")\n"; 449 } 450 451 if (m_drawsContent) { 452 writeIndent(ts, indent + 1); 453 ts << "(drawsContent " << m_drawsContent << ")\n"; 454 } 455 456 if (!m_backfaceVisibility) { 457 writeIndent(ts, indent + 1); 458 ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n"; 459 } 460 461 if (behavior & LayerTreeAsTextDebug) { 462 writeIndent(ts, indent + 1); 463 ts << "("; 464 if (m_client) 465 ts << "client " << static_cast<void*>(m_client); 466 else 467 ts << "no client"; 468 ts << ")\n"; 469 } 470 471 if (m_backgroundColorSet) { 472 writeIndent(ts, indent + 1); 473 ts << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n"; 474 } 475 476 if (!m_transform.isIdentity()) { 477 writeIndent(ts, indent + 1); 478 ts << "(transform "; 479 ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] "; 480 ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] "; 481 ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] "; 482 ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n"; 483 } 484 485 // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior 486 // differs between platforms. 487 if (parent() && !m_childrenTransform.isIdentity()) { 488 writeIndent(ts, indent + 1); 489 ts << "(childrenTransform "; 490 ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] "; 491 ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] "; 492 ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] "; 493 ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n"; 494 } 495 496 if (m_replicaLayer) { 497 writeIndent(ts, indent + 1); 498 ts << "(replica layer"; 499 if (behavior & LayerTreeAsTextDebug) 500 ts << " " << m_replicaLayer; 501 ts << ")\n"; 502 m_replicaLayer->dumpLayer(ts, indent + 2, behavior); 503 } 504 505 if (m_replicatedLayer) { 506 writeIndent(ts, indent + 1); 507 ts << "(replicated layer"; 508 if (behavior & LayerTreeAsTextDebug) 509 ts << " " << m_replicatedLayer;; 510 ts << ")\n"; 511 } 512 513 if (m_children.size()) { 514 writeIndent(ts, indent + 1); 515 ts << "(children " << m_children.size() << "\n"; 516 517 unsigned i; 518 for (i = 0; i < m_children.size(); i++) 519 m_children[i]->dumpLayer(ts, indent + 2, behavior); 520 writeIndent(ts, indent + 1); 521 ts << ")\n"; 522 } 523} 524 525String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const 526{ 527 TextStream ts; 528 529 dumpLayer(ts, 0, behavior); 530 return ts.release(); 531} 532 533} // namespace WebCore 534 535#ifndef NDEBUG 536void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer) 537{ 538 if (!layer) 539 return; 540 541 WTF::String output = layer->layerTreeAsText(LayerTreeAsTextDebug); 542 fprintf(stderr, "%s\n", output.utf8().data()); 543} 544#endif 545 546#endif // USE(ACCELERATED_COMPOSITING) 547