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

Side by Side Diff: Source/core/animation/CompositorAnimations.cpp

Issue 1196913005: Implement animations for Independent CSS Transform Properties (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 6 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
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 return Animation::hasLowerPriority(&animationToAdd, &animation); 89 return Animation::hasLowerPriority(&animationToAdd, &animation);
90 default: 90 default:
91 ASSERT_NOT_REACHED(); 91 ASSERT_NOT_REACHED();
92 return true; 92 return true;
93 } 93 }
94 } 94 }
95 95
96 bool hasIncompatibleAnimations(const Element& targetElement, const Animation& an imationToAdd, const EffectModel& effectToAdd) 96 bool hasIncompatibleAnimations(const Element& targetElement, const Animation& an imationToAdd, const EffectModel& effectToAdd)
97 { 97 {
98 const bool affectsOpacity = effectToAdd.affects(PropertyHandle(CSSPropertyOp acity)); 98 const bool affectsOpacity = effectToAdd.affects(PropertyHandle(CSSPropertyOp acity));
99 const bool affectsTransform = effectToAdd.affects(PropertyHandle(CSSProperty Transform)); 99 const bool affectsTransform = effectToAdd.affects(PropertyHandle(CSSProperty Transform))
100 || effectToAdd.affects(PropertyHandle(CSSPropertyTranslate))
101 || effectToAdd.affects(PropertyHandle(CSSPropertyRotate))
102 || effectToAdd.affects(PropertyHandle(CSSPropertyScale));
100 const bool affectsFilter = effectToAdd.affects(PropertyHandle(CSSPropertyWeb kitFilter)); 103 const bool affectsFilter = effectToAdd.affects(PropertyHandle(CSSPropertyWeb kitFilter));
101 104
102 if (!targetElement.hasAnimations()) 105 if (!targetElement.hasAnimations())
103 return false; 106 return false;
104 107
105 ElementAnimations* elementAnimations = targetElement.elementAnimations(); 108 ElementAnimations* elementAnimations = targetElement.elementAnimations();
106 ASSERT(elementAnimations); 109 ASSERT(elementAnimations);
107 110
108 for (const auto& entry : elementAnimations->animations()) { 111 for (const auto& entry : elementAnimations->animations()) {
109 const Animation* attachedAnimation = entry.key; 112 const Animation* attachedAnimation = entry.key;
110 if (!considerAnimationAsIncompatible(*attachedAnimation, animationToAdd) ) 113 if (!considerAnimationAsIncompatible(*attachedAnimation, animationToAdd) )
111 continue; 114 continue;
112 115
113 if ((affectsOpacity && attachedAnimation->affects(targetElement, CSSProp ertyOpacity)) 116 if ((affectsOpacity && attachedAnimation->affects(targetElement, CSSProp ertyOpacity))
117 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyTranslate))
118 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyScale))
119 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyRotate))
114 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyTransform)) 120 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyTransform))
115 || (affectsFilter && attachedAnimation->affects(targetElement, CSSPr opertyWebkitFilter))) 121 || (affectsFilter && attachedAnimation->affects(targetElement, CSSPr opertyWebkitFilter)))
116 return true; 122 return true;
117 } 123 }
118 124
119 return false; 125 return false;
120 } 126 }
121 127
122 } 128 }
123 129
124 CSSPropertyID CompositorAnimations::CompositableProperties[3] = { 130 CSSPropertyID CompositorAnimations::CompositableProperties[6] = {
125 CSSPropertyOpacity, CSSPropertyTransform, CSSPropertyWebkitFilter 131 CSSPropertyOpacity,
132 CSSPropertyTransform,
133 CSSPropertyWebkitFilter,
134 CSSPropertyTranslate,
135 CSSPropertyRotate,
136 CSSPropertyScale
126 }; 137 };
127 138
128 bool CompositorAnimations::getAnimatedBoundingBox(FloatBox& box, const EffectMod el& effect, double minValue, double maxValue) const 139 bool CompositorAnimations::getAnimatedBoundingBox(FloatBox& box, const EffectMod el& effect, double minValue, double maxValue) const
129 { 140 {
130 const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(ef fect); 141 const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(ef fect);
131 142
132 PropertyHandleSet properties = keyframeEffect.properties(); 143 PropertyHandleSet properties = keyframeEffect.properties();
133 144
134 if (properties.isEmpty()) 145 if (properties.isEmpty())
135 return true; 146 return true;
136 147
137 minValue = std::min(minValue, 0.0); 148 minValue = std::min(minValue, 0.0);
138 maxValue = std::max(maxValue, 1.0); 149 maxValue = std::max(maxValue, 1.0);
139 150
140 for (const auto& property : properties) { 151 for (const auto& property : properties) {
141 if (!property.isCSSProperty()) 152 if (!property.isCSSProperty())
142 continue; 153 continue;
143 154
144 // TODO: Add the ability to get expanded bounds for filters as well. 155 // TODO: Add the ability to get expanded bounds for filters as well.
145 if (property.cssProperty() != CSSPropertyTransform) 156 if (property.cssProperty() != CSSPropertyTransform
157 || property.cssProperty() != CSSPropertyTranslate
158 || property.cssProperty() != CSSPropertyRotate
159 || property.cssProperty() != CSSPropertyScale)
146 continue; 160 continue;
147 161
148 const PropertySpecificKeyframeVector& frames = keyframeEffect.getPropert ySpecificKeyframes(property); 162 const PropertySpecificKeyframeVector& frames = keyframeEffect.getPropert ySpecificKeyframes(property);
149 if (frames.isEmpty() || frames.size() < 2) 163 if (frames.isEmpty() || frames.size() < 2)
150 continue; 164 continue;
151 165
152 FloatBox originalBox(box); 166 FloatBox originalBox(box);
153 167
154 for (size_t j = 0; j < frames.size() - 1; ++j) { 168 for (size_t j = 0; j < frames.size() - 1; ++j) {
155 const AnimatableTransform* startTransform = toAnimatableTransform(fr ames[j]->getAnimatableValue().get()); 169 const AnimatableTransform* startTransform = toAnimatableTransform(fr ames[j]->getAnimatableValue().get());
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 // ----------------------------------------------------------------------- 207 // -----------------------------------------------------------------------
194 208
195 bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& tim ing, const Element& targetElement, const Animation* animationToAdd, const Effect Model& effect, double animationPlaybackRate) 209 bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& tim ing, const Element& targetElement, const Animation* animationToAdd, const Effect Model& effect, double animationPlaybackRate)
196 { 210 {
197 const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(ef fect); 211 const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(ef fect);
198 212
199 PropertyHandleSet properties = keyframeEffect.properties(); 213 PropertyHandleSet properties = keyframeEffect.properties();
200 if (properties.isEmpty()) 214 if (properties.isEmpty())
201 return false; 215 return false;
202 216
217 unsigned transformOperationCount = 0;
203 for (const auto& property : properties) { 218 for (const auto& property : properties) {
204 if (!property.isCSSProperty()) 219 if (!property.isCSSProperty())
205 return false; 220 return false;
206 221
222 if (property.cssProperty() == CSSPropertyTransform
223 || property.cssProperty() == CSSPropertyTranslate
224 || property.cssProperty() == CSSPropertyScale
225 || property.cssProperty() == CSSPropertyRotate)
226 transformOperationCount++;
227
207 const PropertySpecificKeyframeVector& keyframes = keyframeEffect.getProp ertySpecificKeyframes(property); 228 const PropertySpecificKeyframeVector& keyframes = keyframeEffect.getProp ertySpecificKeyframes(property);
208 ASSERT(keyframes.size() >= 2); 229 ASSERT(keyframes.size() >= 2);
209 for (const auto& keyframe : keyframes) { 230 for (const auto& keyframe : keyframes) {
210 // FIXME: Determine candidacy based on the CSSValue instead of a sna pshot AnimatableValue. 231 // FIXME: Determine candidacy based on the CSSValue instead of a sna pshot AnimatableValue.
211 bool isNeutralKeyframe = keyframe->isCSSPropertySpecificKeyframe() & & !toCSSPropertySpecificKeyframe(keyframe.get())->value() && keyframe->composite () == EffectModel::CompositeAdd; 232 bool isNeutralKeyframe = keyframe->isCSSPropertySpecificKeyframe() & & !toCSSPropertySpecificKeyframe(keyframe.get())->value() && keyframe->composite () == EffectModel::CompositeAdd;
212 if ((keyframe->composite() != EffectModel::CompositeReplace && !isNe utralKeyframe) || !keyframe->getAnimatableValue()) 233 if ((keyframe->composite() != EffectModel::CompositeReplace && !isNe utralKeyframe) || !keyframe->getAnimatableValue())
213 return false; 234 return false;
214 235
215 switch (property.cssProperty()) { 236 switch (property.cssProperty()) {
216 case CSSPropertyOpacity: 237 case CSSPropertyOpacity:
217 break; 238 break;
239 /* Intentional fallthrough */
240 case CSSPropertyTranslate:
241 case CSSPropertyRotate:
242 case CSSPropertyScale:
218 case CSSPropertyTransform: 243 case CSSPropertyTransform:
219 if (toAnimatableTransform(keyframe->getAnimatableValue().get())- >transformOperations().dependsOnBoxSize()) 244 if (toAnimatableTransform(keyframe->getAnimatableValue().get())- >transformOperations().dependsOnBoxSize())
220 return false; 245 return false;
221 break; 246 break;
222 case CSSPropertyWebkitFilter: { 247 case CSSPropertyWebkitFilter: {
223 const FilterOperations& operations = toAnimatableFilterOperation s(keyframe->getAnimatableValue().get())->operations(); 248 const FilterOperations& operations = toAnimatableFilterOperation s(keyframe->getAnimatableValue().get())->operations();
224 if (operations.hasFilterThatMovesPixels()) 249 if (operations.hasFilterThatMovesPixels())
225 return false; 250 return false;
226 break; 251 break;
227 } 252 }
228 default: 253 default:
229 // any other types are not allowed to run on compositor. 254 // any other types are not allowed to run on compositor.
230 return false; 255 return false;
231 } 256 }
232 } 257 }
233 } 258 }
259 if (transformOperationCount > 1)
260 return false;
234 261
235 if (animationToAdd && hasIncompatibleAnimations(targetElement, *animationToA dd, effect)) 262 if (animationToAdd && hasIncompatibleAnimations(targetElement, *animationToA dd, effect))
236 return false; 263 return false;
237 264
238 CompositorAnimationsImpl::CompositorTiming out; 265 CompositorAnimationsImpl::CompositorTiming out;
239 if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, 0, out, an imationPlaybackRate)) 266 if (!CompositorAnimationsImpl::convertTimingForCompositor(timing, 0, out, an imationPlaybackRate))
240 return false; 267 return false;
241 268
242 return true; 269 return true;
243 } 270 }
244 271
245 void CompositorAnimations::cancelIncompatibleAnimationsOnCompositor(const Elemen t& targetElement, const Animation& animationToAdd, const EffectModel& effectToAd d) 272 void CompositorAnimations::cancelIncompatibleAnimationsOnCompositor(const Elemen t& targetElement, const Animation& animationToAdd, const EffectModel& effectToAd d)
246 { 273 {
274
247 const bool affectsOpacity = effectToAdd.affects(PropertyHandle(CSSPropertyOp acity)); 275 const bool affectsOpacity = effectToAdd.affects(PropertyHandle(CSSPropertyOp acity));
248 const bool affectsTransform = effectToAdd.affects(PropertyHandle(CSSProperty Transform)); 276 const bool affectsTransform = effectToAdd.affects(PropertyHandle(CSSProperty Transform))
277 || effectToAdd.affects(PropertyHandle(CSSPropertyTranslate))
278 || effectToAdd.affects(PropertyHandle(CSSPropertyRotate))
279 || effectToAdd.affects(PropertyHandle(CSSPropertyScale));
249 const bool affectsFilter = effectToAdd.affects(PropertyHandle(CSSPropertyWeb kitFilter)); 280 const bool affectsFilter = effectToAdd.affects(PropertyHandle(CSSPropertyWeb kitFilter));
250 281
251 if (!targetElement.hasAnimations()) 282 if (!targetElement.hasAnimations())
252 return; 283 return;
253 284
254 ElementAnimations* elementAnimations = targetElement.elementAnimations(); 285 ElementAnimations* elementAnimations = targetElement.elementAnimations();
255 ASSERT(elementAnimations); 286 ASSERT(elementAnimations);
256 287
257 for (const auto& entry : elementAnimations->animations()) { 288 for (const auto& entry : elementAnimations->animations()) {
258 Animation* attachedAnimation = entry.key; 289 Animation* attachedAnimation = entry.key;
259 if (!considerAnimationAsIncompatible(*attachedAnimation, animationToAdd) ) 290 if (!considerAnimationAsIncompatible(*attachedAnimation, animationToAdd) )
260 continue; 291 continue;
261 292
262 if ((affectsOpacity && attachedAnimation->affects(targetElement, CSSProp ertyOpacity)) 293 if ((affectsOpacity && attachedAnimation->affects(targetElement, CSSProp ertyOpacity))
294 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyTranslate))
295 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyScale))
296 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyRotate))
263 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyTransform)) 297 || (affectsTransform && attachedAnimation->affects(targetElement, CS SPropertyTransform))
264 || (affectsFilter && attachedAnimation->affects(targetElement, CSSPr opertyWebkitFilter))) 298 || (affectsFilter && attachedAnimation->affects(targetElement, CSSPr opertyWebkitFilter)))
265 attachedAnimation->cancelAnimationOnCompositor(); 299 attachedAnimation->cancelAnimationOnCompositor();
266 } 300 }
267 } 301 }
268 302
269 bool CompositorAnimations::canStartAnimationOnCompositor(const Element& element) 303 bool CompositorAnimations::canStartAnimationOnCompositor(const Element& element)
270 { 304 {
271 return element.layoutObject() && element.layoutObject()->compositingState() == PaintsIntoOwnBacking; 305 return element.layoutObject() && element.layoutObject()->compositingState() == PaintsIntoOwnBacking;
272 } 306 }
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 break; 657 break;
624 } 658 }
625 case CSSPropertyWebkitFilter: { 659 case CSSPropertyWebkitFilter: {
626 targetProperty = WebCompositorAnimation::TargetPropertyFilter; 660 targetProperty = WebCompositorAnimation::TargetPropertyFilter;
627 WebFilterAnimationCurve* filterCurve = Platform::current()->composit orSupport()->createFilterAnimationCurve(); 661 WebFilterAnimationCurve* filterCurve = Platform::current()->composit orSupport()->createFilterAnimationCurve();
628 addKeyframesToCurve(*filterCurve, values, timing); 662 addKeyframesToCurve(*filterCurve, values, timing);
629 setTimingFunctionOnCurve(*filterCurve, timing.timingFunction.get()); 663 setTimingFunctionOnCurve(*filterCurve, timing.timingFunction.get());
630 curve = adoptPtr(filterCurve); 664 curve = adoptPtr(filterCurve);
631 break; 665 break;
632 } 666 }
667 /* Intentional fallthrough */
668 case CSSPropertyTranslate:
669 case CSSPropertyRotate:
670 case CSSPropertyScale:
633 case CSSPropertyTransform: { 671 case CSSPropertyTransform: {
634 targetProperty = WebCompositorAnimation::TargetPropertyTransform; 672 targetProperty = WebCompositorAnimation::TargetPropertyTransform;
635 WebTransformAnimationCurve* transformCurve = Platform::current()->co mpositorSupport()->createTransformAnimationCurve(); 673 WebTransformAnimationCurve* transformCurve = Platform::current()->co mpositorSupport()->createTransformAnimationCurve();
636 addKeyframesToCurve(*transformCurve, values, timing); 674 addKeyframesToCurve(*transformCurve, values, timing);
637 setTimingFunctionOnCurve(*transformCurve, timing.timingFunction.get( )); 675 setTimingFunctionOnCurve(*transformCurve, timing.timingFunction.get( ));
638 curve = adoptPtr(transformCurve); 676 curve = adoptPtr(transformCurve);
639 break; 677 break;
640 } 678 }
641 default: 679 default:
642 ASSERT_NOT_REACHED(); 680 ASSERT_NOT_REACHED();
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 break; 724 break;
687 default: 725 default:
688 ASSERT_NOT_REACHED(); 726 ASSERT_NOT_REACHED();
689 } 727 }
690 animations.append(animation.release()); 728 animations.append(animation.release());
691 } 729 }
692 ASSERT(!animations.isEmpty()); 730 ASSERT(!animations.isEmpty());
693 } 731 }
694 732
695 } // namespace blink 733 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698