diff options
Diffstat (limited to 'testing/web-platform/tests/web-animations/testcommon.js')
-rw-r--r-- | testing/web-platform/tests/web-animations/testcommon.js | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/testing/web-platform/tests/web-animations/testcommon.js b/testing/web-platform/tests/web-animations/testcommon.js new file mode 100644 index 000000000..31ebdfaf2 --- /dev/null +++ b/testing/web-platform/tests/web-animations/testcommon.js @@ -0,0 +1,176 @@ +/* +Distributed under both the W3C Test Suite License [1] and the W3C +3-clause BSD License [2]. To contribute to a W3C Test Suite, see the +policies and contribution forms [3]. + +[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license +[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license +[3] http://www.w3.org/2004/10/27-testcases + */ + +'use strict'; + +var MS_PER_SEC = 1000; + +// The recommended minimum precision to use for time values[1]. +// +// [1] https://w3c.github.io/web-animations/#precision-of-time-values +var TIME_PRECISION = 0.0005; // ms + +// Allow implementations to substitute an alternative method for comparing +// times based on their precision requirements. +if (!window.assert_times_equal) { + window.assert_times_equal = function(actual, expected, description) { + assert_approx_equals(actual, expected, TIME_PRECISION, description); + } +} + +// creates div element, appends it to the document body and +// removes the created element during test cleanup +function createDiv(test, doc) { + return createElement(test, 'div', doc); +} + +// creates element of given tagName, appends it to the document body and +// removes the created element during test cleanup +// if tagName is null or undefined, returns div element +function createElement(test, tagName, doc) { + if (!doc) { + doc = document; + } + var element = doc.createElement(tagName || 'div'); + doc.body.appendChild(element); + test.add_cleanup(function() { + element.remove(); + }); + return element; +} + +// Creates a style element with the specified rules, appends it to the document +// head and removes the created element during test cleanup. +// |rules| is an object. For example: +// { '@keyframes anim': '' , +// '.className': 'animation: anim 100s;' }; +// or +// { '.className1::before': 'content: ""; width: 0px; transition: all 10s;', +// '.className2::before': 'width: 100px;' }; +// The object property name could be a keyframes name, or a selector. +// The object property value is declarations which are property:value pairs +// split by a space. +function createStyle(test, rules, doc) { + if (!doc) { + doc = document; + } + var extraStyle = doc.createElement('style'); + doc.head.appendChild(extraStyle); + if (rules) { + var sheet = extraStyle.sheet; + for (var selector in rules) { + sheet.insertRule(selector + '{' + rules[selector] + '}', + sheet.cssRules.length); + } + } + test.add_cleanup(function() { + extraStyle.remove(); + }); +} + +// Create a pseudo element +function createPseudo(test, type) { + createStyle(test, { '@keyframes anim': '', + ['.pseudo::' + type]: 'animation: anim 10s;' }); + var div = createDiv(test); + div.classList.add('pseudo'); + var anims = document.getAnimations(); + assert_true(anims.length >= 1); + var anim = anims[anims.length - 1]; + assert_equals(anim.effect.target.parentElement, div); + assert_equals(anim.effect.target.type, '::' + type); + anim.cancel(); + return anim.effect.target; +} + +// Convert px unit value to a Number +function pxToNum(str) { + return Number(String(str).match(/^(-?[\d.]+)px$/)[1]); +} + +// Cubic bezier with control points (0, 0), (x1, y1), (x2, y2), and (1, 1). +function cubicBezier(x1, y1, x2, y2) { + function xForT(t) { + var omt = 1-t; + return 3 * omt * omt * t * x1 + 3 * omt * t * t * x2 + t * t * t; + } + + function yForT(t) { + var omt = 1-t; + return 3 * omt * omt * t * y1 + 3 * omt * t * t * y2 + t * t * t; + } + + function tForX(x) { + // Binary subdivision. + var mint = 0, maxt = 1; + for (var i = 0; i < 30; ++i) { + var guesst = (mint + maxt) / 2; + var guessx = xForT(guesst); + if (x < guessx) { + maxt = guesst; + } else { + mint = guesst; + } + } + return (mint + maxt) / 2; + } + + return function bezierClosure(x) { + if (x == 0) { + return 0; + } + if (x == 1) { + return 1; + } + return yForT(tForX(x)); + } +} + +function stepEnd(nsteps) { + return function stepEndClosure(x) { + return Math.floor(x * nsteps) / nsteps; + } +} + +function stepStart(nsteps) { + return function stepStartClosure(x) { + var result = Math.floor(x * nsteps + 1.0) / nsteps; + return (result > 1.0) ? 1.0 : result; + } +} + +function waitForAnimationFrames(frameCount) { + return new Promise(function(resolve, reject) { + function handleFrame() { + if (--frameCount <= 0) { + resolve(); + } else { + window.requestAnimationFrame(handleFrame); // wait another frame + } + } + window.requestAnimationFrame(handleFrame); + }); +} + +// Continually calls requestAnimationFrame until |minDelay| has elapsed +// as recorded using document.timeline.currentTime (i.e. frame time not +// wall-clock time). +function waitForAnimationFramesWithDelay(minDelay) { + var startTime = document.timeline.currentTime; + return new Promise(function(resolve) { + (function handleFrame() { + if (document.timeline.currentTime - startTime >= minDelay) { + resolve(); + } else { + window.requestAnimationFrame(handleFrame); + } + }()); + }); +} |