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