| 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 |