• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
42 namespace WebCore {
43 
insert(const AnimationValue * value)44 void 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 
GraphicsLayer(GraphicsLayerClient * client)64 GraphicsLayer::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 
~GraphicsLayer()87 GraphicsLayer::~GraphicsLayer()
88 {
89     removeAllChildren();
90     removeFromParent();
91 }
92 
hasAncestor(GraphicsLayer * ancestor) const93 bool 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 
setChildren(const Vector<GraphicsLayer * > & newChildren)103 bool 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 
addChild(GraphicsLayer * childLayer)118 void 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 
addChildAtIndex(GraphicsLayer * childLayer,int index)129 void 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 
addChildBelow(GraphicsLayer * childLayer,GraphicsLayer * sibling)140 void 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 
addChildAbove(GraphicsLayer * childLayer,GraphicsLayer * sibling)160 void 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 
replaceChild(GraphicsLayer * oldChild,GraphicsLayer * newChild)180 bool 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 
removeAllChildren()201 void GraphicsLayer::removeAllChildren()
202 {
203     while (m_children.size()) {
204         GraphicsLayer* curLayer = m_children[0];
205         ASSERT(curLayer->parent());
206         curLayer->removeFromParent();
207     }
208 }
209 
removeFromParent()210 void 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 
setReplicatedByLayer(GraphicsLayer * layer)225 void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
226 {
227     if (layer)
228         layer->setReplicatedLayer(this);
229 
230     m_replicaLayer = layer;
231 }
232 
setBackgroundColor(const Color & color)233 void GraphicsLayer::setBackgroundColor(const Color& color)
234 {
235     m_backgroundColor = color;
236     m_backgroundColorSet = true;
237 }
238 
clearBackgroundColor()239 void GraphicsLayer::clearBackgroundColor()
240 {
241     m_backgroundColor = Color();
242     m_backgroundColorSet = false;
243 }
244 
paintGraphicsLayerContents(GraphicsContext & context,const IntRect & clip)245 void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
246 {
247     if (m_client)
248         m_client->paintContents(this, context, m_paintingPhase, clip);
249 }
250 
animationNameForTransition(AnimatedPropertyID property)251 String 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 
suspendAnimations(double)257 void GraphicsLayer::suspendAnimations(double)
258 {
259 }
260 
resumeAnimations()261 void GraphicsLayer::resumeAnimations()
262 {
263 }
264 
updateDebugIndicators()265 void 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 
setZPosition(float position)282 void GraphicsLayer::setZPosition(float position)
283 {
284     m_zPosition = position;
285 }
286 
accumulatedOpacity() const287 float GraphicsLayer::accumulatedOpacity() const
288 {
289     if (!preserves3D())
290         return 1;
291 
292     return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
293 }
294 
distributeOpacity(float accumulatedOpacity)295 void 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 
operationsAt(const KeyframeValueList & valueList,size_t index)316 static inline const TransformOperations* operationsAt(const KeyframeValueList& valueList, size_t index)
317 {
318     return static_cast<const TransformAnimationValue*>(valueList.at(index))->value();
319 }
320 
fetchTransformOperationList(const KeyframeValueList & valueList,TransformOperationList & list,bool & isValid,bool & hasBigRotation)321 void 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 
writeIndent(TextStream & ts,int indent)397 static void writeIndent(TextStream& ts, int indent)
398 {
399     for (int i = 0; i != indent; ++i)
400         ts << "  ";
401 }
402 
dumpLayer(TextStream & ts,int indent,LayerTreeAsTextBehavior behavior) const403 void 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 
dumpProperties(TextStream & ts,int indent,LayerTreeAsTextBehavior behavior) const419 void 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 
layerTreeAsText(LayerTreeAsTextBehavior behavior) const525 String 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
showGraphicsLayerTree(const WebCore::GraphicsLayer * layer)536 void 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