OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2010 Apple Inc. All rights reserved. | |
3 * Copyright (C) 2011, 2012, 2013 Collabora Ltd. | |
4 * Copyright (C) 2012 Intel Corporation. All rights reserved. | |
5 * | |
6 * Redistribution and use in source and binary forms, with or without | |
7 * modification, are permitted provided that the following conditions | |
8 * are met: | |
9 * 1. Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * | |
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include "config.h" | |
29 | |
30 #if USE(ACCELERATED_COMPOSITING) | |
31 #include "GraphicsLayerClutter.h" | |
32 | |
33 #include "Animation.h" | |
34 #include "FloatConversion.h" | |
35 #include "FloatRect.h" | |
36 #include "GraphicsLayerActor.h" | |
37 #include "GraphicsLayerFactory.h" | |
38 #include "NotImplemented.h" | |
39 #include "RefPtrCairo.h" | |
40 #include "RotateTransformOperation.h" | |
41 #include "ScaleTransformOperation.h" | |
42 #include "TransformState.h" | |
43 #include "TransformationMatrix.h" | |
44 #include "TranslateTransformOperation.h" | |
45 #include <limits.h> | |
46 #include <wtf/text/CString.h> | |
47 #include <wtf/text/WTFString.h> | |
48 | |
49 using namespace std; | |
50 | |
51 namespace WebCore { | |
52 | |
53 // If we send a duration of 0 to ClutterTimeline, then it will fail to set the d
uration. | |
54 // So send a very small value instead. | |
55 static const float cAnimationAlmostZeroDuration = 1e-3f; | |
56 | |
57 static bool isTransformTypeTransformationMatrix(TransformOperation::OperationTyp
e transformType) | |
58 { | |
59 switch (transformType) { | |
60 case TransformOperation::SKEW_X: | |
61 case TransformOperation::SKEW_Y: | |
62 case TransformOperation::SKEW: | |
63 case TransformOperation::MATRIX: | |
64 case TransformOperation::ROTATE_3D: | |
65 case TransformOperation::MATRIX_3D: | |
66 case TransformOperation::PERSPECTIVE: | |
67 case TransformOperation::IDENTITY: | |
68 case TransformOperation::NONE: | |
69 return true; | |
70 default: | |
71 return false; | |
72 } | |
73 } | |
74 | |
75 static bool isTransformTypeFloatPoint3D(TransformOperation::OperationType transf
ormType) | |
76 { | |
77 switch (transformType) { | |
78 case TransformOperation::SCALE: | |
79 case TransformOperation::SCALE_3D: | |
80 case TransformOperation::TRANSLATE: | |
81 case TransformOperation::TRANSLATE_3D: | |
82 return true; | |
83 default: | |
84 return false; | |
85 } | |
86 } | |
87 | |
88 static bool isTransformTypeNumber(TransformOperation::OperationType transformTyp
e) | |
89 { | |
90 return !isTransformTypeTransformationMatrix(transformType) && !isTransformTy
peFloatPoint3D(transformType); | |
91 } | |
92 | |
93 static void getTransformFunctionValue(const TransformOperation* transformOp, Tra
nsformOperation::OperationType transformType, const IntSize& size, float& value) | |
94 { | |
95 switch (transformType) { | |
96 case TransformOperation::ROTATE: | |
97 case TransformOperation::ROTATE_X: | |
98 case TransformOperation::ROTATE_Y: | |
99 value = transformOp ? narrowPrecisionToFloat(deg2rad(static_cast<const R
otateTransformOperation*>(transformOp)->angle())) : 0; | |
100 break; | |
101 case TransformOperation::SCALE_X: | |
102 value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTran
sformOperation*>(transformOp)->x()) : 1; | |
103 break; | |
104 case TransformOperation::SCALE_Y: | |
105 value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTran
sformOperation*>(transformOp)->y()) : 1; | |
106 break; | |
107 case TransformOperation::SCALE_Z: | |
108 value = transformOp ? narrowPrecisionToFloat(static_cast<const ScaleTran
sformOperation*>(transformOp)->z()) : 1; | |
109 break; | |
110 case TransformOperation::TRANSLATE_X: | |
111 value = transformOp ? narrowPrecisionToFloat(static_cast<const Translate
TransformOperation*>(transformOp)->x(size)) : 0; | |
112 break; | |
113 case TransformOperation::TRANSLATE_Y: | |
114 value = transformOp ? narrowPrecisionToFloat(static_cast<const Translate
TransformOperation*>(transformOp)->y(size)) : 0; | |
115 break; | |
116 case TransformOperation::TRANSLATE_Z: | |
117 value = transformOp ? narrowPrecisionToFloat(static_cast<const Translate
TransformOperation*>(transformOp)->z(size)) : 0; | |
118 break; | |
119 default: | |
120 break; | |
121 } | |
122 } | |
123 | |
124 static void getTransformFunctionValue(const TransformOperation* transformOp, Tra
nsformOperation::OperationType transformType, const IntSize& size, FloatPoint3D&
value) | |
125 { | |
126 switch (transformType) { | |
127 case TransformOperation::SCALE: | |
128 case TransformOperation::SCALE_3D: | |
129 value.setX(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleT
ransformOperation*>(transformOp)->x()) : 1); | |
130 value.setY(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleT
ransformOperation*>(transformOp)->y()) : 1); | |
131 value.setZ(transformOp ? narrowPrecisionToFloat(static_cast<const ScaleT
ransformOperation*>(transformOp)->z()) : 1); | |
132 break; | |
133 case TransformOperation::TRANSLATE: | |
134 case TransformOperation::TRANSLATE_3D: | |
135 value.setX(transformOp ? narrowPrecisionToFloat(static_cast<const Transl
ateTransformOperation*>(transformOp)->x(size)) : 0); | |
136 value.setY(transformOp ? narrowPrecisionToFloat(static_cast<const Transl
ateTransformOperation*>(transformOp)->y(size)) : 0); | |
137 value.setZ(transformOp ? narrowPrecisionToFloat(static_cast<const Transl
ateTransformOperation*>(transformOp)->z(size)) : 0); | |
138 break; | |
139 default: | |
140 break; | |
141 } | |
142 } | |
143 | |
144 static void getTransformFunctionValue(const TransformOperation* transformOp, Tra
nsformOperation::OperationType transformType, const IntSize& size, Transformatio
nMatrix& value) | |
145 { | |
146 switch (transformType) { | |
147 case TransformOperation::SKEW_X: | |
148 case TransformOperation::SKEW_Y: | |
149 case TransformOperation::SKEW: | |
150 case TransformOperation::MATRIX: | |
151 case TransformOperation::ROTATE_3D: | |
152 case TransformOperation::MATRIX_3D: | |
153 case TransformOperation::PERSPECTIVE: | |
154 case TransformOperation::IDENTITY: | |
155 case TransformOperation::NONE: | |
156 if (transformOp) | |
157 transformOp->apply(value, size); | |
158 else | |
159 value.makeIdentity(); | |
160 break; | |
161 default: | |
162 break; | |
163 } | |
164 } | |
165 | |
166 static PlatformClutterAnimation::ValueFunctionType getValueFunctionNameForTransf
ormOperation(TransformOperation::OperationType transformType) | |
167 { | |
168 // Use literal strings to avoid link-time dependency on those symbols. | |
169 switch (transformType) { | |
170 case TransformOperation::ROTATE_X: | |
171 return PlatformClutterAnimation::RotateX; | |
172 case TransformOperation::ROTATE_Y: | |
173 return PlatformClutterAnimation::RotateY; | |
174 case TransformOperation::ROTATE: | |
175 return PlatformClutterAnimation::RotateZ; | |
176 case TransformOperation::SCALE_X: | |
177 return PlatformClutterAnimation::ScaleX; | |
178 case TransformOperation::SCALE_Y: | |
179 return PlatformClutterAnimation::ScaleY; | |
180 case TransformOperation::SCALE_Z: | |
181 return PlatformClutterAnimation::ScaleZ; | |
182 case TransformOperation::TRANSLATE_X: | |
183 return PlatformClutterAnimation::TranslateX; | |
184 case TransformOperation::TRANSLATE_Y: | |
185 return PlatformClutterAnimation::TranslateY; | |
186 case TransformOperation::TRANSLATE_Z: | |
187 return PlatformClutterAnimation::TranslateZ; | |
188 case TransformOperation::SCALE: | |
189 case TransformOperation::SCALE_3D: | |
190 return PlatformClutterAnimation::Scale; | |
191 case TransformOperation::TRANSLATE: | |
192 case TransformOperation::TRANSLATE_3D: | |
193 return PlatformClutterAnimation::Translate; | |
194 case TransformOperation::MATRIX_3D: | |
195 return PlatformClutterAnimation::Matrix; | |
196 default: | |
197 return PlatformClutterAnimation::NoValueFunction; | |
198 } | |
199 } | |
200 | |
201 static String propertyIdToString(AnimatedPropertyID property) | |
202 { | |
203 switch (property) { | |
204 case AnimatedPropertyWebkitTransform: | |
205 return "transform"; | |
206 case AnimatedPropertyOpacity: | |
207 return "opacity"; | |
208 case AnimatedPropertyBackgroundColor: | |
209 return "backgroundColor"; | |
210 case AnimatedPropertyWebkitFilter: | |
211 ASSERT_NOT_REACHED(); | |
212 case AnimatedPropertyInvalid: | |
213 ASSERT_NOT_REACHED(); | |
214 } | |
215 ASSERT_NOT_REACHED(); | |
216 return ""; | |
217 } | |
218 | |
219 static String animationIdentifier(const String& animationName, AnimatedPropertyI
D property, int index) | |
220 { | |
221 return animationName + '_' + String::number(property) + '_' + String::number
(index); | |
222 } | |
223 | |
224 static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList,
const Animation* anim) | |
225 { | |
226 if (anim->timingFunction()->isStepsTimingFunction()) | |
227 return true; | |
228 | |
229 for (unsigned i = 0; i < valueList.size(); ++i) { | |
230 const TimingFunction* timingFunction = valueList.at(i)->timingFunction()
; | |
231 if (timingFunction && timingFunction->isStepsTimingFunction()) | |
232 return true; | |
233 } | |
234 | |
235 return false; | |
236 } | |
237 | |
238 // This is the hook for WebCore compositor to know that the webKit clutter port
implements | |
239 // compositing with GraphicsLayerClutter. | |
240 PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, G
raphicsLayerClient* client) | |
241 { | |
242 if (!factory) | |
243 return adoptPtr(new GraphicsLayerClutter(client)); | |
244 | |
245 return factory->createGraphicsLayer(client); | |
246 } | |
247 | |
248 PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) | |
249 { | |
250 return adoptPtr(new GraphicsLayerClutter(client)); | |
251 } | |
252 | |
253 GraphicsLayerClutter::GraphicsLayerClutter(GraphicsLayerClient* client) | |
254 : GraphicsLayer(client) | |
255 , m_uncommittedChanges(0) | |
256 { | |
257 // ClutterRectangle will be used to show the debug border. | |
258 m_layer = graphicsLayerActorNewWithClient(LayerTypeWebLayer, this); | |
259 } | |
260 | |
261 static gboolean idleDestroy(gpointer data) | |
262 { | |
263 GRefPtr<ClutterActor> actor = adoptGRef(CLUTTER_ACTOR(data)); | |
264 ClutterActor* parent = clutter_actor_get_parent(actor.get()); | |
265 | |
266 // We should remove child actors manually because the container of Clutter | |
267 // seems to have a bug to remove its child actors when it is removed. | |
268 if (GRAPHICS_LAYER_IS_ACTOR(GRAPHICS_LAYER_ACTOR(actor.get()))) | |
269 graphicsLayerActorRemoveAll(GRAPHICS_LAYER_ACTOR(actor.get())); | |
270 | |
271 if (parent) | |
272 clutter_actor_remove_child(parent, actor.get()); | |
273 | |
274 // FIXME: we should assert that the actor's ref count is 1 here, but some | |
275 // of them are getting here with 2! | |
276 // ASSERT((G_OBJECT(actor.get()))->ref_count == 1); | |
277 | |
278 return FALSE; | |
279 } | |
280 | |
281 GraphicsLayerClutter::~GraphicsLayerClutter() | |
282 { | |
283 if (graphicsLayerActorGetLayerType(m_layer.get()) == GraphicsLayerClutter::L
ayerTypeRootLayer) | |
284 return; | |
285 | |
286 // Even though we call notifyFlushRequired to remove existing animations in
removeAnimation(), | |
287 // removeClutterAnimationFromLayer has been never reached since the root lay
er is destroyed. | |
288 // It means that we haven't lost a change to remove actual animations from c
lutterActor. | |
289 // So, we call explictly updateAnimations once here to remove uncommitted an
imations. | |
290 if (m_uncommittedChanges & AnimationChanged) | |
291 updateAnimations(); | |
292 | |
293 willBeDestroyed(); | |
294 | |
295 // We destroy the actors on an idle so that the main loop can run enough to | |
296 // repaint the background that will replace the actor. | |
297 if (m_layer) { | |
298 graphicsLayerActorSetClient(m_layer.get(), 0); | |
299 g_idle_add(idleDestroy, m_layer.leakRef()); | |
300 } | |
301 | |
302 if (m_structuralLayer) { | |
303 graphicsLayerActorSetClient(m_structuralLayer.get(), 0); | |
304 g_idle_add(idleDestroy, m_structuralLayer.leakRef()); | |
305 } | |
306 } | |
307 | |
308 void GraphicsLayerClutter::setName(const String& name) | |
309 { | |
310 String longName = String::format("Actor(%p) GraphicsLayer(%p) ", m_layer.get
(), this) + name; | |
311 GraphicsLayer::setName(longName); | |
312 noteLayerPropertyChanged(NameChanged); | |
313 } | |
314 | |
315 ClutterActor* GraphicsLayerClutter::platformLayer() const | |
316 { | |
317 return CLUTTER_ACTOR(primaryLayer()); | |
318 } | |
319 | |
320 void GraphicsLayerClutter::setNeedsDisplay() | |
321 { | |
322 FloatRect hugeRect(FloatPoint(), m_size); | |
323 setNeedsDisplayInRect(hugeRect); | |
324 } | |
325 | |
326 void GraphicsLayerClutter::setNeedsDisplayInRect(const FloatRect& r) | |
327 { | |
328 if (!drawsContent()) | |
329 return; | |
330 | |
331 FloatRect rect(r); | |
332 FloatRect layerBounds(FloatPoint(), m_size); | |
333 rect.intersect(layerBounds); | |
334 if (rect.isEmpty()) | |
335 return; | |
336 | |
337 const size_t maxDirtyRects = 32; | |
338 | |
339 for (size_t i = 0; i < m_dirtyRects.size(); ++i) { | |
340 if (m_dirtyRects[i].contains(rect)) | |
341 return; | |
342 } | |
343 | |
344 if (m_dirtyRects.size() < maxDirtyRects) | |
345 m_dirtyRects.append(rect); | |
346 else | |
347 m_dirtyRects[0].unite(rect); | |
348 | |
349 noteLayerPropertyChanged(DirtyRectsChanged); | |
350 } | |
351 | |
352 void GraphicsLayerClutter::setAnchorPoint(const FloatPoint3D& point) | |
353 { | |
354 if (point == m_anchorPoint) | |
355 return; | |
356 | |
357 GraphicsLayer::setAnchorPoint(point); | |
358 noteLayerPropertyChanged(GeometryChanged); | |
359 } | |
360 | |
361 void GraphicsLayerClutter::setOpacity(float opacity) | |
362 { | |
363 float clampedOpacity = max(0.0f, min(opacity, 1.0f)); | |
364 if (clampedOpacity == m_opacity) | |
365 return; | |
366 | |
367 GraphicsLayer::setOpacity(clampedOpacity); | |
368 noteLayerPropertyChanged(OpacityChanged); | |
369 } | |
370 | |
371 void GraphicsLayerClutter::setPosition(const FloatPoint& point) | |
372 { | |
373 if (point == m_position) | |
374 return; | |
375 | |
376 GraphicsLayer::setPosition(point); | |
377 noteLayerPropertyChanged(GeometryChanged); | |
378 } | |
379 | |
380 void GraphicsLayerClutter::setSize(const FloatSize& size) | |
381 { | |
382 if (size == m_size) | |
383 return; | |
384 | |
385 GraphicsLayer::setSize(size); | |
386 noteLayerPropertyChanged(GeometryChanged); | |
387 } | |
388 void GraphicsLayerClutter::setTransform(const TransformationMatrix& t) | |
389 { | |
390 if (t == m_transform) | |
391 return; | |
392 | |
393 GraphicsLayer::setTransform(t); | |
394 noteLayerPropertyChanged(TransformChanged); | |
395 } | |
396 | |
397 void GraphicsLayerClutter::moveOrCopyAnimations(MoveOrCopy operation, GraphicsLa
yerActor* fromLayer, GraphicsLayerActor* toLayer) | |
398 { | |
399 notImplemented(); | |
400 } | |
401 | |
402 void GraphicsLayerClutter::setPreserves3D(bool preserves3D) | |
403 { | |
404 if (preserves3D == m_preserves3D) | |
405 return; | |
406 | |
407 GraphicsLayer::setPreserves3D(preserves3D); | |
408 noteLayerPropertyChanged(Preserves3DChanged); | |
409 } | |
410 | |
411 void GraphicsLayerClutter::setDrawsContent(bool drawsContent) | |
412 { | |
413 if (drawsContent == m_drawsContent) | |
414 return; | |
415 | |
416 GraphicsLayer::setDrawsContent(drawsContent); | |
417 noteLayerPropertyChanged(DrawsContentChanged); | |
418 } | |
419 | |
420 void GraphicsLayerClutter::setParent(GraphicsLayer* childLayer) | |
421 { | |
422 notImplemented(); | |
423 | |
424 GraphicsLayer::setParent(childLayer); | |
425 } | |
426 | |
427 bool GraphicsLayerClutter::setChildren(const Vector<GraphicsLayer*>& children) | |
428 { | |
429 bool childrenChanged = GraphicsLayer::setChildren(children); | |
430 if (childrenChanged) | |
431 noteSublayersChanged(); | |
432 | |
433 return childrenChanged; | |
434 } | |
435 | |
436 void GraphicsLayerClutter::addChild(GraphicsLayer* childLayer) | |
437 { | |
438 GraphicsLayer::addChild(childLayer); | |
439 noteSublayersChanged(); | |
440 } | |
441 | |
442 void GraphicsLayerClutter::addChildAtIndex(GraphicsLayer* childLayer, int index) | |
443 { | |
444 GraphicsLayer::addChildAtIndex(childLayer, index); | |
445 noteSublayersChanged(); | |
446 } | |
447 | |
448 void GraphicsLayerClutter::addChildBelow(GraphicsLayer* childLayer, GraphicsLaye
r* sibling) | |
449 { | |
450 GraphicsLayer::addChildBelow(childLayer, sibling); | |
451 noteSublayersChanged(); | |
452 } | |
453 | |
454 void GraphicsLayerClutter::addChildAbove(GraphicsLayer* childLayer, GraphicsLaye
r* sibling) | |
455 { | |
456 GraphicsLayer::addChildAbove(childLayer, sibling); | |
457 noteSublayersChanged(); | |
458 } | |
459 | |
460 bool GraphicsLayerClutter::replaceChild(GraphicsLayer* oldChild, GraphicsLayer*
newChild) | |
461 { | |
462 if (GraphicsLayer::replaceChild(oldChild, newChild)) { | |
463 noteSublayersChanged(); | |
464 return true; | |
465 } | |
466 return false; | |
467 } | |
468 | |
469 void GraphicsLayerClutter::removeFromParent() | |
470 { | |
471 if (m_parent) | |
472 static_cast<GraphicsLayerClutter*>(m_parent)->noteSublayersChanged(); | |
473 GraphicsLayer::removeFromParent(); | |
474 } | |
475 | |
476 void GraphicsLayerClutter::platformClutterLayerPaintContents(GraphicsContext& co
ntext, const IntRect& clip) | |
477 { | |
478 paintGraphicsLayerContents(context, clip); | |
479 } | |
480 | |
481 void GraphicsLayerClutter::platformClutterLayerAnimationStarted(double startTime
) | |
482 { | |
483 if (m_client) | |
484 m_client->notifyAnimationStarted(this, startTime); | |
485 } | |
486 | |
487 void GraphicsLayerClutter::repaintLayerDirtyRects() | |
488 { | |
489 if (!m_dirtyRects.size()) | |
490 return; | |
491 | |
492 for (size_t i = 0; i < m_dirtyRects.size(); ++i) | |
493 graphicsLayerActorInvalidateRectangle(m_layer.get(), m_dirtyRects[i]); | |
494 | |
495 m_dirtyRects.clear(); | |
496 } | |
497 | |
498 void GraphicsLayerClutter::updateOpacityOnLayer() | |
499 { | |
500 clutter_actor_set_opacity(CLUTTER_ACTOR(primaryLayer()), static_cast<guint8>
(roundf(m_opacity * 255))); | |
501 } | |
502 | |
503 void GraphicsLayerClutter::updateAnimations() | |
504 { | |
505 if (m_animationsToProcess.size()) { | |
506 AnimationsToProcessMap::const_iterator end = m_animationsToProcess.end()
; | |
507 for (AnimationsToProcessMap::const_iterator it = m_animationsToProcess.b
egin(); it != end; ++it) { | |
508 const String& currAnimationName = it->key; | |
509 AnimationsMap::iterator animationIt = m_runningAnimations.find(currA
nimationName); | |
510 if (animationIt == m_runningAnimations.end()) | |
511 continue; | |
512 | |
513 const AnimationProcessingAction& processingInfo = it->value; | |
514 const Vector<LayerPropertyAnimation>& animations = animationIt->valu
e; | |
515 for (size_t i = 0; i < animations.size(); ++i) { | |
516 const LayerPropertyAnimation& currAnimation = animations[i]; | |
517 switch (processingInfo.action) { | |
518 case Remove: | |
519 removeClutterAnimationFromLayer(currAnimation.m_property, cu
rrAnimationName, currAnimation.m_index); | |
520 break; | |
521 case Pause: | |
522 pauseClutterAnimationOnLayer(currAnimation.m_property, currA
nimationName, currAnimation.m_index, processingInfo.timeOffset); | |
523 break; | |
524 } | |
525 } | |
526 | |
527 if (processingInfo.action == Remove) | |
528 m_runningAnimations.remove(currAnimationName); | |
529 } | |
530 | |
531 m_animationsToProcess.clear(); | |
532 } | |
533 | |
534 size_t numAnimations; | |
535 if ((numAnimations = m_uncomittedAnimations.size())) { | |
536 for (size_t i = 0; i < numAnimations; ++i) { | |
537 const LayerPropertyAnimation& pendingAnimation = m_uncomittedAnimati
ons[i]; | |
538 setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnima
tion.m_property, pendingAnimation.m_name, pendingAnimation.m_index, pendingAnima
tion.m_timeOffset); | |
539 | |
540 AnimationsMap::iterator it = m_runningAnimations.find(pendingAnimati
on.m_name); | |
541 if (it == m_runningAnimations.end()) { | |
542 Vector<LayerPropertyAnimation> animations; | |
543 animations.append(pendingAnimation); | |
544 m_runningAnimations.add(pendingAnimation.m_name, animations); | |
545 } else { | |
546 Vector<LayerPropertyAnimation>& animations = it->value; | |
547 animations.append(pendingAnimation); | |
548 } | |
549 } | |
550 | |
551 m_uncomittedAnimations.clear(); | |
552 } | |
553 } | |
554 | |
555 FloatPoint GraphicsLayerClutter::computePositionRelativeToBase(float& pageScale)
const | |
556 { | |
557 pageScale = 1; | |
558 | |
559 FloatPoint offset; | |
560 for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer
->parent()) { | |
561 if (currLayer->appliesPageScale()) { | |
562 if (currLayer->client()) | |
563 pageScale = currLayer->pageScaleFactor(); | |
564 return offset; | |
565 } | |
566 | |
567 offset += currLayer->position(); | |
568 } | |
569 | |
570 return FloatPoint(); | |
571 } | |
572 | |
573 // called from void RenderLayerCompositor::flushPendingLayerChanges | |
574 void GraphicsLayerClutter::flushCompositingState(const FloatRect& clipRect) | |
575 { | |
576 TransformState state(TransformState::UnapplyInverseTransformDirection, Float
Quad(clipRect)); | |
577 recursiveCommitChanges(CommitState(), state); | |
578 } | |
579 | |
580 void GraphicsLayerClutter::recursiveCommitChanges(const CommitState& commitState
, const TransformState& state, float pageScaleFactor, const FloatPoint& position
RelativeToBase, bool affectedByPageScale) | |
581 { | |
582 if (appliesPageScale()) { | |
583 pageScaleFactor = this->pageScaleFactor(); | |
584 affectedByPageScale = true; | |
585 } | |
586 | |
587 // Accumulate an offset from the ancestral pixel-aligned layer. | |
588 FloatPoint baseRelativePosition = positionRelativeToBase; | |
589 if (affectedByPageScale) | |
590 baseRelativePosition += m_position; | |
591 | |
592 commitLayerChangesBeforeSublayers(pageScaleFactor, baseRelativePosition); | |
593 | |
594 const Vector<GraphicsLayer*>& childLayers = children(); | |
595 size_t numChildren = childLayers.size(); | |
596 | |
597 for (size_t i = 0; i < numChildren; ++i) { | |
598 GraphicsLayerClutter* currentChild = static_cast<GraphicsLayerClutter*>(
childLayers[i]); | |
599 currentChild->recursiveCommitChanges(commitState, state, pageScaleFactor
, baseRelativePosition, affectedByPageScale); | |
600 } | |
601 | |
602 commitLayerChangesAfterSublayers(); | |
603 } | |
604 | |
605 void GraphicsLayerClutter::flushCompositingStateForThisLayerOnly() | |
606 { | |
607 float pageScaleFactor; | |
608 FloatPoint offset = computePositionRelativeToBase(pageScaleFactor); | |
609 commitLayerChangesBeforeSublayers(pageScaleFactor, offset); | |
610 commitLayerChangesAfterSublayers(); | |
611 } | |
612 | |
613 void GraphicsLayerClutter::commitLayerChangesAfterSublayers() | |
614 { | |
615 if (!m_uncommittedChanges) | |
616 return; | |
617 | |
618 if (m_uncommittedChanges & ChildrenChanged) | |
619 updateSublayerList(); | |
620 | |
621 m_uncommittedChanges = NoChange; | |
622 } | |
623 void GraphicsLayerClutter::noteSublayersChanged() | |
624 { | |
625 noteLayerPropertyChanged(ChildrenChanged); | |
626 } | |
627 | |
628 void GraphicsLayerClutter::noteLayerPropertyChanged(LayerChangeFlags flags) | |
629 { | |
630 if (!m_uncommittedChanges && m_client) | |
631 m_client->notifyFlushRequired(this); // call RenderLayerBacking::notifyF
lushRequired | |
632 | |
633 m_uncommittedChanges |= flags; | |
634 } | |
635 | |
636 void GraphicsLayerClutter::commitLayerChangesBeforeSublayers(float pageScaleFact
or, const FloatPoint& positionRelativeToBase) | |
637 { | |
638 if (!m_uncommittedChanges) | |
639 return; | |
640 | |
641 // Need to handle Preserves3DChanged first, because it affects which layers
subsequent properties are applied to | |
642 if (m_uncommittedChanges & Preserves3DChanged) | |
643 updateStructuralLayer(); | |
644 | |
645 if (m_uncommittedChanges & GeometryChanged) | |
646 updateGeometry(pageScaleFactor, positionRelativeToBase); | |
647 | |
648 if (m_uncommittedChanges & DrawsContentChanged) | |
649 updateLayerDrawsContent(pageScaleFactor, positionRelativeToBase); | |
650 | |
651 if (m_uncommittedChanges & NameChanged) | |
652 updateLayerNames(); | |
653 | |
654 if (m_uncommittedChanges & TransformChanged) | |
655 updateTransform(); | |
656 | |
657 if (m_uncommittedChanges & OpacityChanged) | |
658 updateOpacityOnLayer(); | |
659 | |
660 if (m_uncommittedChanges & AnimationChanged) | |
661 updateAnimations(); | |
662 | |
663 if (m_uncommittedChanges & DirtyRectsChanged) | |
664 repaintLayerDirtyRects(); | |
665 | |
666 if (m_uncommittedChanges & ChildrenChanged) { | |
667 updateSublayerList(); | |
668 // Sublayers may set this flag again, so clear it to avoid always updati
ng sublayers in commitLayerChangesAfterSublayers(). | |
669 m_uncommittedChanges &= ~ChildrenChanged; | |
670 } | |
671 } | |
672 | |
673 void GraphicsLayerClutter::updateGeometry(float pageScaleFactor, const FloatPoin
t& positionRelativeToBase) | |
674 { | |
675 // FIXME: Need to support page scaling. | |
676 if (m_structuralLayer) { | |
677 clutter_actor_set_position(CLUTTER_ACTOR(m_structuralLayer.get()), m_pos
ition.x(), m_position.y()); | |
678 clutter_actor_set_size(CLUTTER_ACTOR(m_structuralLayer.get()), m_size.wi
dth(), m_size.height()); | |
679 graphicsLayerActorSetAnchorPoint(m_structuralLayer.get(), m_anchorPoint.
x(), m_anchorPoint.y(), m_anchorPoint.z()); | |
680 } | |
681 | |
682 clutter_actor_set_position(CLUTTER_ACTOR(m_layer.get()), m_position.x(), m_p
osition.y()); | |
683 clutter_actor_set_size(CLUTTER_ACTOR(m_layer.get()), m_size.width(), m_size.
height()); | |
684 graphicsLayerActorSetAnchorPoint(m_layer.get(), m_anchorPoint.x(), m_anchorP
oint.y(), m_anchorPoint.z()); | |
685 } | |
686 | |
687 // Each GraphicsLayer has the corresponding layer in the platform port. | |
688 // So whenever the list of child layer changes, the list of GraphicsLayerActor s
hould be updated accordingly. | |
689 void GraphicsLayerClutter::updateSublayerList() | |
690 { | |
691 GraphicsLayerActorList structuralLayerChildren; | |
692 GraphicsLayerActorList primaryLayerChildren; | |
693 | |
694 GraphicsLayerActorList& childListForSublayers = m_structuralLayer ? structur
alLayerChildren : primaryLayerChildren; | |
695 | |
696 if (m_structuralLayer) | |
697 structuralLayerChildren.append(m_layer); | |
698 | |
699 const Vector<GraphicsLayer*>& childLayers = children(); | |
700 size_t numChildren = childLayers.size(); | |
701 for (size_t i = 0; i < numChildren; ++i) { | |
702 GraphicsLayerClutter* currentChild = static_cast<GraphicsLayerClutter*>(
childLayers[i]); | |
703 GraphicsLayerActor* childLayer = currentChild->layerForSuperlayer(); | |
704 ASSERT(GRAPHICS_LAYER_IS_ACTOR(childLayer)); | |
705 childListForSublayers.append(childLayer); | |
706 | |
707 // The child layer only preserves 3D if either itself or its parent has
preserves3D set. | |
708 graphicsLayerActorSetFlatten(childLayer, !(preserves3D() || currentChild
->preserves3D())); | |
709 } | |
710 | |
711 if (m_structuralLayer) | |
712 graphicsLayerActorSetSublayers(m_structuralLayer.get(), structuralLayerC
hildren); | |
713 | |
714 graphicsLayerActorSetSublayers(m_layer.get(), primaryLayerChildren); | |
715 } | |
716 | |
717 void GraphicsLayerClutter::updateLayerNames() | |
718 { | |
719 clutter_actor_set_name(CLUTTER_ACTOR(m_layer.get()), name().utf8().data()); | |
720 } | |
721 | |
722 void GraphicsLayerClutter::updateTransform() | |
723 { | |
724 CoglMatrix matrix = m_transform; | |
725 clutter_actor_set_transform(CLUTTER_ACTOR(primaryLayer()), &matrix); | |
726 } | |
727 | |
728 void GraphicsLayerClutter::updateStructuralLayer() | |
729 { | |
730 ensureStructuralLayer(structuralLayerPurpose()); | |
731 } | |
732 | |
733 void GraphicsLayerClutter::ensureStructuralLayer(StructuralLayerPurpose purpose) | |
734 { | |
735 const LayerChangeFlags structuralLayerChangeFlags = NameChanged | |
736 | GeometryChanged | |
737 | TransformChanged | |
738 | ChildrenTransformChanged | |
739 | ChildrenChanged | |
740 | BackfaceVisibilityChanged | |
741 | OpacityChanged; | |
742 | |
743 if (purpose == NoStructuralLayer) { | |
744 if (m_structuralLayer) { | |
745 // Replace the transformLayer in the parent with this layer. | |
746 graphicsLayerActorRemoveFromSuperLayer(m_layer.get()); | |
747 | |
748 // If m_layer doesn't have a parent, it means it's the root layer an
d | |
749 // is likely hosted by something that is not expecting to be changed | |
750 ClutterActor* parentActor = clutter_actor_get_parent(CLUTTER_ACTOR(m
_structuralLayer.get())); | |
751 ASSERT(parentActor); | |
752 graphicsLayerActorReplaceSublayer(GRAPHICS_LAYER_ACTOR(parentActor),
CLUTTER_ACTOR(m_structuralLayer.get()), CLUTTER_ACTOR(m_layer.get())); | |
753 | |
754 moveOrCopyAnimations(Move, m_structuralLayer.get(), m_layer.get()); | |
755 | |
756 // Release the structural layer. | |
757 m_structuralLayer = 0; | |
758 | |
759 m_uncommittedChanges |= structuralLayerChangeFlags; | |
760 } | |
761 return; | |
762 } | |
763 | |
764 bool structuralLayerChanged = false; | |
765 if (purpose == StructuralLayerForPreserves3D) { | |
766 if (m_structuralLayer && (graphicsLayerActorGetLayerType(m_structuralLay
er.get()) != GraphicsLayerClutter::LayerTypeTransformLayer)) | |
767 m_structuralLayer = 0; | |
768 | |
769 if (!m_structuralLayer) { | |
770 m_structuralLayer = graphicsLayerActorNewWithClient(GraphicsLayerClu
tter::LayerTypeTransformLayer, this); | |
771 structuralLayerChanged = true; | |
772 } | |
773 } else { | |
774 if (m_structuralLayer && (graphicsLayerActorGetLayerType(m_structuralLay
er.get()) != GraphicsLayerClutter::LayerTypeLayer)) | |
775 m_structuralLayer = 0; | |
776 | |
777 if (!m_structuralLayer) { | |
778 m_structuralLayer = graphicsLayerActorNewWithClient(GraphicsLayerClu
tter::LayerTypeLayer, this); | |
779 structuralLayerChanged = true; | |
780 } | |
781 } | |
782 | |
783 if (!structuralLayerChanged) | |
784 return; | |
785 | |
786 m_uncommittedChanges |= structuralLayerChangeFlags; | |
787 | |
788 // We've changed the layer that our parent added to its sublayer list, so te
ll it to update | |
789 // sublayers again in its commitLayerChangesAfterSublayers(). | |
790 static_cast<GraphicsLayerClutter*>(parent())->noteSublayersChanged(); | |
791 | |
792 // Set properties of m_layer to their default values, since these are expres
sed on on the structural layer. | |
793 FloatPoint point(0, 0); | |
794 FloatPoint3D anchorPoint(0.5f, 0.5f, 0); | |
795 clutter_actor_set_position(CLUTTER_ACTOR(m_layer.get()), point.x(), point.y(
)); | |
796 graphicsLayerActorSetAnchorPoint(m_layer.get(), anchorPoint.x(), anchorPoint
.y(), anchorPoint.z()); | |
797 | |
798 CoglMatrix matrix = TransformationMatrix(); | |
799 clutter_actor_set_transform(CLUTTER_ACTOR(m_layer.get()), &matrix); | |
800 | |
801 clutter_actor_set_opacity(CLUTTER_ACTOR(m_layer.get()), 255); | |
802 | |
803 moveOrCopyAnimations(Move, m_layer.get(), m_structuralLayer.get()); | |
804 } | |
805 | |
806 GraphicsLayerClutter::StructuralLayerPurpose GraphicsLayerClutter::structuralLay
erPurpose() const | |
807 { | |
808 if (preserves3D()) | |
809 return StructuralLayerForPreserves3D; | |
810 | |
811 return NoStructuralLayer; | |
812 } | |
813 | |
814 void GraphicsLayerClutter::updateLayerDrawsContent(float pageScaleFactor, const
FloatPoint& positionRelativeToBase) | |
815 { | |
816 if (m_drawsContent) { | |
817 graphicsLayerActorSetDrawsContent(m_layer.get(), TRUE); | |
818 setNeedsDisplay(); | |
819 } else { | |
820 graphicsLayerActorSetDrawsContent(m_layer.get(), FALSE); | |
821 graphicsLayerActorSetSurface(m_layer.get(), 0); | |
822 } | |
823 | |
824 updateDebugIndicators(); | |
825 } | |
826 | |
827 void GraphicsLayerClutter::setupAnimation(PlatformClutterAnimation* propertyAnim
, const Animation* anim, bool additive) | |
828 { | |
829 double duration = anim->duration(); | |
830 if (duration <= 0) | |
831 duration = cAnimationAlmostZeroDuration; | |
832 | |
833 float repeatCount = anim->iterationCount(); | |
834 if (repeatCount == Animation::IterationCountInfinite) | |
835 repeatCount = numeric_limits<float>::max(); | |
836 else if (anim->direction() == Animation::AnimationDirectionAlternate || anim
->direction() == Animation::AnimationDirectionAlternateReverse) | |
837 repeatCount /= 2; | |
838 | |
839 PlatformClutterAnimation::FillModeType fillMode = PlatformClutterAnimation::
NoFillMode; | |
840 switch (anim->fillMode()) { | |
841 case AnimationFillModeNone: | |
842 fillMode = PlatformClutterAnimation::Forwards; // Use "forwards" rather
than "removed" because the style system will remove the animation when it is fin
ished. This avoids a flash. | |
843 break; | |
844 case AnimationFillModeBackwards: | |
845 fillMode = PlatformClutterAnimation::Both; // Use "both" rather than "ba
ckwards" because the style system will remove the animation when it is finished.
This avoids a flash. | |
846 break; | |
847 case AnimationFillModeForwards: | |
848 fillMode = PlatformClutterAnimation::Forwards; | |
849 break; | |
850 case AnimationFillModeBoth: | |
851 fillMode = PlatformClutterAnimation::Both; | |
852 break; | |
853 } | |
854 | |
855 propertyAnim->setDuration(duration); | |
856 propertyAnim->setRepeatCount(repeatCount); | |
857 propertyAnim->setAutoreverses(anim->direction() == Animation::AnimationDirec
tionAlternate || anim->direction() == Animation::AnimationDirectionAlternateReve
rse); | |
858 propertyAnim->setRemovedOnCompletion(false); | |
859 propertyAnim->setAdditive(additive); | |
860 propertyAnim->setFillMode(fillMode); | |
861 } | |
862 | |
863 const TimingFunction* GraphicsLayerClutter::timingFunctionForAnimationValue(cons
t AnimationValue* animValue, const Animation* anim) | |
864 { | |
865 if (animValue->timingFunction()) | |
866 return animValue->timingFunction(); | |
867 if (anim->isTimingFunctionSet()) | |
868 return anim->timingFunction().get(); | |
869 | |
870 return CubicBezierTimingFunction::defaultTimingFunction(); | |
871 } | |
872 | |
873 PassRefPtr<PlatformClutterAnimation> GraphicsLayerClutter::createBasicAnimation(
const Animation* anim, const String& keyPath, bool additive) | |
874 { | |
875 RefPtr<PlatformClutterAnimation> basicAnim = PlatformClutterAnimation::creat
e(PlatformClutterAnimation::Basic, keyPath); | |
876 setupAnimation(basicAnim.get(), anim, additive); | |
877 return basicAnim; | |
878 } | |
879 | |
880 PassRefPtr<PlatformClutterAnimation>GraphicsLayerClutter::createKeyframeAnimatio
n(const Animation* anim, const String& keyPath, bool additive) | |
881 { | |
882 RefPtr<PlatformClutterAnimation> keyframeAnim = PlatformClutterAnimation::cr
eate(PlatformClutterAnimation::Keyframe, keyPath); | |
883 setupAnimation(keyframeAnim.get(), anim, additive); | |
884 return keyframeAnim; | |
885 } | |
886 | |
887 bool GraphicsLayerClutter::setTransformAnimationKeyframes(const KeyframeValueLis
t& valueList, const Animation* animation, PlatformClutterAnimation* keyframeAnim
, int functionIndex, TransformOperation::OperationType transformOpType, bool isM
atrixAnimation, const IntSize& boxSize) | |
888 { | |
889 Vector<float> keyTimes; | |
890 Vector<float> floatValues; | |
891 Vector<FloatPoint3D> floatPoint3DValues; | |
892 Vector<TransformationMatrix> transformationMatrixValues; | |
893 Vector<const TimingFunction*> timingFunctions; | |
894 | |
895 bool forwards = animation->directionIsForwards(); | |
896 | |
897 for (unsigned i = 0; i < valueList.size(); ++i) { | |
898 unsigned index = forwards ? i : (valueList.size() - i - 1); | |
899 const TransformAnimationValue* curValue = static_cast<const TransformAni
mationValue*>(valueList.at(index)); | |
900 keyTimes.append(forwards ? curValue->keyTime() : (1 - curValue->keyTime(
))); | |
901 | |
902 if (isMatrixAnimation) { | |
903 TransformationMatrix transform; | |
904 curValue->value()->apply(boxSize, transform); | |
905 | |
906 // FIXME: In CoreAnimation case, if any matrix is singular, CA won't
animate it correctly. | |
907 // But I'm not sure clutter also does. Check it later, and then deci
de | |
908 // whether removing following lines or not. | |
909 if (!transform.isInvertible()) | |
910 return false; | |
911 | |
912 transformationMatrixValues.append(transform); | |
913 } else { | |
914 const TransformOperation* transformOp = curValue->value()->at(functi
onIndex); | |
915 if (isTransformTypeNumber(transformOpType)) { | |
916 float value; | |
917 getTransformFunctionValue(transformOp, transformOpType, boxSize,
value); | |
918 floatValues.append(value); | |
919 } else if (isTransformTypeFloatPoint3D(transformOpType)) { | |
920 FloatPoint3D value; | |
921 getTransformFunctionValue(transformOp, transformOpType, boxSize,
value); | |
922 floatPoint3DValues.append(value); | |
923 } else { | |
924 TransformationMatrix value; | |
925 getTransformFunctionValue(transformOp, transformOpType, boxSize,
value); | |
926 transformationMatrixValues.append(value); | |
927 } | |
928 } | |
929 | |
930 if (i < (valueList.size() - 1)) | |
931 timingFunctions.append(timingFunctionForAnimationValue(forwards ? cu
rValue : valueList.at(index - 1), animation)); | |
932 } | |
933 | |
934 keyframeAnim->setKeyTimes(keyTimes); | |
935 | |
936 if (isTransformTypeNumber(transformOpType)) | |
937 keyframeAnim->setValues(floatValues); | |
938 else if (isTransformTypeFloatPoint3D(transformOpType)) | |
939 keyframeAnim->setValues(floatPoint3DValues); | |
940 else | |
941 keyframeAnim->setValues(transformationMatrixValues); | |
942 | |
943 keyframeAnim->setTimingFunctions(timingFunctions, !forwards); | |
944 | |
945 PlatformClutterAnimation::ValueFunctionType valueFunction = getValueFunction
NameForTransformOperation(transformOpType); | |
946 if (valueFunction != PlatformClutterAnimation::NoValueFunction) | |
947 keyframeAnim->setValueFunction(valueFunction); | |
948 | |
949 return true; | |
950 } | |
951 | |
952 bool GraphicsLayerClutter::setTransformAnimationEndpoints(const KeyframeValueLis
t& valueList, const Animation* animation, PlatformClutterAnimation* basicAnim, i
nt functionIndex, TransformOperation::OperationType transformOpType, bool isMatr
ixAnimation, const IntSize& boxSize) | |
953 { | |
954 ASSERT(valueList.size() == 2); | |
955 | |
956 bool forwards = animation->directionIsForwards(); | |
957 | |
958 unsigned fromIndex = !forwards; | |
959 unsigned toIndex = forwards; | |
960 | |
961 const TransformAnimationValue* startValue = static_cast<const TransformAnima
tionValue*>(valueList.at(fromIndex)); | |
962 const TransformAnimationValue* endValue = static_cast<const TransformAnimati
onValue*>(valueList.at(toIndex)); | |
963 | |
964 if (isMatrixAnimation) { | |
965 TransformationMatrix fromTransform, toTransform; | |
966 startValue->value()->apply(boxSize, fromTransform); | |
967 endValue->value()->apply(boxSize, toTransform); | |
968 | |
969 // FIXME: If any matrix is singular, CA won't animate it correctly. | |
970 // So fall back to software animation, But it's not sure in clutter case
. | |
971 // We need to investigate it more. | |
972 if (!fromTransform.isInvertible() || !toTransform.isInvertible()) | |
973 return false; | |
974 | |
975 basicAnim->setFromValue(fromTransform); | |
976 basicAnim->setToValue(toTransform); | |
977 } else { | |
978 if (isTransformTypeNumber(transformOpType)) { | |
979 float fromValue; | |
980 getTransformFunctionValue(startValue->value()->at(functionIndex), tr
ansformOpType, boxSize, fromValue); | |
981 basicAnim->setFromValue(fromValue); | |
982 | |
983 float toValue; | |
984 getTransformFunctionValue(endValue->value()->at(functionIndex), tran
sformOpType, boxSize, toValue); | |
985 basicAnim->setToValue(toValue); | |
986 } else if (isTransformTypeFloatPoint3D(transformOpType)) { | |
987 FloatPoint3D fromValue; | |
988 getTransformFunctionValue(startValue->value()->at(functionIndex), tr
ansformOpType, boxSize, fromValue); | |
989 basicAnim->setFromValue(fromValue); | |
990 | |
991 FloatPoint3D toValue; | |
992 getTransformFunctionValue(endValue->value()->at(functionIndex), tran
sformOpType, boxSize, toValue); | |
993 basicAnim->setToValue(toValue); | |
994 } else { | |
995 TransformationMatrix fromValue; | |
996 getTransformFunctionValue(startValue->value()->at(functionIndex), tr
ansformOpType, boxSize, fromValue); | |
997 basicAnim->setFromValue(fromValue); | |
998 | |
999 TransformationMatrix toValue; | |
1000 getTransformFunctionValue(endValue->value()->at(functionIndex), tran
sformOpType, boxSize, toValue); | |
1001 basicAnim->setToValue(toValue); | |
1002 } | |
1003 } | |
1004 | |
1005 // This codepath is used for 2-keyframe animations, so we still need to look
in the start | |
1006 // for a timing function. Even in the reversing animation case, the first ke
yframe provides the timing function. | |
1007 const TimingFunction* timingFunction = timingFunctionForAnimationValue(value
List.at(0), animation); | |
1008 basicAnim->setTimingFunction(timingFunction, !forwards); | |
1009 | |
1010 PlatformClutterAnimation::ValueFunctionType valueFunction = getValueFunction
NameForTransformOperation(transformOpType); | |
1011 if (valueFunction != PlatformClutterAnimation::NoValueFunction) | |
1012 basicAnim->setValueFunction(valueFunction); | |
1013 | |
1014 return true; | |
1015 } | |
1016 | |
1017 bool GraphicsLayerClutter::appendToUncommittedAnimations(const KeyframeValueList
& valueList, const TransformOperations* operations, const Animation* animation,
const String& animationName, const IntSize& boxSize, int animationIndex, double
timeOffset, bool isMatrixAnimation) | |
1018 { | |
1019 TransformOperation::OperationType transformOp = isMatrixAnimation ? Transfor
mOperation::MATRIX_3D : operations->operations().at(animationIndex)->getOperatio
nType(); | |
1020 bool additive = animationIndex > 0; | |
1021 bool isKeyframe = valueList.size() > 2; | |
1022 | |
1023 RefPtr<PlatformClutterAnimation> clutterAnimation; | |
1024 bool validMatrices = true; | |
1025 if (isKeyframe) { | |
1026 clutterAnimation = createKeyframeAnimation(animation, propertyIdToString
(valueList.property()), additive); | |
1027 validMatrices = setTransformAnimationKeyframes(valueList, animation, clu
tterAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize); | |
1028 } else { | |
1029 clutterAnimation = createBasicAnimation(animation, propertyIdToString(va
lueList.property()), additive); | |
1030 validMatrices = setTransformAnimationEndpoints(valueList, animation, clu
tterAnimation.get(), animationIndex, transformOp, isMatrixAnimation, boxSize); | |
1031 } | |
1032 | |
1033 if (!validMatrices) | |
1034 return false; | |
1035 | |
1036 m_uncomittedAnimations.append(LayerPropertyAnimation(clutterAnimation, anima
tionName, valueList.property(), animationIndex, timeOffset)); | |
1037 return true; | |
1038 } | |
1039 | |
1040 bool GraphicsLayerClutter::createTransformAnimationsFromKeyframes(const Keyframe
ValueList& valueList, const Animation* animation, const String& animationName, d
ouble timeOffset, const IntSize& boxSize) | |
1041 { | |
1042 ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); | |
1043 | |
1044 bool hasBigRotation; | |
1045 int listIndex = validateTransformOperations(valueList, hasBigRotation); | |
1046 const TransformOperations* operations = (listIndex >= 0) ? static_cast<const
TransformAnimationValue*>(valueList.at(listIndex))->value() : 0; | |
1047 | |
1048 // We need to fall back to software animation if we don't have setValueFunct
ion:, and | |
1049 // we would need to animate each incoming transform function separately. Thi
s is the | |
1050 // case if we have a rotation >= 180 or we have more than one transform func
tion. | |
1051 if ((hasBigRotation || (operations && operations->size() > 1)) && !PlatformC
lutterAnimation::supportsValueFunction()) | |
1052 return false; | |
1053 | |
1054 bool validMatrices = true; | |
1055 | |
1056 // If function lists don't match we do a matrix animation, otherwise we do a
component hardware animation. | |
1057 // Also, we can't do component animation unless we have valueFunction, so we
need to do matrix animation | |
1058 // if that's not true as well. | |
1059 bool isMatrixAnimation = listIndex < 0 || !PlatformClutterAnimation::support
sValueFunction() || (operations->size() >= 2 && !PlatformClutterAnimation::suppo
rtsAdditiveValueFunction()); | |
1060 int numAnimations = isMatrixAnimation ? 1 : operations->size(); | |
1061 | |
1062 for (int animationIndex = 0; animationIndex < numAnimations; ++animationInde
x) { | |
1063 if (!appendToUncommittedAnimations(valueList, operations, animation, ani
mationName, boxSize, animationIndex, timeOffset, isMatrixAnimation)) { | |
1064 validMatrices = false; | |
1065 break; | |
1066 } | |
1067 } | |
1068 | |
1069 return validMatrices; | |
1070 } | |
1071 | |
1072 bool GraphicsLayerClutter::createAnimationFromKeyframes(const KeyframeValueList&
valueList, const Animation* animation, const String& animationName, double time
Offset) | |
1073 { | |
1074 ASSERT(valueList.property() != AnimatedPropertyWebkitTransform); | |
1075 | |
1076 bool isKeyframe = valueList.size() > 2; | |
1077 bool valuesOK; | |
1078 | |
1079 bool additive = false; | |
1080 int animationIndex = 0; | |
1081 | |
1082 RefPtr<PlatformClutterAnimation> clutterAnimation; | |
1083 | |
1084 if (isKeyframe) { | |
1085 clutterAnimation = createKeyframeAnimation(animation, propertyIdToString
(valueList.property()), additive); | |
1086 valuesOK = setAnimationKeyframes(valueList, animation, clutterAnimation.
get()); | |
1087 } else { | |
1088 clutterAnimation = createBasicAnimation(animation, propertyIdToString(va
lueList.property()), additive); | |
1089 valuesOK = setAnimationEndpoints(valueList, animation, clutterAnimation.
get()); | |
1090 } | |
1091 | |
1092 if (!valuesOK) | |
1093 return false; | |
1094 | |
1095 m_uncomittedAnimations.append(LayerPropertyAnimation(clutterAnimation, anima
tionName, valueList.property(), animationIndex, timeOffset)); | |
1096 | |
1097 return true; | |
1098 } | |
1099 | |
1100 bool GraphicsLayerClutter::addAnimation(const KeyframeValueList& valueList, cons
t IntSize& boxSize, const Animation* anim, const String& animationName, double t
imeOffset) | |
1101 { | |
1102 ASSERT(!animationName.isEmpty()); | |
1103 | |
1104 if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) | |
1105 return false; | |
1106 | |
1107 // FIXME: ClutterTimeline seems to support steps timing function. So we need
to improve here. | |
1108 // See http://developer.gnome.org/clutter/stable/ClutterTimeline.html#Clutte
rAnimationMode | |
1109 if (animationHasStepsTimingFunction(valueList, anim)) | |
1110 return false; | |
1111 | |
1112 bool createdAnimations = false; | |
1113 if (valueList.property() == AnimatedPropertyWebkitTransform) | |
1114 createdAnimations = createTransformAnimationsFromKeyframes(valueList, an
im, animationName, timeOffset, boxSize); | |
1115 else | |
1116 createdAnimations = createAnimationFromKeyframes(valueList, anim, animat
ionName, timeOffset); | |
1117 | |
1118 if (createdAnimations) | |
1119 noteLayerPropertyChanged(AnimationChanged); | |
1120 | |
1121 return createdAnimations; | |
1122 } | |
1123 | |
1124 void GraphicsLayerClutter::removeAnimation(const String& animationName) | |
1125 { | |
1126 if (!animationIsRunning(animationName)) | |
1127 return; | |
1128 | |
1129 m_animationsToProcess.add(animationName, AnimationProcessingAction(Remove)); | |
1130 noteLayerPropertyChanged(AnimationChanged); | |
1131 } | |
1132 | |
1133 bool GraphicsLayerClutter::removeClutterAnimationFromLayer(AnimatedPropertyID pr
operty, const String& animationName, int index) | |
1134 { | |
1135 GraphicsLayerActor* layer = animatedLayer(property); | |
1136 | |
1137 String animationID = animationIdentifier(animationName, property, index); | |
1138 | |
1139 PlatformClutterAnimation* existingAnimation = graphicsLayerActorGetAnimation
ForKey(layer, animationID); | |
1140 if (!existingAnimation) | |
1141 return false; | |
1142 | |
1143 existingAnimation->removeAnimationForKey(layer, animationID); | |
1144 return true; | |
1145 } | |
1146 | |
1147 void GraphicsLayerClutter::pauseClutterAnimationOnLayer(AnimatedPropertyID prope
rty, const String& animationName, int index, double timeOffset) | |
1148 { | |
1149 notImplemented(); | |
1150 } | |
1151 | |
1152 void GraphicsLayerClutter::setAnimationOnLayer(PlatformClutterAnimation* clutter
Anim, AnimatedPropertyID property, const String& animationName, int index, doubl
e timeOffset) | |
1153 { | |
1154 GraphicsLayerActor* layer = animatedLayer(property); | |
1155 | |
1156 if (timeOffset) | |
1157 clutterAnim->setBeginTime(g_get_real_time() - timeOffset); | |
1158 | |
1159 String animationID = animationIdentifier(animationName, property, index); | |
1160 | |
1161 PlatformClutterAnimation* existingAnimation = graphicsLayerActorGetAnimation
ForKey(layer, animationID); | |
1162 if (existingAnimation) | |
1163 existingAnimation->removeAnimationForKey(layer, animationID); | |
1164 | |
1165 clutterAnim->addAnimationForKey(layer, animationID); | |
1166 } | |
1167 | |
1168 bool GraphicsLayerClutter::setAnimationEndpoints(const KeyframeValueList& valueL
ist, const Animation* animation, PlatformClutterAnimation* basicAnim) | |
1169 { | |
1170 bool forwards = animation->directionIsForwards(); | |
1171 | |
1172 unsigned fromIndex = !forwards; | |
1173 unsigned toIndex = forwards; | |
1174 | |
1175 switch (valueList.property()) { | |
1176 case AnimatedPropertyOpacity: { | |
1177 basicAnim->setFromValue(static_cast<const FloatAnimationValue*>(valueLis
t.at(fromIndex))->value()); | |
1178 basicAnim->setToValue(static_cast<const FloatAnimationValue*>(valueList.
at(toIndex))->value()); | |
1179 break; | |
1180 } | |
1181 default: | |
1182 ASSERT_NOT_REACHED(); // we don't animate color yet | |
1183 break; | |
1184 } | |
1185 | |
1186 // This codepath is used for 2-keyframe animations, so we still need to look
in the start | |
1187 // for a timing function. Even in the reversing animation case, the first ke
yframe provides the timing function. | |
1188 const TimingFunction* timingFunction = timingFunctionForAnimationValue(value
List.at(0), animation); | |
1189 if (timingFunction) | |
1190 basicAnim->setTimingFunction(timingFunction, !forwards); | |
1191 | |
1192 return true; | |
1193 } | |
1194 | |
1195 bool GraphicsLayerClutter::setAnimationKeyframes(const KeyframeValueList& valueL
ist, const Animation* animation, PlatformClutterAnimation* keyframeAnim) | |
1196 { | |
1197 Vector<float> keyTimes; | |
1198 Vector<float> values; | |
1199 Vector<const TimingFunction*> timingFunctions; | |
1200 | |
1201 bool forwards = animation->directionIsForwards(); | |
1202 | |
1203 for (unsigned i = 0; i < valueList.size(); ++i) { | |
1204 unsigned index = forwards ? i : (valueList.size() - i - 1); | |
1205 const AnimationValue* curValue = valueList.at(index); | |
1206 keyTimes.append(forwards ? curValue->keyTime() : (1 - curValue->keyTime(
))); | |
1207 | |
1208 switch (valueList.property()) { | |
1209 case AnimatedPropertyOpacity: { | |
1210 const FloatAnimationValue* floatValue = static_cast<const FloatAnima
tionValue*>(curValue); | |
1211 values.append(floatValue->value()); | |
1212 break; | |
1213 } | |
1214 default: | |
1215 ASSERT_NOT_REACHED(); // we don't animate color yet | |
1216 break; | |
1217 } | |
1218 | |
1219 if (i < (valueList.size() - 1)) | |
1220 timingFunctions.append(timingFunctionForAnimationValue(forwards ? cu
rValue : valueList.at(index - 1), animation)); | |
1221 } | |
1222 | |
1223 keyframeAnim->setKeyTimes(keyTimes); | |
1224 keyframeAnim->setValues(values); | |
1225 keyframeAnim->setTimingFunctions(timingFunctions, !forwards); | |
1226 | |
1227 return true; | |
1228 } | |
1229 | |
1230 GraphicsLayerActor* GraphicsLayerClutter::layerForSuperlayer() const | |
1231 { | |
1232 return m_structuralLayer ? m_structuralLayer.get() : m_layer.get(); | |
1233 } | |
1234 | |
1235 GraphicsLayerActor* GraphicsLayerClutter::animatedLayer(AnimatedPropertyID prope
rty) const | |
1236 { | |
1237 return primaryLayer(); | |
1238 } | |
1239 | |
1240 } // namespace WebCore | |
1241 | |
1242 #endif // USE(ACCELERATED_COMPOSITING) | |
OLD | NEW |