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

Side by Side 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 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 29 matching lines...) Expand all
40 #include "core/dom/Document.h" 40 #include "core/dom/Document.h"
41 #include "core/dom/Element.h" 41 #include "core/dom/Element.h"
42 #include "core/dom/ExceptionCode.h" 42 #include "core/dom/ExceptionCode.h"
43 #include "core/dom/NodeComputedStyle.h" 43 #include "core/dom/NodeComputedStyle.h"
44 #include "wtf/ASCIICType.h" 44 #include "wtf/ASCIICType.h"
45 #include "wtf/HashSet.h" 45 #include "wtf/HashSet.h"
46 #include "wtf/NonCopyingSort.h" 46 #include "wtf/NonCopyingSort.h"
47 47
48 namespace blink { 48 namespace blink {
49 49
50 namespace {
51 bool compareKeyframes(const RefPtr<StringKeyframe>& a, const RefPtr<StringKeyfra me>& b)
52 {
53 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.
54 }
55 } // 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.
56
57 EffectModel* EffectInput::convert(Element* element, const EffectModelOrDictionar ySequenceOrDictionary& effectInput, ExceptionState& exceptionState)
58 {
59 if (effectInput.isEffectModel())
60 return effectInput.getAsEffectModel();
61 if (effectInput.isDictionarySequence())
62 return convert(element, effectInput.getAsDictionarySequence(), exception State);
63 if (effectInput.isDictionary()) {
64 return convert(element, effectInput.getAsDictionary(), exceptionState);
65 }
66 return nullptr;
67 }
68
69 bool EffectInput::setKeyframeValue(Element* element, StringKeyframe* keyframe, c onst 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.
70 {
71 StyleSheetContents* styleSheetContents = element->document().elementSheet(). contents();
72 CSSPropertyID cssProperty = AnimationInputHelpers::keyframeAttributeToCSSPro perty(property, element->document());
73 if (cssProperty != CSSPropertyInvalid) {
74 keyframe->setCSSPropertyValue(cssProperty, value, element, styleSheetCon tents);
75 return CompositorAnimations::isCompositableProperty(cssProperty);
76 }
77 cssProperty = AnimationInputHelpers::keyframeAttributeToPresentationAttribut e(property, *element);
78 if (cssProperty != CSSPropertyInvalid) {
79 keyframe->setPresentationAttributeValue(cssProperty, value, element, sty leSheetContents);
80 return false;
81 }
82 const QualifiedName* svgAttribute = AnimationInputHelpers::keyframeAttribute ToSVGAttribute(property, *element);
83 if (svgAttribute)
84 keyframe->setSVGAttributeValue(*svgAttribute, value);
85 return false;
86 }
87
88 // TODO(alancutter): Remove this once composited animations no longer depend on AnimatableValues.
89 void EffectInput::updateElementStyleIfNeeded(Element* element, bool encounteredC ompositableProperty)
90 {
91 if (encounteredCompositableProperty && element->inActiveDocument())
92 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.
93 }
94
95 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.
96 {
97 StringKeyframeEffectModel* keyframeEffectModel = StringKeyframeEffectModel:: create(keyframes);
98 if (!RuntimeEnabledFeatures::cssAdditiveAnimationsEnabled()) {
99 for (const auto& keyframeGroup : keyframeEffectModel->getPropertySpecifi cKeyframeGroups()) {
100 PropertyHandle property = keyframeGroup.key;
101 if (!property.isCSSProperty())
102 continue;
103
104 for (const auto& keyframe : keyframeGroup.value->keyframes()) {
105 if (keyframe->isNeutral()) {
106 exceptionState.throwDOMException(NotSupportedError, "Partial keyframes are not supported.");
107 return nullptr;
108 }
109 if (keyframe->composite() != EffectModel::CompositeReplace) {
110 exceptionState.throwDOMException(NotSupportedError, "Additiv e animations are not supported.");
111 return nullptr;
112 }
113 }
114 }
115 }
116 keyframeEffectModel->forceConversionsToAnimatableValues(*element, element->c omputedStyle());
117
118 return keyframeEffectModel;
119 }
120
50 EffectModel* EffectInput::convert(Element* element, const Vector<Dictionary>& ke yframeDictionaryVector, ExceptionState& exceptionState) 121 EffectModel* EffectInput::convert(Element* element, const Vector<Dictionary>& ke yframeDictionaryVector, ExceptionState& exceptionState)
51 { 122 {
52 if (!element) 123 if (!element)
53 return nullptr; 124 return nullptr;
54 125
55 StyleSheetContents* styleSheetContents = element->document().elementSheet(). contents();
56 StringKeyframeVector keyframes; 126 StringKeyframeVector keyframes;
57 double lastOffset = 0; 127 double lastOffset = 0;
58 bool encounteredCompositableProperty = false; 128 bool encounteredCompositableProperty = false;
59 129
60 for (const auto& keyframeDictionary : keyframeDictionaryVector) { 130 for (const auto& keyframeDictionary : keyframeDictionaryVector) {
61 RefPtr<StringKeyframe> keyframe = StringKeyframe::create(); 131 RefPtr<StringKeyframe> keyframe = StringKeyframe::create();
62 132
63 ScriptValue scriptValue; 133 ScriptValue scriptValue;
64 bool frameHasOffset = DictionaryHelper::get(keyframeDictionary, "offset" , scriptValue) && !scriptValue.isNull(); 134 bool frameHasOffset = DictionaryHelper::get(keyframeDictionary, "offset" , scriptValue) && !scriptValue.isNull();
65 135
(...skipping 13 matching lines...) Expand all
79 149
80 if (offset < lastOffset) { 150 if (offset < lastOffset) {
81 exceptionState.throwDOMException(InvalidModificationError, "Keyf rames with specified offsets are not sorted"); 151 exceptionState.throwDOMException(InvalidModificationError, "Keyf rames with specified offsets are not sorted");
82 return nullptr; 152 return nullptr;
83 } 153 }
84 154
85 lastOffset = offset; 155 lastOffset = offset;
86 156
87 keyframe->setOffset(offset); 157 keyframe->setOffset(offset);
88 } 158 }
89 keyframes.append(keyframe);
90 159
91 String compositeString; 160 String compositeString;
92 DictionaryHelper::get(keyframeDictionary, "composite", compositeString); 161 DictionaryHelper::get(keyframeDictionary, "composite", compositeString);
93 if (compositeString == "add") 162 if (compositeString == "add")
94 keyframe->setComposite(EffectModel::CompositeAdd); 163 keyframe->setComposite(EffectModel::CompositeAdd);
95 // TODO(alancutter): Support "accumulate" keyframe composition. 164 // TODO(alancutter): Support "accumulate" keyframe composition.
96 165
97 String timingFunctionString; 166 String timingFunctionString;
98 if (DictionaryHelper::get(keyframeDictionary, "easing", timingFunctionSt ring)) { 167 if (DictionaryHelper::get(keyframeDictionary, "easing", timingFunctionSt ring)) {
99 if (RefPtr<TimingFunction> timingFunction = AnimationInputHelpers::p arseTimingFunction(timingFunctionString)) 168 if (RefPtr<TimingFunction> timingFunction = AnimationInputHelpers::p arseTimingFunction(timingFunctionString))
100 keyframe->setEasing(timingFunction); 169 keyframe->setEasing(timingFunction);
101 } 170 }
102 171
103 Vector<String> keyframeProperties; 172 Vector<String> keyframeProperties;
104 keyframeDictionary.getPropertyNames(keyframeProperties); 173 keyframeDictionary.getPropertyNames(keyframeProperties);
105 for (const auto& property : keyframeProperties) { 174 for (const auto& property : keyframeProperties) {
106 String value;
107 DictionaryHelper::get(keyframeDictionary, property, value);
108
109 CSSPropertyID cssProperty = AnimationInputHelpers::keyframeAttribute ToCSSProperty(property, element->document());
110 if (cssProperty != CSSPropertyInvalid) {
111 if (!encounteredCompositableProperty && CompositorAnimations::is CompositableProperty(cssProperty))
112 encounteredCompositableProperty = true;
113
114 keyframe->setCSSPropertyValue(cssProperty, value, element, style SheetContents);
115 continue;
116 }
117
118 if (property == "offset" 175 if (property == "offset"
119 || property == "composite" 176 || property == "composite"
120 || property == "easing") { 177 || property == "easing") {
121 continue; 178 continue;
122 } 179 }
123 180
124 cssProperty = AnimationInputHelpers::keyframeAttributeToPresentation Attribute(property, *element); 181 Vector<String> values;
125 if (cssProperty != CSSPropertyInvalid) { 182 bool isList = DictionaryHelper::get(keyframeDictionary, property, va lues);
126 keyframe->setPresentationAttributeValue(cssProperty, value, elem ent, styleSheetContents); 183 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
127 continue; 184 exceptionState.throwDOMException(InvalidModificationError, "List s 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.
185
186 String value;
187 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
188
189 encounteredCompositableProperty |= setKeyframeValue(element, keyfram e.get(), property, value);
190 }
191 keyframes.append(keyframe);
192 }
193
194 updateElementStyleIfNeeded(element, encounteredCompositableProperty);
195
196 return createEffectModelFromKeyframes(element, keyframes, exceptionState);
197 }
198
199 EffectModel* EffectInput::convert(Element* element, const Dictionary& keyframeDi ctionary, ExceptionState& exceptionState)
200 {
201 if (!element)
202 return nullptr;
203
204 StringKeyframeVector keyframes;
205 bool encounteredCompositableProperty = false;
206
207 String timingFunctionString;
208 RefPtr<TimingFunction> timingFunction = nullptr;
209 if (DictionaryHelper::get(keyframeDictionary, "easing", timingFunctionString ))
210 timingFunction = AnimationInputHelpers::parseTimingFunction(timingFuncti onString);
211
212 Vector<String> keyframeProperties;
213 keyframeDictionary.getPropertyNames(keyframeProperties);
214 for (const auto& property : keyframeProperties) {
215 if (property == "offset")
216 exceptionState.throwDOMException(InvalidModificationError, "Keyframe offsets not permitted in object-form list of keyframes");
217 if (property == "composite")
218 exceptionState.throwDOMException(InvalidModificationError, "Keyframe -specific composite operations not permitted in object-form list of keyframes");
219
220 if (property == "easing") {
221 continue;
222 }
223
224 Vector<String> values;
225 bool isList = DictionaryHelper::get(keyframeDictionary, property, values );
226 if (!isList) {
227 String value;
228 DictionaryHelper::get(keyframeDictionary, property, value);
229 values.append(value);
230 }
231
232 size_t numKeyframes = values.size();
233
234 Vector<double> offsets;
235 if (numKeyframes == 1) {
236 offsets.append(1.0);
237 } else {
238 for (size_t i = 0; i < numKeyframes; ++i) {
239 offsets.append(i / (numKeyframes - 1.0));
128 } 240 }
241 }
129 242
130 const QualifiedName* svgAttribute = AnimationInputHelpers::keyframeA ttributeToSVGAttribute(property, *element); 243 for (size_t i = 0; i < numKeyframes; ++i) {
131 if (svgAttribute) 244 RefPtr<StringKeyframe> keyframe = StringKeyframe::create();
132 keyframe->setSVGAttributeValue(*svgAttribute, value); 245 keyframe->setOffset(offsets[i]);
246
247 const String& value = values[i];
248
249 if (timingFunction)
250 keyframe->setEasing(timingFunction);
251
252 encounteredCompositableProperty |= setKeyframeValue(element, keyfram e.get(), property, value);
253 keyframes.append(keyframe);
133 } 254 }
134 } 255 }
135 256
136 // TODO(alancutter): Remove this once composited animations no longer depend on AnimatableValues. 257 std::sort(keyframes.begin(), keyframes.end(), compareKeyframes);
137 if (encounteredCompositableProperty && element->inActiveDocument())
138 element->document().updateLayoutTreeForNodeIfNeeded(element);
139 258
140 StringKeyframeEffectModel* keyframeEffectModel = StringKeyframeEffectModel:: create(keyframes); 259 updateElementStyleIfNeeded(element, encounteredCompositableProperty);
141 if (!RuntimeEnabledFeatures::cssAdditiveAnimationsEnabled()) {
142 for (const auto& keyframeGroup : keyframeEffectModel->getPropertySpecifi cKeyframeGroups()) {
143 PropertyHandle property = keyframeGroup.key;
144 if (!property.isCSSProperty())
145 continue;
146 260
147 for (const auto& keyframe : keyframeGroup.value->keyframes()) { 261 return createEffectModelFromKeyframes(element, keyframes, exceptionState);
148 if (keyframe->isNeutral()) {
149 exceptionState.throwDOMException(NotSupportedError, "Partial keyframes are not supported.");
150 return nullptr;
151 }
152 if (keyframe->composite() != EffectModel::CompositeReplace) {
153 exceptionState.throwDOMException(NotSupportedError, "Additiv e animations are not supported.");
154 return nullptr;
155 }
156 }
157 }
158 }
159 keyframeEffectModel->forceConversionsToAnimatableValues(*element, element->c omputedStyle());
160
161 return keyframeEffectModel;
162 }
163
164 EffectModel* EffectInput::convert(Element* element, const EffectModelOrDictionar ySequenceOrDictionary& effectInput, ExceptionState& exceptionState)
165 {
166 if (effectInput.isEffectModel())
167 return effectInput.getAsEffectModel();
168 if (effectInput.isDictionarySequence())
169 return convert(element, effectInput.getAsDictionarySequence(), exception State);
170 if (effectInput.isDictionary()) {
171 Vector<Dictionary> keyframes;
172 keyframes.append(effectInput.getAsDictionary());
173 return convert(element, keyframes, exceptionState);
174 }
175 return nullptr;
176 } 262 }
177 263
178 } // namespace blink 264 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698