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