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

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: Fix mistake in rebase 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
« no previous file with comments | « third_party/WebKit/Source/core/animation/EffectInput.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 b05cc6cccff3c22cb1347c02b9f584be7eb6289a..3b729571add8c96920f4f6b72062433b85bb08c9 100644
--- a/third_party/WebKit/Source/core/animation/EffectInput.cpp
+++ b/third_party/WebKit/Source/core/animation/EffectInput.cpp
@@ -47,12 +47,81 @@
namespace blink {
-EffectModel* EffectInput::convert(Element* element, const Vector<Dictionary>& keyframeDictionaryVector, ExceptionState& exceptionState)
+namespace {
+
+bool compareKeyframes(const RefPtr<StringKeyframe>& a, const RefPtr<StringKeyframe>& b)
+{
+ return a->offset() < b->offset();
+}
+
+} // namespace
+
+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, true);
+ if (effectInput.isDictionary()) {
+ return convert(element, effectInput.getAsDictionary(), exceptionState);
+ }
+ return nullptr;
+}
+
+bool EffectInput::setKeyframeValue(Element* element, StringKeyframe& keyframe, const String& property, const String& value)
+{
+ 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;
+}
+
+EffectModel* EffectInput::createEffectModelFromKeyframes(Element* element, const StringKeyframeVector& keyframes, bool encounteredCompositableProperty, ExceptionState& exceptionState)
+{
+ // TODO(alancutter): Remove this once composited animations no longer depend on AnimatableValues.
+ if (encounteredCompositableProperty && element->inActiveDocument())
+ element->document().updateLayoutTreeForNode(element);
+
+ 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, bool keyframesSpecifiedAsList)
{
if (!element)
return nullptr;
- StyleSheetContents* styleSheetContents = element->document().elementSheet().contents();
StringKeyframeVector keyframes;
double lastOffset = 0;
bool encounteredCompositableProperty = false;
@@ -70,6 +139,7 @@ EffectModel* EffectInput::convert(Element* element, const Vector<Dictionary>& ke
// Keyframes with offsets outside the range [0.0, 1.0] are an error.
if (std::isnan(offset)) {
exceptionState.throwDOMException(InvalidModificationError, "Non numeric offset provided");
+ return nullptr;
}
if (offset < 0 || offset > 1) {
@@ -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,100 @@ 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;
+ if (DictionaryHelper::get(keyframeDictionary, property, values)) {
+ String exceptionMessage = keyframesSpecifiedAsList ?
+ "Lists of values not permitted in array-form list of keyframes" :
+ "Offsets and keyframe-specific composite operations not permitted in object-form list of keyframes";
+ exceptionState.throwDOMException(InvalidModificationError, exceptionMessage);
alancutter (OOO until 2018) 2016/02/25 06:52:27 This is definitely not a modification error, I'd g
shans 2016/02/25 22:30:28 Spec says TypeError.
suzyh_UTC10 (ex-contributor) 2016/02/26 04:35:31 As discussed offline, I've made all these InvalidM
+ return nullptr;
}
- const QualifiedName* svgAttribute = AnimationInputHelpers::keyframeAttributeToSVGAttribute(property, *element);
- if (svgAttribute)
- keyframe->setSVGAttributeValue(*svgAttribute, value);
+ String value;
+ DictionaryHelper::get(keyframeDictionary, property, 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().updateLayoutTreeForNode(element);
+ return createEffectModelFromKeyframes(element, keyframes, encounteredCompositableProperty, exceptionState);
+}
- StringKeyframeEffectModel* keyframeEffectModel = StringKeyframeEffectModel::create(keyframes);
- if (!RuntimeEnabledFeatures::cssAdditiveAnimationsEnabled()) {
- for (const auto& keyframeGroup : keyframeEffectModel->getPropertySpecificKeyframeGroups()) {
- PropertyHandle property = keyframeGroup.key;
- if (!property.isCSSProperty())
- continue;
+EffectModel* EffectInput::convert(Element* element, const Dictionary& keyframeDictionary, ExceptionState& exceptionState)
+{
+ if (!element)
+ return nullptr;
- 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;
- }
+ ScriptValue scriptValue;
+ String compositeString;
+ bool frameHasOffset = DictionaryHelper::get(keyframeDictionary, "offset", scriptValue) && !scriptValue.isNull();
+ bool frameHasComposite = DictionaryHelper::get(keyframeDictionary, "composite", compositeString);
+ if (frameHasOffset || frameHasComposite) {
+ Vector<Dictionary> keyframeDictionaryVector;
+ keyframeDictionaryVector.append(keyframeDictionary);
+ return convert(element, keyframeDictionaryVector, exceptionState, false);
+ }
+
+ 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"
+ || property == "composite"
+ || 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);
+
+ return createEffectModelFromKeyframes(element, keyframes, encounteredCompositableProperty, exceptionState);
}
} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/animation/EffectInput.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698