1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "config.h" 18 #include "AndroidAnimation.h" 19 20 #if USE(ACCELERATED_COMPOSITING) 21 22 #include "Animation.h" 23 #include "GraphicsLayerAndroid.h" 24 25 #include "Timer.h" 26 #include "TimingFunction.h" 27 #include "TranslateTransformOperation.h" 28 #include "UnitBezier.h" 29 30 #include <wtf/CurrentTime.h> 31 #include <cutils/log.h> 32 #include <wtf/text/CString.h> 33 34 #undef XLOGC 35 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__) 36 37 #ifdef DEBUG 38 39 #undef XLOG 40 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__) 41 42 #else 43 44 #undef XLOG 45 #define XLOG(...) 46 47 #endif // DEBUG 48 49 50 namespace WebCore { 51 52 static int gUniqueId; 53 54 static long gDebugAndroidAnimationInstances; 55 56 long AndroidAnimation::instancesCount() 57 { 58 return gDebugAndroidAnimationInstances; 59 } 60 61 AndroidAnimation::AndroidAnimation(AnimatedPropertyID type, 62 const Animation* animation, 63 KeyframeValueList* operations, 64 double beginTime) 65 : m_beginTime(beginTime) 66 , m_duration(animation->duration()) 67 , m_fillsBackwards(animation->fillsBackwards()) 68 , m_fillsForwards(animation->fillsForwards()) 69 , m_iterationCount(animation->iterationCount()) 70 , m_direction(animation->direction()) 71 , m_timingFunction(animation->timingFunction()) 72 , m_type(type) 73 , m_operations(operations) 74 , m_uniqueId(++gUniqueId) 75 , m_hasFinished(false) 76 { 77 ASSERT(m_timingFunction); 78 79 gDebugAndroidAnimationInstances++; 80 } 81 82 AndroidAnimation::~AndroidAnimation() 83 { 84 gDebugAndroidAnimationInstances--; 85 } 86 87 void AndroidAnimation::suggestBeginTime(double time) 88 { 89 if (m_beginTime <= 0.000001) // overflow or not yet set 90 m_beginTime = time; 91 } 92 93 double AndroidAnimation::elapsedTime(double time) 94 { 95 double elapsedTime = (m_beginTime < 0.000001) ? 0 : time - m_beginTime; 96 97 if (m_duration <= 0) 98 m_duration = 0.000001; 99 100 if (elapsedTime < 0) // animation not yet started. 101 return 0; 102 103 return elapsedTime; 104 } 105 106 bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress) 107 { 108 double progress = elapsedTime(time); 109 double dur = m_duration; 110 if (m_iterationCount > 0) 111 dur *= m_iterationCount; 112 113 if (m_duration <= 0) 114 return false; 115 116 // If not infinite, return false if we are done 117 if (m_iterationCount > 0 && progress > dur) { 118 *finalProgress = 1.0; 119 if (!m_hasFinished) { 120 // first time past duration, continue with progress 1.0 so the 121 // element's final position lines up with it's last keyframe 122 m_hasFinished = true; 123 return true; 124 } 125 126 return false; 127 } 128 129 double fractionalTime = progress / m_duration; 130 int integralTime = static_cast<int>(fractionalTime); 131 132 fractionalTime -= integralTime; 133 134 if ((m_direction == Animation::AnimationDirectionAlternate) && (integralTime & 1)) 135 fractionalTime = 1 - fractionalTime; 136 137 *finalProgress = fractionalTime; 138 return true; 139 } 140 141 double AndroidAnimation::applyTimingFunction(float from, float to, double progress, 142 const TimingFunction* tf) 143 { 144 double fractionalTime = progress; 145 double offset = from; 146 double scale = 1.0 / (to - from); 147 148 if (scale != 1 || offset) 149 fractionalTime = (fractionalTime - offset) * scale; 150 151 const TimingFunction* timingFunction = tf; 152 153 if (!timingFunction) 154 timingFunction = m_timingFunction.get(); 155 156 if (timingFunction && timingFunction->isCubicBezierTimingFunction()) { 157 const CubicBezierTimingFunction* bezierFunction = static_cast<const CubicBezierTimingFunction*>(timingFunction); 158 UnitBezier bezier(bezierFunction->x1(), 159 bezierFunction->y1(), 160 bezierFunction->x2(), 161 bezierFunction->y2()); 162 if (m_duration > 0) 163 fractionalTime = bezier.solve(fractionalTime, 1.0f / (200.0f * m_duration)); 164 } else if (timingFunction && timingFunction->isStepsTimingFunction()) { 165 const StepsTimingFunction* stepFunction = static_cast<const StepsTimingFunction*>(timingFunction); 166 if (stepFunction->stepAtStart()) { 167 fractionalTime = (floor(stepFunction->numberOfSteps() * fractionalTime) + 1) / stepFunction->numberOfSteps(); 168 if (fractionalTime > 1.0) 169 fractionalTime = 1.0; 170 } else { 171 fractionalTime = floor(stepFunction->numberOfSteps() * fractionalTime) / stepFunction->numberOfSteps(); 172 } 173 } 174 return fractionalTime; 175 } 176 177 bool AndroidAnimation::evaluate(LayerAndroid* layer, double time) 178 { 179 float progress; 180 if (!checkIterationsAndProgress(time, &progress) 181 && !(m_fillsBackwards || m_fillsForwards)) 182 return false; 183 184 if (progress < 0) { 185 // The animation hasn't started yet 186 if (m_fillsBackwards || m_beginTime <= 0.000001) { 187 // in this case we want to apply the initial keyframe to the layer 188 applyForProgress(layer, 0); 189 } 190 // we still want to be evaluated until we get progress > 0 191 return true; 192 } 193 194 if (progress > 1) { 195 if (!m_fillsForwards) 196 return false; 197 progress = 1; 198 } 199 200 if (!m_operations->size()) 201 return false; 202 203 applyForProgress(layer, progress); 204 205 return true; 206 } 207 208 PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create( 209 const Animation* animation, 210 KeyframeValueList* operations, 211 double beginTime) 212 { 213 return adoptRef(new AndroidOpacityAnimation(animation, operations, 214 beginTime)); 215 } 216 217 AndroidOpacityAnimation::AndroidOpacityAnimation(const Animation* animation, 218 KeyframeValueList* operations, 219 double beginTime) 220 : AndroidAnimation(AnimatedPropertyOpacity, animation, operations, beginTime) 221 { 222 } 223 224 void AndroidAnimation::pickValues(double progress, int* start, int* end) 225 { 226 float distance = -1; 227 unsigned int foundAt = 0; 228 for (unsigned int i = 0; i < m_operations->size(); i++) { 229 const AnimationValue* value = m_operations->at(i); 230 float key = value->keyTime(); 231 float d = progress - key; 232 if (distance == -1 || (d >= 0 && d < distance && i + 1 < m_operations->size())) { 233 distance = d; 234 foundAt = i; 235 } 236 } 237 238 *start = foundAt; 239 240 if (foundAt + 1 < m_operations->size()) 241 *end = foundAt + 1; 242 else 243 *end = foundAt; 244 } 245 246 void AndroidOpacityAnimation::applyForProgress(LayerAndroid* layer, float progress) 247 { 248 // First, we need to get the from and to values 249 int from, to; 250 pickValues(progress, &from, &to); 251 FloatAnimationValue* fromValue = (FloatAnimationValue*) m_operations->at(from); 252 FloatAnimationValue* toValue = (FloatAnimationValue*) m_operations->at(to); 253 254 XLOG("[layer %d] opacity fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f", 255 layer->uniqueId(), 256 fromValue, fromValue->keyTime(), 257 toValue, toValue->keyTime(), progress); 258 259 // We now have the correct two values to work with, let's compute the 260 // progress value 261 262 const TimingFunction* timingFunction = fromValue->timingFunction(); 263 progress = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(), 264 progress, timingFunction); 265 266 267 float value = fromValue->value() + ((toValue->value() - fromValue->value()) * progress); 268 269 layer->setOpacity(value); 270 } 271 272 PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create( 273 const Animation* animation, 274 KeyframeValueList* operations, 275 double beginTime) 276 { 277 return adoptRef(new AndroidTransformAnimation(animation, operations, beginTime)); 278 } 279 280 AndroidTransformAnimation::AndroidTransformAnimation(const Animation* animation, 281 KeyframeValueList* operations, 282 double beginTime) 283 : AndroidAnimation(AnimatedPropertyWebkitTransform, animation, operations, beginTime) 284 { 285 } 286 287 void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress) 288 { 289 // First, we need to get the from and to values 290 int from, to; 291 pickValues(progress, &from, &to); 292 293 TransformAnimationValue* fromValue = (TransformAnimationValue*) m_operations->at(from); 294 TransformAnimationValue* toValue = (TransformAnimationValue*) m_operations->at(to); 295 296 XLOG("[layer %d] fromValue %x, key %.2f, toValue %x, key %.2f for progress %.2f", 297 layer->uniqueId(), 298 fromValue, fromValue->keyTime(), 299 toValue, toValue->keyTime(), progress); 300 301 // We now have the correct two values to work with, let's compute the 302 // progress value 303 304 const TimingFunction* timingFunction = fromValue->timingFunction(); 305 float p = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(), 306 progress, timingFunction); 307 XLOG("progress %.2f => %.2f from: %.2f to: %.2f", progress, p, fromValue->keyTime(), 308 toValue->keyTime()); 309 progress = p; 310 311 // With both values and the progress, we also need to check out that 312 // the operations are compatible (i.e. we are animating the same number 313 // of values; if not we do a matrix blend) 314 315 TransformationMatrix transformMatrix; 316 bool valid = true; 317 unsigned int fromSize = fromValue->value()->size(); 318 if (fromSize) { 319 if (toValue->value()->size() != fromSize) 320 valid = false; 321 else { 322 for (unsigned int j = 0; j < fromSize && valid; j++) { 323 if (!fromValue->value()->operations()[j]->isSameType( 324 *toValue->value()->operations()[j])) 325 valid = false; 326 } 327 } 328 } 329 330 IntSize size(layer->getSize().width(), layer->getSize().height()); 331 if (valid) { 332 for (size_t i = 0; i < toValue->value()->size(); ++i) 333 toValue->value()->operations()[i]->blend(fromValue->value()->at(i), 334 progress)->apply(transformMatrix, size); 335 } else { 336 TransformationMatrix source; 337 338 fromValue->value()->apply(size, source); 339 toValue->value()->apply(size, transformMatrix); 340 341 transformMatrix.blend(source, progress); 342 } 343 344 // Set the final transform on the layer 345 layer->setTransform(transformMatrix); 346 } 347 348 } // namespace WebCore 349 350 #endif // USE(ACCELERATED_COMPOSITING) 351