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 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.
28 #if USE(ACCELERATED_COMPOSITING)
30 #include "GraphicsLayer.h"
32 #include "FloatPoint.h"
33 #include "RotateTransformOperation.h"
34 #include "TextStream.h"
35 #include <wtf/text/CString.h>
36 #include <wtf/text/WTFString.h>
44 void KeyframeValueList::insert(const AnimationValue* value)
46 for (size_t i = 0; i < m_values.size(); ++i) {
47 const AnimationValue* curValue = m_values[i];
48 if (curValue->keyTime() == value->keyTime()) {
51 m_values.insert(i + 1, value);
54 if (curValue->keyTime() > value->keyTime()) {
56 m_values.insert(i, value);
61 m_values.append(value);
64 GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
66 , m_anchorPoint(0.5f, 0.5f, 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_maintainsPixelAlignment(false)
78 , m_appliesPageScale(false)
79 , m_paintingPhase(GraphicsLayerPaintAll)
80 , m_contentsOrientation(CompositingCoordinatesTopDown)
84 , m_replicatedLayer(0)
89 GraphicsLayer::~GraphicsLayer()
95 void GraphicsLayer::setParent(GraphicsLayer* layer)
97 ASSERT(!layer || !layer->hasAncestor(this));
101 bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const
103 for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) {
104 if (curr == ancestor)
111 bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren)
113 // If the contents of the arrays are the same, nothing to do.
114 if (newChildren == m_children)
119 size_t listSize = newChildren.size();
120 for (size_t i = 0; i < listSize; ++i)
121 addChild(newChildren[i]);
126 void GraphicsLayer::addChild(GraphicsLayer* childLayer)
128 ASSERT(childLayer != this);
130 if (childLayer->parent())
131 childLayer->removeFromParent();
133 childLayer->setParent(this);
134 m_children.append(childLayer);
137 void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index)
139 ASSERT(childLayer != this);
141 if (childLayer->parent())
142 childLayer->removeFromParent();
144 childLayer->setParent(this);
145 m_children.insert(index, childLayer);
148 void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
150 ASSERT(childLayer != this);
151 childLayer->removeFromParent();
154 for (unsigned i = 0; i < m_children.size(); i++) {
155 if (sibling == m_children[i]) {
156 m_children.insert(i, childLayer);
162 childLayer->setParent(this);
165 m_children.append(childLayer);
168 void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
170 childLayer->removeFromParent();
171 ASSERT(childLayer != this);
174 for (unsigned i = 0; i < m_children.size(); i++) {
175 if (sibling == m_children[i]) {
176 m_children.insert(i+1, childLayer);
182 childLayer->setParent(this);
185 m_children.append(childLayer);
188 bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
190 ASSERT(!newChild->parent());
192 for (unsigned i = 0; i < m_children.size(); i++) {
193 if (oldChild == m_children[i]) {
194 m_children[i] = newChild;
200 oldChild->setParent(0);
202 newChild->removeFromParent();
203 newChild->setParent(this);
209 void GraphicsLayer::removeAllChildren()
211 while (m_children.size()) {
212 GraphicsLayer* curLayer = m_children[0];
213 ASSERT(curLayer->parent());
214 curLayer->removeFromParent();
218 void GraphicsLayer::removeFromParent()
222 for (i = 0; i < m_parent->m_children.size(); i++) {
223 if (this == m_parent->m_children[i]) {
224 m_parent->m_children.remove(i);
233 void GraphicsLayer::noteDeviceOrPageScaleFactorChangedIncludingDescendants()
235 deviceOrPageScaleFactorChanged();
238 m_maskLayer->deviceOrPageScaleFactorChanged();
241 m_replicaLayer->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
243 const Vector<GraphicsLayer*>& childLayers = children();
244 size_t numChildren = childLayers.size();
245 for (size_t i = 0; i < numChildren; ++i)
246 childLayers[i]->noteDeviceOrPageScaleFactorChangedIncludingDescendants();
249 void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
252 layer->setReplicatedLayer(this);
254 m_replicaLayer = layer;
257 void GraphicsLayer::setBackgroundColor(const Color& color)
259 m_backgroundColor = color;
260 m_backgroundColorSet = true;
263 void GraphicsLayer::clearBackgroundColor()
265 m_backgroundColor = Color();
266 m_backgroundColorSet = false;
269 void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
272 m_client->paintContents(this, context, m_paintingPhase, clip);
275 String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
277 // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
278 String id = "-|transition";
279 id.append(static_cast<char>(property));
284 void GraphicsLayer::suspendAnimations(double)
288 void GraphicsLayer::resumeAnimations()
292 void GraphicsLayer::updateDebugIndicators()
294 if (GraphicsLayer::showDebugBorders()) {
295 if (drawsContent()) {
296 if (m_usingTiledLayer)
297 setDebugBorder(Color(0, 255, 0, 204), 2.0f); // tiled layer: green
299 setDebugBorder(Color(255, 0, 0, 204), 2.0f); // normal layer: red
300 } else if (masksToBounds()) {
301 setDebugBorder(Color(128, 255, 255, 178), 2.0f); // masking layer: pale blue
302 if (GraphicsLayer::showDebugBorders())
303 setDebugBackgroundColor(Color(128, 255, 255, 52));
305 setDebugBorder(Color(255, 255, 0, 204), 2.0f); // container: yellow
309 void GraphicsLayer::setZPosition(float position)
311 m_zPosition = position;
314 float GraphicsLayer::accumulatedOpacity() const
319 return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
322 void GraphicsLayer::distributeOpacity(float accumulatedOpacity)
324 // If this is a transform layer we need to distribute our opacity to all our children
326 // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own
327 // opacity to get the total contribution
328 accumulatedOpacity *= m_opacity;
330 setOpacityInternal(accumulatedOpacity);
333 size_t numChildren = children().size();
334 for (size_t i = 0; i < numChildren; ++i)
335 children()[i]->distributeOpacity(accumulatedOpacity);
340 GraphicsLayer::GraphicsLayerFactory* GraphicsLayer::s_graphicsLayerFactory = 0;
342 void GraphicsLayer::setGraphicsLayerFactory(GraphicsLayer::GraphicsLayerFactory factory)
344 s_graphicsLayerFactory = factory;
348 // An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
349 // The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
350 // true if the rotation between any two keyframes is >= 180 degrees.
352 static inline const TransformOperations* operationsAt(const KeyframeValueList& valueList, size_t index)
354 return static_cast<const TransformAnimationValue*>(valueList.at(index))->value();
357 void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueList, TransformOperationList& list, bool& isValid, bool& hasBigRotation)
359 ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
363 hasBigRotation = false;
365 if (valueList.size() < 2)
368 // Empty transforms match anything, so find the first non-empty entry as the reference.
369 size_t firstIndex = 0;
370 for ( ; firstIndex < valueList.size(); ++firstIndex) {
371 if (operationsAt(valueList, firstIndex)->operations().size() > 0)
375 if (firstIndex >= valueList.size())
378 const TransformOperations* firstVal = operationsAt(valueList, firstIndex);
380 // See if the keyframes are valid.
381 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
382 const TransformOperations* val = operationsAt(valueList, i);
384 // a null transform matches anything
385 if (val->operations().isEmpty())
388 if (firstVal->operations().size() != val->operations().size())
391 for (size_t j = 0; j < firstVal->operations().size(); ++j) {
392 if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j)))
397 // Keyframes are valid, fill in the list.
400 double lastRotAngle = 0.0;
401 double maxRotAngle = -1.0;
403 list.resize(firstVal->operations().size());
404 for (size_t j = 0; j < firstVal->operations().size(); ++j) {
405 TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType();
408 // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
409 if (type == TransformOperation::ROTATE_X ||
410 type == TransformOperation::ROTATE_Y ||
411 type == TransformOperation::ROTATE_Z ||
412 type == TransformOperation::ROTATE_3D) {
413 lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle();
416 maxRotAngle = fabs(lastRotAngle);
418 for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
419 const TransformOperations* val = operationsAt(valueList, i);
420 double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle());
421 double diffAngle = fabs(rotAngle - lastRotAngle);
422 if (diffAngle > maxRotAngle)
423 maxRotAngle = diffAngle;
424 lastRotAngle = rotAngle;
429 hasBigRotation = maxRotAngle >= 180.0;
433 static void writeIndent(TextStream& ts, int indent)
435 for (int i = 0; i != indent; ++i)
439 void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
441 writeIndent(ts, indent);
442 ts << "(" << "GraphicsLayer";
444 if (behavior & LayerTreeAsTextDebug) {
445 ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
446 ts << " \"" << m_name << "\"";
450 dumpProperties(ts, indent, behavior);
451 writeIndent(ts, indent);
455 void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const
457 if (m_position != FloatPoint()) {
458 writeIndent(ts, indent + 1);
459 ts << "(position " << m_position.x() << " " << m_position.y() << ")\n";
462 if (m_boundsOrigin != FloatPoint()) {
463 writeIndent(ts, indent + 1);
464 ts << "(bounds origin " << m_boundsOrigin.x() << " " << m_boundsOrigin.y() << ")\n";
467 if (m_anchorPoint != FloatPoint3D(0.5f, 0.5f, 0)) {
468 writeIndent(ts, indent + 1);
469 ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n";
472 if (m_size != IntSize()) {
473 writeIndent(ts, indent + 1);
474 ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
477 if (m_opacity != 1) {
478 writeIndent(ts, indent + 1);
479 ts << "(opacity " << m_opacity << ")\n";
482 if (m_usingTiledLayer) {
483 writeIndent(ts, indent + 1);
484 ts << "(usingTiledLayer " << m_usingTiledLayer << ")\n";
488 writeIndent(ts, indent + 1);
489 ts << "(preserves3D " << m_preserves3D << ")\n";
492 if (m_drawsContent) {
493 writeIndent(ts, indent + 1);
494 ts << "(drawsContent " << m_drawsContent << ")\n";
497 if (!m_backfaceVisibility) {
498 writeIndent(ts, indent + 1);
499 ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
502 if (behavior & LayerTreeAsTextDebug) {
503 writeIndent(ts, indent + 1);
506 ts << "client " << static_cast<void*>(m_client);
512 if (m_backgroundColorSet) {
513 writeIndent(ts, indent + 1);
514 ts << "(backgroundColor " << m_backgroundColor.nameForRenderTreeAsText() << ")\n";
517 if (!m_transform.isIdentity()) {
518 writeIndent(ts, indent + 1);
520 ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] ";
521 ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] ";
522 ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] ";
523 ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "])\n";
526 // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior
527 // differs between platforms.
528 if (parent() && !m_childrenTransform.isIdentity()) {
529 writeIndent(ts, indent + 1);
530 ts << "(childrenTransform ";
531 ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] ";
532 ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] ";
533 ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] ";
534 ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "])\n";
537 if (m_replicaLayer) {
538 writeIndent(ts, indent + 1);
539 ts << "(replica layer";
540 if (behavior & LayerTreeAsTextDebug)
541 ts << " " << m_replicaLayer;
543 m_replicaLayer->dumpLayer(ts, indent + 2, behavior);
546 if (m_replicatedLayer) {
547 writeIndent(ts, indent + 1);
548 ts << "(replicated layer";
549 if (behavior & LayerTreeAsTextDebug)
550 ts << " " << m_replicatedLayer;;
554 if (m_children.size()) {
555 writeIndent(ts, indent + 1);
556 ts << "(children " << m_children.size() << "\n";
559 for (i = 0; i < m_children.size(); i++)
560 m_children[i]->dumpLayer(ts, indent + 2, behavior);
561 writeIndent(ts, indent + 1);
566 String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const
570 dumpLayer(ts, 0, behavior);
574 } // namespace WebCore
577 void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer)
582 WTF::String output = layer->layerTreeAsText(LayerTreeAsTextDebug);
583 fprintf(stderr, "%s\n", output.utf8().data());
587 #endif // USE(ACCELERATED_COMPOSITING)