mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Update web-platform-tests to revision e87f38097902e16348d4e17f4fe3bc2d0112bff1
This commit is contained in:
parent
2f8fa32e91
commit
db5631a086
381 changed files with 11610 additions and 4232 deletions
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect and KeyframeEffectReadOnly constructor</title>
|
||||
<title>KeyframeEffect constructor</title>
|
||||
<link rel="help"
|
||||
href="https://drafts.csswg.org/web-animations/#dom-keyframeeffect-keyframeeffect">
|
||||
<link rel="help"
|
||||
|
@ -21,49 +21,48 @@ const target = document.getElementById('target');
|
|||
|
||||
test(t => {
|
||||
for (const frames of gEmptyKeyframeListTests) {
|
||||
assert_equals(new KeyframeEffectReadOnly(target, frames)
|
||||
.getKeyframes().length,
|
||||
assert_equals(new KeyframeEffect(target, frames).getKeyframes().length,
|
||||
0, `number of frames for ${JSON.stringify(frames)}`);
|
||||
}
|
||||
}, 'A KeyframeEffectReadOnly can be constructed with no frames');
|
||||
}, 'A KeyframeEffect can be constructed with no frames');
|
||||
|
||||
test(t => {
|
||||
for (const subtest of gEasingParsingTests) {
|
||||
const easing = subtest[0];
|
||||
const expected = subtest[1];
|
||||
const effect = new KeyframeEffectReadOnly(target, {
|
||||
const effect = new KeyframeEffect(target, {
|
||||
left: ['10px', '20px']
|
||||
}, { easing: easing });
|
||||
assert_equals(effect.timing.easing, expected,
|
||||
assert_equals(effect.getTiming().easing, expected,
|
||||
`resulting easing for '${easing}'`);
|
||||
}
|
||||
}, 'easing values are parsed correctly when passed to the ' +
|
||||
'KeyframeEffectReadOnly constructor in KeyframeEffectOptions');
|
||||
'KeyframeEffect constructor in KeyframeEffectOptions');
|
||||
|
||||
test(t => {
|
||||
for (const invalidEasing of gInvalidEasings) {
|
||||
assert_throws(new TypeError, () => {
|
||||
new KeyframeEffectReadOnly(target, null, { easing: invalidEasing });
|
||||
new KeyframeEffect(target, null, { easing: invalidEasing });
|
||||
}, `TypeError is thrown for easing '${invalidEasing}'`);
|
||||
}
|
||||
}, 'Invalid easing values are correctly rejected when passed to the ' +
|
||||
'KeyframeEffectReadOnly constructor in KeyframeEffectOptions');
|
||||
'KeyframeEffect constructor in KeyframeEffectOptions');
|
||||
|
||||
test(t => {
|
||||
const getKeyframe =
|
||||
composite => ({ left: [ '10px', '20px' ], composite: composite });
|
||||
for (const composite of gGoodKeyframeCompositeValueTests) {
|
||||
const effect = new KeyframeEffectReadOnly(target, getKeyframe(composite));
|
||||
const effect = new KeyframeEffect(target, getKeyframe(composite));
|
||||
assert_equals(effect.getKeyframes()[0].composite, composite,
|
||||
`resulting composite for '${composite}'`);
|
||||
}
|
||||
for (const composite of gBadKeyframeCompositeValueTests) {
|
||||
assert_throws(new TypeError, () => {
|
||||
new KeyframeEffectReadOnly(target, getKeyframe(composite));
|
||||
new KeyframeEffect(target, getKeyframe(composite));
|
||||
});
|
||||
}
|
||||
}, 'composite values are parsed correctly when passed to the ' +
|
||||
'KeyframeEffectReadOnly constructor in property-indexed keyframes');
|
||||
'KeyframeEffect constructor in property-indexed keyframes');
|
||||
|
||||
test(t => {
|
||||
const getKeyframes = composite =>
|
||||
|
@ -72,29 +71,29 @@ test(t => {
|
|||
{ offset: 1, left: '20px' }
|
||||
];
|
||||
for (const composite of gGoodKeyframeCompositeValueTests) {
|
||||
const effect = new KeyframeEffectReadOnly(target, getKeyframes(composite));
|
||||
const effect = new KeyframeEffect(target, getKeyframes(composite));
|
||||
assert_equals(effect.getKeyframes()[0].composite, composite,
|
||||
`resulting composite for '${composite}'`);
|
||||
}
|
||||
for (const composite of gBadKeyframeCompositeValueTests) {
|
||||
assert_throws(new TypeError, () => {
|
||||
new KeyframeEffectReadOnly(target, getKeyframes(composite));
|
||||
new KeyframeEffect(target, getKeyframes(composite));
|
||||
});
|
||||
}
|
||||
}, 'composite values are parsed correctly when passed to the ' +
|
||||
'KeyframeEffectReadOnly constructor in regular keyframes');
|
||||
'KeyframeEffect constructor in regular keyframes');
|
||||
|
||||
test(t => {
|
||||
for (const composite of gGoodOptionsCompositeValueTests) {
|
||||
const effect = new KeyframeEffectReadOnly(target, {
|
||||
const effect = new KeyframeEffect(target, {
|
||||
left: ['10px', '20px']
|
||||
}, { composite: composite });
|
||||
}, { composite });
|
||||
assert_equals(effect.getKeyframes()[0].composite, null,
|
||||
`resulting composite for '${composite}'`);
|
||||
}
|
||||
for (const composite of gBadOptionsCompositeValueTests) {
|
||||
assert_throws(new TypeError, () => {
|
||||
new KeyframeEffectReadOnly(target, {
|
||||
new KeyframeEffect(target, {
|
||||
left: ['10px', '20px']
|
||||
}, { composite: composite });
|
||||
});
|
||||
|
@ -104,32 +103,30 @@ test(t => {
|
|||
|
||||
for (const subtest of gKeyframesTests) {
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
const effect = new KeyframeEffect(target, subtest.input);
|
||||
assert_frame_lists_equal(effect.getKeyframes(), subtest.output);
|
||||
}, `A KeyframeEffectReadOnly can be constructed with ${subtest.desc}`);
|
||||
}, `A KeyframeEffect can be constructed with ${subtest.desc}`);
|
||||
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(target, subtest.input);
|
||||
const secondEffect =
|
||||
new KeyframeEffectReadOnly(target, effect.getKeyframes());
|
||||
const effect = new KeyframeEffect(target, subtest.input);
|
||||
const secondEffect = new KeyframeEffect(target, effect.getKeyframes());
|
||||
assert_frame_lists_equal(secondEffect.getKeyframes(),
|
||||
effect.getKeyframes());
|
||||
}, `A KeyframeEffectReadOnly constructed with ${subtest.desc} roundtrips`);
|
||||
}, `A KeyframeEffect constructed with ${subtest.desc} roundtrips`);
|
||||
}
|
||||
|
||||
for (const subtest of gInvalidKeyframesTests) {
|
||||
test(t => {
|
||||
assert_throws(new TypeError, () => {
|
||||
new KeyframeEffectReadOnly(target, subtest.input);
|
||||
new KeyframeEffect(target, subtest.input);
|
||||
});
|
||||
}, `KeyframeEffectReadOnly constructor throws with ${subtest.desc}`);
|
||||
}, `KeyframeEffect constructor throws with ${subtest.desc}`);
|
||||
}
|
||||
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ['10px', '20px'] });
|
||||
const effect = new KeyframeEffect(target, { left: ['10px', '20px'] });
|
||||
|
||||
const timing = effect.timing;
|
||||
const timing = effect.getTiming();
|
||||
assert_equals(timing.delay, 0, 'default delay');
|
||||
assert_equals(timing.endDelay, 0, 'default endDelay');
|
||||
assert_equals(timing.fill, 'auto', 'default fill');
|
||||
|
@ -142,14 +139,12 @@ test(t => {
|
|||
assert_equals(effect.composite, 'replace', 'default composite');
|
||||
assert_equals(effect.iterationComposite, 'replace',
|
||||
'default iterationComposite');
|
||||
}, 'A KeyframeEffectReadOnly constructed without any ' +
|
||||
'KeyframeEffectOptions object');
|
||||
}, 'A KeyframeEffect constructed without any KeyframeEffectOptions object');
|
||||
|
||||
for (const subtest of gKeyframeEffectOptionTests) {
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(target,
|
||||
{ left: ['10px', '20px'] },
|
||||
subtest.input);
|
||||
const effect = new KeyframeEffect(target, { left: ['10px', '20px'] },
|
||||
subtest.input);
|
||||
|
||||
// Helper function to provide default expected values when the test does
|
||||
// not supply them.
|
||||
|
@ -157,7 +152,7 @@ for (const subtest of gKeyframeEffectOptionTests) {
|
|||
return field in subtest.expected ? subtest.expected[field] : defaultValue;
|
||||
};
|
||||
|
||||
const timing = effect.timing;
|
||||
const timing = effect.getTiming();
|
||||
assert_equals(timing.delay, expected('delay', 0),
|
||||
'timing delay');
|
||||
assert_equals(timing.fill, expected('fill', 'auto'),
|
||||
|
@ -169,27 +164,24 @@ for (const subtest of gKeyframeEffectOptionTests) {
|
|||
assert_equals(timing.direction, expected('direction', 'normal'),
|
||||
'timing direction');
|
||||
|
||||
}, `A KeyframeEffectReadOnly constructed by ${subtest.desc}`);
|
||||
}, `A KeyframeEffect constructed by ${subtest.desc}`);
|
||||
}
|
||||
|
||||
for (const subtest of gInvalidKeyframeEffectOptionTests) {
|
||||
test(t => {
|
||||
assert_throws(new TypeError, () => {
|
||||
new KeyframeEffectReadOnly(target,
|
||||
{ left: ['10px', '20px'] },
|
||||
subtest.input);
|
||||
new KeyframeEffect(target, { left: ['10px', '20px'] }, subtest.input);
|
||||
});
|
||||
}, `Invalid KeyframeEffectReadOnly option by ${subtest.desc}`);
|
||||
}, `Invalid KeyframeEffect option by ${subtest.desc}`);
|
||||
}
|
||||
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(null,
|
||||
{ left: ['10px', '20px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
fill: 'forwards' });
|
||||
const effect = new KeyframeEffect(null, { left: ['10px', '20px'] },
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
fill: 'forwards' });
|
||||
assert_equals(effect.target, null,
|
||||
'Effect created with null target has correct target');
|
||||
}, 'A KeyframeEffectReadOnly constructed with null target');
|
||||
}, 'A KeyframeEffect constructed with null target');
|
||||
|
||||
test(t => {
|
||||
const test_error = { name: 'test' };
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>KeyframeEffect and KeyframeEffectReadOnly copy constructor</title>
|
||||
<title>KeyframeEffect copy constructor</title>
|
||||
<link rel="help"
|
||||
href="https://drafts.csswg.org/web-animations/#dom-keyframeeffect-keyframeeffect-source">
|
||||
<link rel="help"
|
||||
|
@ -14,21 +14,21 @@
|
|||
'use strict';
|
||||
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(createDiv(t), null);
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
const effect = new KeyframeEffect(createDiv(t), null);
|
||||
const copiedEffect = new KeyframeEffect(effect);
|
||||
assert_equals(copiedEffect.target, effect.target, 'same target');
|
||||
}, 'Copied KeyframeEffectReadOnly has the same target');
|
||||
}, 'Copied KeyframeEffect has the same target');
|
||||
|
||||
test(t => {
|
||||
const effect =
|
||||
new KeyframeEffectReadOnly(null,
|
||||
[ { marginLeft: '0px' },
|
||||
{ marginLeft: '-20px', easing: 'ease-in',
|
||||
offset: 0.1 },
|
||||
{ marginLeft: '100px', easing: 'ease-out' },
|
||||
{ marginLeft: '50px' } ]);
|
||||
new KeyframeEffect(null,
|
||||
[ { marginLeft: '0px' },
|
||||
{ marginLeft: '-20px', easing: 'ease-in',
|
||||
offset: 0.1 },
|
||||
{ marginLeft: '100px', easing: 'ease-out' },
|
||||
{ marginLeft: '50px' } ]);
|
||||
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
const copiedEffect = new KeyframeEffect(effect);
|
||||
const keyframesA = effect.getKeyframes();
|
||||
const keyframesB = copiedEffect.getKeyframes();
|
||||
assert_equals(keyframesA.length, keyframesB.length, 'same keyframes length');
|
||||
|
@ -50,34 +50,33 @@ test(t => {
|
|||
assert_equals(keyframesA[i].marginLeft, keyframesB[i].marginLeft,
|
||||
`Keyframe ${i} has the same property value pair`);
|
||||
}
|
||||
}, 'Copied KeyframeEffectReadOnly has the same keyframes');
|
||||
}, 'Copied KeyframeEffect has the same keyframes');
|
||||
|
||||
test(t => {
|
||||
const effect =
|
||||
new KeyframeEffectReadOnly(null, null,
|
||||
{ iterationComposite: 'accumulate' });
|
||||
new KeyframeEffect(null, null, { iterationComposite: 'accumulate' });
|
||||
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
const copiedEffect = new KeyframeEffect(effect);
|
||||
assert_equals(copiedEffect.iterationComposite, effect.iterationComposite,
|
||||
'same iterationCompositeOperation');
|
||||
assert_equals(copiedEffect.composite, effect.composite,
|
||||
'same compositeOperation');
|
||||
}, 'Copied KeyframeEffectReadOnly has the same KeyframeEffectOptions');
|
||||
}, 'Copied KeyframeEffect has the same KeyframeEffectOptions');
|
||||
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(null, null,
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
delay: -1 * MS_PER_SEC,
|
||||
endDelay: 2 * MS_PER_SEC,
|
||||
fill: 'forwards',
|
||||
iterationStart: 2,
|
||||
iterations: 20,
|
||||
easing: 'ease-out',
|
||||
direction: 'alternate' } );
|
||||
const effect = new KeyframeEffect(null, null,
|
||||
{ duration: 100 * MS_PER_SEC,
|
||||
delay: -1 * MS_PER_SEC,
|
||||
endDelay: 2 * MS_PER_SEC,
|
||||
fill: 'forwards',
|
||||
iterationStart: 2,
|
||||
iterations: 20,
|
||||
easing: 'ease-out',
|
||||
direction: 'alternate' } );
|
||||
|
||||
const copiedEffect = new KeyframeEffectReadOnly(effect);
|
||||
const timingA = effect.timing;
|
||||
const timingB = copiedEffect.timing;
|
||||
const copiedEffect = new KeyframeEffect(effect);
|
||||
const timingA = effect.getTiming();
|
||||
const timingB = copiedEffect.getTiming();
|
||||
assert_not_equals(timingA, timingB, 'different timing objects');
|
||||
assert_equals(timingA.delay, timingB.delay, 'same delay');
|
||||
assert_equals(timingA.endDelay, timingB.endDelay, 'same endDelay');
|
||||
|
@ -88,19 +87,7 @@ test(t => {
|
|||
assert_equals(timingA.duration, timingB.duration, 'same duration');
|
||||
assert_equals(timingA.direction, timingB.direction, 'same direction');
|
||||
assert_equals(timingA.easing, timingB.easing, 'same easing');
|
||||
}, 'Copied KeyframeEffectReadOnly has the same timing content');
|
||||
|
||||
test(t => {
|
||||
const effect = new KeyframeEffectReadOnly(createDiv(t), null);
|
||||
assert_equals(effect.constructor.name, 'KeyframeEffectReadOnly');
|
||||
assert_equals(effect.timing.constructor.name,
|
||||
'AnimationEffectTimingReadOnly');
|
||||
|
||||
// Make a mutable copy
|
||||
const copiedEffect = new KeyframeEffect(effect);
|
||||
assert_equals(copiedEffect.constructor.name, 'KeyframeEffect');
|
||||
assert_equals(copiedEffect.timing.constructor.name, 'AnimationEffectTiming');
|
||||
}, 'KeyframeEffect constructed from a KeyframeEffectReadOnly is mutable');
|
||||
}, 'Copied KeyframeEffect has the same timing content');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<script src="/resources/WebIDLParser.js"></script>
|
||||
<script src="/resources/idlharness.js"></script>
|
||||
<div id="log"></div>
|
||||
<script type="text/plain" id="AnimationEffectTimingReadOnly-IDL">
|
||||
<script type="text/plain" id="AnimationEffect-IDL">
|
||||
enum FillMode { "none", "forwards", "backwards", "both", "auto" };
|
||||
enum PlaybackDirection {
|
||||
"normal",
|
||||
|
@ -18,7 +18,7 @@ enum PlaybackDirection {
|
|||
"alternate-reverse"
|
||||
};
|
||||
|
||||
dictionary AnimationEffectTimingProperties {
|
||||
dictionary EffectTiming {
|
||||
double delay = 0.0;
|
||||
double endDelay = 0.0;
|
||||
FillMode fill = "auto";
|
||||
|
@ -29,38 +29,37 @@ dictionary AnimationEffectTimingProperties {
|
|||
DOMString easing = "linear";
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface AnimationEffectTimingReadOnly {
|
||||
readonly attribute double delay;
|
||||
readonly attribute double endDelay;
|
||||
readonly attribute FillMode fill;
|
||||
readonly attribute double iterationStart;
|
||||
readonly attribute unrestricted double iterations;
|
||||
readonly attribute (unrestricted double or DOMString) duration;
|
||||
readonly attribute PlaybackDirection direction;
|
||||
readonly attribute DOMString easing;
|
||||
dictionary OptionalEffectTiming {
|
||||
double delay;
|
||||
double endDelay;
|
||||
FillMode fill;
|
||||
double iterationStart;
|
||||
unrestricted double iterations;
|
||||
(unrestricted double or DOMString) duration;
|
||||
PlaybackDirection direction;
|
||||
DOMString easing;
|
||||
};
|
||||
</script>
|
||||
<script type="text/plain" id="AnimationEffectReadOnly-IDL">
|
||||
dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
|
||||
unrestricted double endTime;
|
||||
unrestricted double activeDuration;
|
||||
double? localTime;
|
||||
double? progress;
|
||||
unrestricted double? currentIteration;
|
||||
|
||||
dictionary ComputedEffectTiming : EffectTiming {
|
||||
unrestricted double endTime = 0.0;
|
||||
unrestricted double activeDuration = 0.0;
|
||||
double? localTime = null;
|
||||
double? progress = null;
|
||||
unrestricted double? currentIteration = null;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface AnimationEffectReadOnly {
|
||||
readonly attribute AnimationEffectTimingReadOnly timing;
|
||||
ComputedTimingProperties getComputedTiming();
|
||||
interface AnimationEffect {
|
||||
EffectTiming getTiming();
|
||||
ComputedEffectTiming getComputedTiming();
|
||||
void updateTiming(optional OptionalEffectTiming timing);
|
||||
};
|
||||
</script>
|
||||
<script type="text/plain" id="KeyframeEffectReadOnly-IDL">
|
||||
<script type="text/plain" id="KeyframeEffect-IDL">
|
||||
enum IterationCompositeOperation { "replace", "accumulate" };
|
||||
enum CompositeOperation { "replace", "add", "accumulate" };
|
||||
|
||||
dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
|
||||
dictionary KeyframeEffectOptions : EffectTiming {
|
||||
IterationCompositeOperation iterationComposite = "replace";
|
||||
CompositeOperation composite = "replace";
|
||||
};
|
||||
|
@ -69,24 +68,13 @@ dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
|
|||
Constructor ((Element or CSSPseudoElement)? target,
|
||||
object? keyframes,
|
||||
optional (unrestricted double or KeyframeEffectOptions) options),
|
||||
Constructor (KeyframeEffectReadOnly source)]
|
||||
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
|
||||
readonly attribute (Element or CSSPseudoElement)? target;
|
||||
readonly attribute IterationCompositeOperation iterationComposite;
|
||||
readonly attribute CompositeOperation composite;
|
||||
Constructor (KeyframeEffect source)]
|
||||
interface KeyframeEffect : AnimationEffect {
|
||||
attribute (Element or CSSPseudoElement)? target;
|
||||
attribute IterationCompositeOperation iterationComposite;
|
||||
attribute CompositeOperation composite;
|
||||
|
||||
sequence<object> getKeyframes ();
|
||||
};
|
||||
</script>
|
||||
<script type="text/plain" id="KeyframeEffect-IDL">
|
||||
[Exposed=Window,
|
||||
Constructor ((Element or CSSPseudoElement)? target,
|
||||
object? keyframes,
|
||||
optional (unrestricted double or KeyframeEffectOptions) options),
|
||||
Constructor (KeyframeEffectReadOnly source)]
|
||||
interface KeyframeEffect : KeyframeEffectReadOnly {
|
||||
inherit attribute (Element or CSSPseudoElement)? target;
|
||||
inherit attribute IterationCompositeOperation iterationComposite;
|
||||
inherit attribute CompositeOperation composite;
|
||||
void setKeyframes (object? keyframes);
|
||||
};
|
||||
</script>
|
||||
|
@ -98,20 +86,13 @@ const idlArray = new IdlArray();
|
|||
idlArray.add_untested_idls('interface CSSPseudoElement {};');
|
||||
idlArray.add_untested_idls('interface Element {};');
|
||||
idlArray.add_untested_idls(
|
||||
document.getElementById('AnimationEffectTimingReadOnly-IDL').textContent
|
||||
);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('AnimationEffectReadOnly-IDL').textContent
|
||||
);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('KeyframeEffectReadOnly-IDL').textContent
|
||||
document.getElementById('AnimationEffect-IDL').textContent
|
||||
);
|
||||
idlArray.add_idls(
|
||||
document.getElementById('KeyframeEffect-IDL').textContent
|
||||
);
|
||||
idlArray.add_objects({
|
||||
KeyframeEffect: ['new KeyframeEffect(null, null)'],
|
||||
KeyframeEffectReadOnly: ['new KeyframeEffectReadOnly(null, null)'],
|
||||
});
|
||||
|
||||
idlArray.test();
|
||||
|
|
|
@ -19,7 +19,8 @@ test(t => {
|
|||
anim.pause();
|
||||
|
||||
anim.currentTime =
|
||||
anim.effect.timing.duration * 2 + anim.effect.timing.duration / 2;
|
||||
anim.effect.getComputedTiming().duration * 2 +
|
||||
anim.effect.getComputedTiming().duration / 2;
|
||||
assert_equals(getComputedStyle(div).marginLeft, '25px',
|
||||
'Animated style at 50s of the third iteration');
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
'use strict';
|
||||
|
||||
// This file only tests the KeyframeEffect constructor since it is
|
||||
// assumed that the implementation of the KeyframeEffectReadOnly constructor,
|
||||
// assumed that the implementation of the KeyframeEffect constructor,
|
||||
// Animatable.animate() method, and KeyframeEffect.setKeyframes() method will
|
||||
// all share common machinery and it is not necessary to test each method.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue