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