Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(830)

Side by Side Diff: Source/WebCore/platform/graphics/clutter/GraphicsLayerClutter.cpp

Issue 13724012: Remove Cairo support. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698