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

Unified Diff: third_party/WebKit/Source/core/animation/EffectInput.cpp

Issue 1720403002: Alternative syntax for element.animate list of keyframes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@animations-keyframeeffect-api
Patch Set: Fill in error message strings Created 4 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/animation/EffectInput.cpp
diff --git a/third_party/WebKit/Source/core/animation/EffectInput.cpp b/third_party/WebKit/Source/core/animation/EffectInput.cpp
index 04fad6a5a5c41f59512f67b913d53b71305c1114..7cc8c3d3013aa22280bf1d2714c1eeb79e7e5f9b 100644
--- a/third_party/WebKit/Source/core/animation/EffectInput.cpp
+++ b/third_party/WebKit/Source/core/animation/EffectInput.cpp
@@ -47,12 +47,82 @@
namespace blink {
+namespace {
+bool compareKeyframes(const RefPtr<StringKeyframe>& a, const RefPtr<StringKeyframe>& b)
+{
+ return (a->offset() < b->offset());
alancutter (OOO until 2018) 2016/02/24 08:50:02 No need for the outer brackets.
suzyh_UTC10 (ex-contributor) 2016/02/25 02:42:35 Done.
+}
+} // namespace
alancutter (OOO until 2018) 2016/02/24 08:50:02 Blank lines around the namespace boundaries.
suzyh_UTC10 (ex-contributor) 2016/02/25 02:42:36 Done.
+
+EffectModel* EffectInput::convert(Element* element, const EffectModelOrDictionarySequenceOrDictionary& effectInput, ExceptionState& exceptionState)
+{
+ if (effectInput.isEffectModel())
+ return effectInput.getAsEffectModel();
+ if (effectInput.isDictionarySequence())
+ return convert(element, effectInput.getAsDictionarySequence(), exceptionState);
+ if (effectInput.isDictionary()) {
+ return convert(element, effectInput.getAsDictionary(), exceptionState);
+ }
+ return nullptr;
+}
+
+bool EffectInput::setKeyframeValue(Element* element, StringKeyframe* keyframe, const String& property, const String& value)
alancutter (OOO until 2018) 2016/02/24 08:50:02 Blink style dictates the element and keyframe para
suzyh_UTC10 (ex-contributor) 2016/02/25 02:42:35 I'm happy to make the keyframe parameter a StringK
alancutter (OOO until 2018) 2016/02/25 06:52:27 If a function dereferences it without performing a
suzyh_UTC10 (ex-contributor) 2016/02/26 04:35:30 Done.
+{
+ StyleSheetContents* styleSheetContents = element->document().elementSheet().contents();
+ CSSPropertyID cssProperty = AnimationInputHelpers::keyframeAttributeToCSSProperty(property, element->document());
+ if (cssProperty != CSSPropertyInvalid) {
+ keyframe->setCSSPropertyValue(cssProperty, value, element, styleSheetContents);
+ return CompositorAnimations::isCompositableProperty(cssProperty);
+ }
+ cssProperty = AnimationInputHelpers::keyframeAttributeToPresentationAttribute(property, *element);
+ if (cssProperty != CSSPropertyInvalid) {
+ keyframe->setPresentationAttributeValue(cssProperty, value, element, styleSheetContents);
+ return false;
+ }
+ const QualifiedName* svgAttribute = AnimationInputHelpers::keyframeAttributeToSVGAttribute(property, *element);
+ if (svgAttribute)
+ keyframe->setSVGAttributeValue(*svgAttribute, value);
+ return false;
+}
+
+// TODO(alancutter): Remove this once composited animations no longer depend on AnimatableValues.
+void EffectInput::updateElementStyleIfNeeded(Element* element, bool encounteredCompositableProperty)
+{
+ if (encounteredCompositableProperty && element->inActiveDocument())
+ element->document().updateLayoutTreeForNodeIfNeeded(element);
alancutter (OOO until 2018) 2016/02/24 08:50:02 This code always needs to be run before the call t
suzyh_UTC10 (ex-contributor) 2016/02/25 02:42:35 Done.
+}
+
+EffectModel* EffectInput::createEffectModelFromKeyframes(Element* element, const StringKeyframeVector& keyframes, ExceptionState& exceptionState)
alancutter (OOO until 2018) 2016/02/24 08:50:02 element should be a reference.
+{
+ StringKeyframeEffectModel* keyframeEffectModel = StringKeyframeEffectModel::create(keyframes);
+ if (!RuntimeEnabledFeatures::cssAdditiveAnimationsEnabled()) {
+ for (const auto& keyframeGroup : keyframeEffectModel->getPropertySpecificKeyframeGroups()) {
+ PropertyHandle property = keyframeGroup.key;
+ if (!property.isCSSProperty())
+ continue;
+
+ for (const auto& keyframe : keyframeGroup.value->keyframes()) {
+ if (keyframe->isNeutral()) {
+ exceptionState.throwDOMException(NotSupportedError, "Partial keyframes are not supported.");
+ return nullptr;
+ }
+ if (keyframe->composite() != EffectModel::CompositeReplace) {
+ exceptionState.throwDOMException(NotSupportedError, "Additive animations are not supported.");
+ return nullptr;
+ }
+ }
+ }
+ }
+ keyframeEffectModel->forceConversionsToAnimatableValues(*element, element->computedStyle());
+
+ return keyframeEffectModel;
+}
+
EffectModel* EffectInput::convert(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
{
if (!element)
return nullptr;
- StyleSheetContents* styleSheetContents = element->document().elementSheet().contents();
StringKeyframeVector keyframes;
double lastOffset = 0;
bool encounteredCompositableProperty = false;
@@ -86,7 +156,6 @@ EffectModel* EffectInput::convert(Element* element, const Vector<Dictionary>& ke
keyframe->setOffset(offset);
}
- keyframes.append(keyframe);
String compositeString;
DictionaryHelper::get(keyframeDictionary, "composite", compositeString);
@@ -103,76 +172,93 @@ EffectModel* EffectInput::convert(Element* element, const Vector<Dictionary>& ke
Vector<String> keyframeProperties;
keyframeDictionary.getPropertyNames(keyframeProperties);
for (const auto& property : keyframeProperties) {
- String value;
- DictionaryHelper::get(keyframeDictionary, property, value);
-
- CSSPropertyID cssProperty = AnimationInputHelpers::keyframeAttributeToCSSProperty(property, element->document());
- if (cssProperty != CSSPropertyInvalid) {
- if (!encounteredCompositableProperty && CompositorAnimations::isCompositableProperty(cssProperty))
- encounteredCompositableProperty = true;
-
- keyframe->setCSSPropertyValue(cssProperty, value, element, styleSheetContents);
- continue;
- }
-
if (property == "offset"
|| property == "composite"
|| property == "easing") {
continue;
}
- cssProperty = AnimationInputHelpers::keyframeAttributeToPresentationAttribute(property, *element);
- if (cssProperty != CSSPropertyInvalid) {
- keyframe->setPresentationAttributeValue(cssProperty, value, element, styleSheetContents);
- continue;
- }
+ Vector<String> values;
+ bool isList = DictionaryHelper::get(keyframeDictionary, property, values);
+ if (isList)
alancutter (OOO until 2018) 2016/02/24 08:50:02 No need for single use bool variable.
suzyh_UTC10 (ex-contributor) 2016/02/25 02:42:36 Done. I used this here to be consistent with the c
alancutter (OOO until 2018) 2016/02/25 06:52:27 True, the name does add to code clarity. Feel free
+ exceptionState.throwDOMException(InvalidModificationError, "Lists of values not permitted in array-form list of keyframes");
alancutter (OOO until 2018) 2016/02/24 08:50:02 Is there a test for this exception? Shouldn't we r
suzyh_UTC10 (ex-contributor) 2016/02/25 02:42:36 Test: Done. Return nullptr: Whoops, yes. Fixed.
+
+ String value;
+ DictionaryHelper::get(keyframeDictionary, property, value);
alancutter (OOO until 2018) 2016/02/24 08:50:02 Can this return false if the user provides their o
suzyh_UTC10 (ex-contributor) 2016/02/25 02:42:35 Hm, I have no idea. The existing code used Diction
- const QualifiedName* svgAttribute = AnimationInputHelpers::keyframeAttributeToSVGAttribute(property, *element);
- if (svgAttribute)
- keyframe->setSVGAttributeValue(*svgAttribute, value);
+ encounteredCompositableProperty |= setKeyframeValue(element, keyframe.get(), property, value);
}
+ keyframes.append(keyframe);
}
- // TODO(alancutter): Remove this once composited animations no longer depend on AnimatableValues.
- if (encounteredCompositableProperty && element->inActiveDocument())
- element->document().updateLayoutTreeForNodeIfNeeded(element);
+ updateElementStyleIfNeeded(element, encounteredCompositableProperty);
- StringKeyframeEffectModel* keyframeEffectModel = StringKeyframeEffectModel::create(keyframes);
- if (!RuntimeEnabledFeatures::cssAdditiveAnimationsEnabled()) {
- for (const auto& keyframeGroup : keyframeEffectModel->getPropertySpecificKeyframeGroups()) {
- PropertyHandle property = keyframeGroup.key;
- if (!property.isCSSProperty())
- continue;
+ return createEffectModelFromKeyframes(element, keyframes, exceptionState);
+}
- for (const auto& keyframe : keyframeGroup.value->keyframes()) {
- if (keyframe->isNeutral()) {
- exceptionState.throwDOMException(NotSupportedError, "Partial keyframes are not supported.");
- return nullptr;
- }
- if (keyframe->composite() != EffectModel::CompositeReplace) {
- exceptionState.throwDOMException(NotSupportedError, "Additive animations are not supported.");
- return nullptr;
- }
+EffectModel* EffectInput::convert(Element* element, const Dictionary& keyframeDictionary, ExceptionState& exceptionState)
+{
+ if (!element)
+ return nullptr;
+
+ StringKeyframeVector keyframes;
+ bool encounteredCompositableProperty = false;
+
+ String timingFunctionString;
+ RefPtr<TimingFunction> timingFunction = nullptr;
+ if (DictionaryHelper::get(keyframeDictionary, "easing", timingFunctionString))
+ timingFunction = AnimationInputHelpers::parseTimingFunction(timingFunctionString);
+
+ Vector<String> keyframeProperties;
+ keyframeDictionary.getPropertyNames(keyframeProperties);
+ for (const auto& property : keyframeProperties) {
+ if (property == "offset")
+ exceptionState.throwDOMException(InvalidModificationError, "Keyframe offsets not permitted in object-form list of keyframes");
+ if (property == "composite")
+ exceptionState.throwDOMException(InvalidModificationError, "Keyframe-specific composite operations not permitted in object-form list of keyframes");
+
+ if (property == "easing") {
+ continue;
+ }
+
+ Vector<String> values;
+ bool isList = DictionaryHelper::get(keyframeDictionary, property, values);
+ if (!isList) {
+ String value;
+ DictionaryHelper::get(keyframeDictionary, property, value);
+ values.append(value);
+ }
+
+ size_t numKeyframes = values.size();
+
+ Vector<double> offsets;
+ if (numKeyframes == 1) {
+ offsets.append(1.0);
+ } else {
+ for (size_t i = 0; i < numKeyframes; ++i) {
+ offsets.append(i / (numKeyframes - 1.0));
}
}
- }
- keyframeEffectModel->forceConversionsToAnimatableValues(*element, element->computedStyle());
- return keyframeEffectModel;
-}
+ for (size_t i = 0; i < numKeyframes; ++i) {
+ RefPtr<StringKeyframe> keyframe = StringKeyframe::create();
+ keyframe->setOffset(offsets[i]);
-EffectModel* EffectInput::convert(Element* element, const EffectModelOrDictionarySequenceOrDictionary& effectInput, ExceptionState& exceptionState)
-{
- if (effectInput.isEffectModel())
- return effectInput.getAsEffectModel();
- if (effectInput.isDictionarySequence())
- return convert(element, effectInput.getAsDictionarySequence(), exceptionState);
- if (effectInput.isDictionary()) {
- Vector<Dictionary> keyframes;
- keyframes.append(effectInput.getAsDictionary());
- return convert(element, keyframes, exceptionState);
+ const String& value = values[i];
+
+ if (timingFunction)
+ keyframe->setEasing(timingFunction);
+
+ encounteredCompositableProperty |= setKeyframeValue(element, keyframe.get(), property, value);
+ keyframes.append(keyframe);
+ }
}
- return nullptr;
+
+ std::sort(keyframes.begin(), keyframes.end(), compareKeyframes);
+
+ updateElementStyleIfNeeded(element, encounteredCompositableProperty);
+
+ return createEffectModelFromKeyframes(element, keyframes, exceptionState);
}
} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698