Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |