Changeset 233729 in webkit
- Timestamp:
- Jul 11, 2018 8:54:00 AM (6 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/imported/w3c/ChangeLog
r233720 r233729 1 2018-07-10 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Make WPT test at interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html pass reliably 4 https://bugs.webkit.org/show_bug.cgi?id=186501 5 <rdar://problem/41000224> 6 7 Reviewed by Dean Jackson. 8 9 Mark 2 new WPT progressions. 10 11 * web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt: 12 1 13 2018-07-10 Youenn Fablet <youenn@apple.com> 2 14 -
trunk/LayoutTests/imported/w3c/web-platform-tests/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-001-expected.txt
r233632 r233729 43 43 PASS Keyframes are read from a custom iterator with multiple properties specified 44 44 PASS Keyframes are read from a custom iterator with where an offset is specified 45 FAIL Reading from a custom iterator that returns a non-object keyframe should throw assert_throws: function "() => { 46 new KeyframeEffect(null, createIterable([ 47 { done: false, value: { left: '100px' } }, 48 { done: false, value: 1234 }, 49 { done: false, value: { left: '200px' } }, 50 { done: true }, 51 ])); 52 }" did not throw 45 PASS Reading from a custom iterator that returns a non-object keyframe should throw 53 46 PASS A list of values returned from a custom iterator should be ignored 54 47 PASS Only enumerable properties on keyframes are read … … 56 49 PASS Only enumerable properties on property-indexed keyframes are read 57 50 PASS Only properties defined directly on property-indexed keyframes are read 58 FAIL Properties are read in ascending order by Unicode codepoint assert_array_equals: property access order property 0, expected "composite" but got "marginLeft" 51 PASS Properties are read in ascending order by Unicode codepoint 59 52 -
trunk/Source/WebCore/ChangeLog
r233728 r233729 1 2018-07-10 Antoine Quint <graouts@apple.com> 2 3 [Web Animations] Make WPT test at interfaces/KeyframeEffect/processing-a-keyframes-argument-001.html pass reliably 4 https://bugs.webkit.org/show_bug.cgi?id=186501 5 <rdar://problem/41000224> 6 7 Reviewed by Dean Jackson. 8 9 There were two remaining assertions that we were failing in this WPT test file, both related to processing iterable keyframes. 10 The first one was failing because didn't correctly propagate the TypeError exception in the forEachInIterable() callback. The 11 second one was failing because we didn't use the "process a keyframe-like object" procedure when processing iterable keyframes 12 and, as such, we didn't correctly sort property alphabetically before reading their values. 13 14 To fix this second issue, we make processIterableKeyframes() use processKeyframeLikeObject(). To do so, we update processKeyframeLikeObject() 15 to accept a new boolean flag to match the "allow lists" flag from the specification. We also ensure we sort the properties *before* 16 reading from them which we didn't use to do previously. 17 18 * animation/KeyframeEffectReadOnly.cpp: 19 (WebCore::processKeyframeLikeObject): 20 (WebCore::processIterableKeyframes): 21 (WebCore::processPropertyIndexedKeyframes): 22 * animation/KeyframeEffectReadOnly.h: 23 * animation/KeyframeEffectReadOnly.idl: 24 1 25 2018-07-11 Zalan Bujtas <zalan@apple.com> 2 26 -
trunk/Source/WebCore/animation/KeyframeEffectReadOnly.cpp
r233676 r233729 52 52 #include "TranslateTransformOperation.h" 53 53 #include "WillChangeData.h" 54 #include <JavaScriptCore/Exception.h> 54 55 #include <wtf/UUID.h> 55 56 … … 155 156 } 156 157 157 static inline ExceptionOr<void> processIterableKeyframes(ExecState& state, Strong<JSObject>&& keyframesInput, JSValue method, Vector<KeyframeEffectReadOnly::ParsedKeyframe>& parsedKeyframes) 158 { 158 static inline ExceptionOr<KeyframeEffectReadOnly::KeyframeLikeObject> processKeyframeLikeObject(ExecState& state, Strong<JSObject>&& keyframesInput, bool allowLists) 159 { 160 // https://drafts.csswg.org/web-animations-1/#process-a-keyframe-like-object 161 159 162 VM& vm = state.vm(); 160 163 auto scope = DECLARE_THROW_SCOPE(vm); 161 164 162 // 1. Let iter be GetIterator(object, method).163 forEachInIterable(state, keyframesInput.get(), method, [&parsedKeyframes](VM& vm, ExecState& state, JSValue nextValue) -> ExceptionOr<void> {164 if (!nextValue || !nextValue.isObject())165 return Exception { TypeError };166 167 auto scope = DECLARE_THROW_SCOPE(vm);168 169 JSObject* keyframe = nextValue.toObject(&state);170 PropertyNameArray ownPropertyNames(&vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);171 JSObject::getOwnPropertyNames(keyframe, &state, ownPropertyNames, EnumerationMode());172 size_t numberOfProperties = ownPropertyNames.size();173 174 KeyframeEffectReadOnly::ParsedKeyframe keyframeOutput;175 176 String easing("linear");177 std::optional<double> offset;178 std::optional<CompositeOperation> composite;179 180 for (size_t j = 0; j < numberOfProperties; ++j) {181 auto ownPropertyName = ownPropertyNames[j];182 if (ownPropertyName == "easing")183 easing = convert<IDLDOMString>(state, keyframe->get(&state, ownPropertyName));184 else if (ownPropertyName == "offset")185 offset = convert<IDLNullable<IDLDouble>>(state, keyframe->get(&state, ownPropertyName));186 else if (ownPropertyName == "composite")187 composite = convert<IDLNullable<IDLEnumeration<CompositeOperation>>>(state, keyframe->get(&state, ownPropertyName));188 else {189 auto cssPropertyId = IDLAttributeNameToAnimationPropertyName(ownPropertyName.string());190 if (CSSPropertyAnimation::isPropertyAnimatable(cssPropertyId)) {191 auto stringValue = convert<IDLDOMString>(state, keyframe->get(&state, ownPropertyName));192 if (keyframeOutput.style->setProperty(cssPropertyId, stringValue))193 keyframeOutput.unparsedStyle.set(cssPropertyId, stringValue);194 }195 }196 RETURN_IF_EXCEPTION(scope, Exception { TypeError });197 }198 199 keyframeOutput.easing = easing;200 keyframeOutput.offset = offset;201 keyframeOutput.composite = composite;202 203 parsedKeyframes.append(WTFMove(keyframeOutput));204 205 return { };206 });207 RETURN_IF_EXCEPTION(scope, Exception { TypeError });208 209 return { };210 }211 212 static inline ExceptionOr<KeyframeEffectReadOnly::KeyframeLikeObject> processKeyframeLikeObject(ExecState& state, Strong<JSObject>&& keyframesInput)213 {214 // https://drafts.csswg.org/web-animations-1/#process-a-keyframe-like-object215 216 VM& vm = state.vm();217 auto scope = DECLARE_THROW_SCOPE(vm);218 219 165 // 1. Run the procedure to convert an ECMAScript value to a dictionary type [WEBIDL] with keyframe input as the ECMAScript value as follows: 220 166 // 167 // If allow lists is true, use the following dictionary type: 168 // 221 169 // dictionary BasePropertyIndexedKeyframe { 222 // (double? or sequence<double?>) offset = [];223 // (DOMString or sequence<DOMString>) easing = [];170 // (double? or sequence<double?>) offset = []; 171 // (DOMString or sequence<DOMString>) easing = []; 224 172 // (CompositeOperation? or sequence<CompositeOperation?>) composite = []; 225 173 // }; 226 174 // 175 // Otherwise, use the following dictionary type: 176 // 177 // dictionary BaseKeyframe { 178 // double? offset = null; 179 // DOMString easing = "linear"; 180 // CompositeOperation? composite = null; 181 // }; 182 // 227 183 // Store the result of this procedure as keyframe output. 228 auto baseProperties = convert<IDLDictionary<KeyframeEffectReadOnly::BasePropertyIndexedKeyframe>>(state, keyframesInput.get()); 184 KeyframeEffect::BasePropertyIndexedKeyframe baseProperties; 185 if (allowLists) 186 baseProperties = convert<IDLDictionary<KeyframeEffectReadOnly::BasePropertyIndexedKeyframe>>(state, keyframesInput.get()); 187 else { 188 auto baseKeyframe = convert<IDLDictionary<KeyframeEffectReadOnly::BaseKeyframe>>(state, keyframesInput.get()); 189 if (baseKeyframe.offset) 190 baseProperties.offset = baseKeyframe.offset.value(); 191 else 192 baseProperties.offset = nullptr; 193 baseProperties.easing = baseKeyframe.easing; 194 if (baseKeyframe.composite) 195 baseProperties.composite = baseKeyframe.composite.value(); 196 else 197 baseProperties.composite = nullptr; 198 } 229 199 RETURN_IF_EXCEPTION(scope, Exception { TypeError }); 230 200 … … 245 215 // 4. Make up a new list animation properties that consists of all of the properties that are in both input properties and animatable 246 216 // properties, or which are in input properties and conform to the <custom-property-name> production. 247 248 // 5. Sort animation properties in ascending order by the Unicode codepoints that define each property name. 249 // We only actually perform this after step 6. 250 251 // 6. For each property name in animation properties, 217 Vector<JSC::Identifier> animationProperties; 252 218 size_t numberOfProperties = inputProperties.size(); 253 219 for (size_t i = 0; i < numberOfProperties; ++i) { 254 auto cssPropertyID = IDLAttributeNameToAnimationPropertyName(inputProperties[i].string()); 255 if (!CSSPropertyAnimation::isPropertyAnimatable(cssPropertyID)) 256 continue; 257 220 if (CSSPropertyAnimation::isPropertyAnimatable(IDLAttributeNameToAnimationPropertyName(inputProperties[i].string()))) 221 animationProperties.append(inputProperties[i]); 222 } 223 224 // 5. Sort animation properties in ascending order by the Unicode codepoints that define each property name. 225 std::sort(animationProperties.begin(), animationProperties.end(), [](auto& lhs, auto& rhs) { 226 return lhs.string().utf8() < rhs.string().utf8(); 227 }); 228 229 // 6. For each property name in animation properties, 230 size_t numberOfAnimationProperties = animationProperties.size(); 231 for (size_t i = 0; i < numberOfAnimationProperties; ++i) { 258 232 // 1. Let raw value be the result of calling the [[Get]] internal method on keyframe input, with property name as the property 259 233 // key and keyframe input as the receiver. 260 auto rawValue = keyframesInput->get(&state, inputProperties[i]);234 auto rawValue = keyframesInput->get(&state, animationProperties[i]); 261 235 262 236 // 2. Check the completion record of raw value. … … 265 239 // 3. Convert raw value to a DOMString or sequence of DOMStrings property values as follows: 266 240 Vector<String> propertyValues; 267 // Let property values be the result of converting raw value to IDL type (DOMString or sequence<DOMString>) 268 // using the procedures defined for converting an ECMAScript value to an IDL value [WEBIDL]. 269 // If property values is a single DOMString, replace property values with a sequence of DOMStrings with the original value of property 270 // Values as the only element. 271 if (rawValue.isString()) 272 propertyValues = { rawValue.toWTFString(&state) }; 273 else if (rawValue.isObject()) 274 propertyValues = convert<IDLSequence<IDLDOMString>>(state, rawValue); 241 if (allowLists) { 242 // If allow lists is true, 243 // Let property values be the result of converting raw value to IDL type (DOMString or sequence<DOMString>) 244 // using the procedures defined for converting an ECMAScript value to an IDL value [WEBIDL]. 245 // If property values is a single DOMString, replace property values with a sequence of DOMStrings with the original value of property 246 // Values as the only element. 247 if (rawValue.isString()) 248 propertyValues = { rawValue.toWTFString(&state) }; 249 else if (rawValue.isObject()) 250 propertyValues = convert<IDLSequence<IDLDOMString>>(state, rawValue); 251 } else { 252 // Otherwise, 253 // Let property values be the result of converting raw value to a DOMString using the procedure for converting an ECMAScript value to a DOMString. 254 propertyValues = { convert<IDLDOMString>(state, rawValue) }; 255 } 275 256 RETURN_IF_EXCEPTION(scope, Exception { TypeError }); 276 257 277 258 // 4. Calculate the normalized property name as the result of applying the IDL attribute name to animation property name algorithm to property name. 259 auto cssPropertyID = IDLAttributeNameToAnimationPropertyName(animationProperties[i].string()); 260 278 261 // 5. Add a property to to keyframe output with normalized property name as the property name, and property values as the property value. 279 262 keyframeOuput.propertiesAndValues.append({ cssPropertyID, propertyValues }); 280 263 } 281 264 282 // Now we can perform step 5.283 std::sort(keyframeOuput.propertiesAndValues.begin(), keyframeOuput.propertiesAndValues.end(), [](auto& lhs, auto& rhs) {284 return getPropertyNameString(lhs.property).utf8() < getPropertyNameString(rhs.property).utf8();285 });286 287 265 // 7. Return keyframe output. 288 266 return { WTFMove(keyframeOuput) }; 289 267 } 290 268 269 static inline ExceptionOr<void> processIterableKeyframes(ExecState& state, Strong<JSObject>&& keyframesInput, JSValue method, Vector<KeyframeEffectReadOnly::ParsedKeyframe>& parsedKeyframes) 270 { 271 VM& vm = state.vm(); 272 auto scope = DECLARE_THROW_SCOPE(vm); 273 274 // 1. Let iter be GetIterator(object, method). 275 forEachInIterable(state, keyframesInput.get(), method, [&parsedKeyframes](VM& vm, ExecState& state, JSValue nextValue) -> ExceptionOr<void> { 276 // Steps 2 through 6 are already implemented by forEachInIterable(). 277 auto scope = DECLARE_THROW_SCOPE(vm); 278 if (!nextValue || !nextValue.isObject()) { 279 throwException(&state, scope, JSC::Exception::create(vm, createTypeError(&state))); 280 return { }; 281 } 282 283 // 7. Append to processed keyframes the result of running the procedure to process a keyframe-like object passing nextItem 284 // as the keyframe input and with the allow lists flag set to false. 285 auto processKeyframeLikeObjectResult = processKeyframeLikeObject(state, Strong<JSObject>(vm, nextValue.toObject(&state)), false); 286 if (processKeyframeLikeObjectResult.hasException()) 287 return processKeyframeLikeObjectResult.releaseException(); 288 auto keyframeLikeObject = processKeyframeLikeObjectResult.returnValue(); 289 290 KeyframeEffectReadOnly::ParsedKeyframe keyframeOutput; 291 292 // When calling processKeyframeLikeObject() with the "allow lists" flag set to false, the only offset 293 // alternatives we should expect are double and nullptr. 294 if (WTF::holds_alternative<double>(keyframeLikeObject.baseProperties.offset)) 295 keyframeOutput.offset = WTF::get<double>(keyframeLikeObject.baseProperties.offset); 296 else 297 ASSERT(WTF::holds_alternative<std::nullptr_t>(keyframeLikeObject.baseProperties.offset)); 298 299 // When calling processKeyframeLikeObject() with the "allow lists" flag set to false, the only easing 300 // alternative we should expect is String. 301 ASSERT(WTF::holds_alternative<String>(keyframeLikeObject.baseProperties.easing)); 302 keyframeOutput.easing = WTF::get<String>(keyframeLikeObject.baseProperties.easing); 303 304 // When calling processKeyframeLikeObject() with the "allow lists" flag set to false, the only composite 305 // alternatives we should expect are CompositeOperation and nullptr. 306 if (WTF::holds_alternative<CompositeOperation>(keyframeLikeObject.baseProperties.composite)) 307 keyframeOutput.composite = WTF::get<CompositeOperation>(keyframeLikeObject.baseProperties.composite); 308 else 309 ASSERT(WTF::holds_alternative<std::nullptr_t>(keyframeLikeObject.baseProperties.composite)); 310 311 for (auto& propertyAndValue : keyframeLikeObject.propertiesAndValues) { 312 auto cssPropertyId = propertyAndValue.property; 313 // When calling processKeyframeLikeObject() with the "allow lists" flag set to false, 314 // there should only ever be a single value for a given property. 315 ASSERT(propertyAndValue.values.size() == 1); 316 auto stringValue = propertyAndValue.values[0]; 317 if (keyframeOutput.style->setProperty(cssPropertyId, stringValue)) 318 keyframeOutput.unparsedStyle.set(cssPropertyId, stringValue); 319 } 320 321 parsedKeyframes.append(WTFMove(keyframeOutput)); 322 323 return { }; 324 }); 325 326 return { }; 327 } 328 291 329 static inline ExceptionOr<void> processPropertyIndexedKeyframes(ExecState& state, Strong<JSObject>&& keyframesInput, Vector<KeyframeEffectReadOnly::ParsedKeyframe>& parsedKeyframes, Vector<String>& unusedEasings) 292 330 { 293 331 // 1. Let property-indexed keyframe be the result of running the procedure to process a keyframe-like object passing object as the keyframe input. 294 auto processKeyframeLikeObjectResult = processKeyframeLikeObject(state, WTFMove(keyframesInput) );332 auto processKeyframeLikeObjectResult = processKeyframeLikeObject(state, WTFMove(keyframesInput), true); 295 333 if (processKeyframeLikeObjectResult.hasException()) 296 334 return processKeyframeLikeObjectResult.releaseException(); -
trunk/Source/WebCore/animation/KeyframeEffectReadOnly.h
r232946 r233729 54 54 Variant<Vector<String>, String> easing = Vector<String>(); 55 55 Variant<std::nullptr_t, Vector<std::optional<CompositeOperation>>, CompositeOperation> composite = Vector<std::optional<CompositeOperation>>(); 56 }; 57 58 struct BaseKeyframe { 59 std::optional<double> offset; 60 String easing { "linear" }; 61 std::optional<CompositeOperation> composite; 56 62 }; 57 63 -
trunk/Source/WebCore/animation/KeyframeEffectReadOnly.idl
r228694 r233729 45 45 }; 46 46 47 dictionary BaseKeyframe { 48 double? offset = null; 49 DOMString easing = "linear"; 50 CompositeOperation? composite = null; 51 }; 52 47 53 [ 48 54 JSGenerateToJSObject
Note: See TracChangeset
for help on using the changeset viewer.