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