diff options
Diffstat (limited to 'testing/web-platform/tests/css/css-transitions/support')
51 files changed, 1239 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-green.png b/testing/web-platform/tests/css/css-transitions/support/1x1-green.png Binary files differnew file mode 100644 index 0000000000..b98ca0ba0a --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/1x1-green.png diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-lime.png b/testing/web-platform/tests/css/css-transitions/support/1x1-lime.png Binary files differnew file mode 100644 index 0000000000..cb397fb090 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/1x1-lime.png diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-maroon.png b/testing/web-platform/tests/css/css-transitions/support/1x1-maroon.png Binary files differnew file mode 100644 index 0000000000..3f86b07219 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/1x1-maroon.png diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-navy.png b/testing/web-platform/tests/css/css-transitions/support/1x1-navy.png Binary files differnew file mode 100644 index 0000000000..9b9a03955b --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/1x1-navy.png diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-red.png b/testing/web-platform/tests/css/css-transitions/support/1x1-red.png Binary files differnew file mode 100644 index 0000000000..6bd73ac101 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/1x1-red.png diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-white.png b/testing/web-platform/tests/css/css-transitions/support/1x1-white.png Binary files differnew file mode 100644 index 0000000000..dd43faec54 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/1x1-white.png diff --git a/testing/web-platform/tests/css/css-transitions/support/60x60-gg-rr.png b/testing/web-platform/tests/css/css-transitions/support/60x60-gg-rr.png Binary files differnew file mode 100644 index 0000000000..84f5b2a4f1 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/60x60-gg-rr.png diff --git a/testing/web-platform/tests/css/css-transitions/support/60x60-green.png b/testing/web-platform/tests/css/css-transitions/support/60x60-green.png Binary files differnew file mode 100644 index 0000000000..b3c8cf3eb4 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/60x60-green.png diff --git a/testing/web-platform/tests/css/css-transitions/support/README b/testing/web-platform/tests/css/css-transitions/support/README new file mode 100644 index 0000000000..2e5f2ad073 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/README @@ -0,0 +1,28 @@ +CSS Global Support Directory +============================ + +This directory contains common support files (such as images and external +style sheets). These are sync'ed into the support directories of all our +test suites. If you have test-suite-specific support files, please add +them to the appropriate test-suite-specific support/ directory. + +If you add to a support/ directory, please run the tools/supportprop.py +script from the top of the repository to cascade support files into the +lower-level support directories. + +Description of the Common Support File Collection +------------------------------------------------- + +The 1x1-* images are all exactly one pixel. + +The swatch-* images all use 15x15 cells. + +The square-* images all use 15x15 cells with one pixel borders. + +The pattern-* images use cells of various sizes: + + pattern-grg-rgr-grg.png 20x20 + pattern-rgr-grg-rgr.png 20x20 + pattern-tr.png 15x15 + pattern-grg-rrg-rgg.png 15x15 + diff --git a/testing/web-platform/tests/css/css-transitions/support/a-green-transition.css b/testing/web-platform/tests/css/css-transitions/support/a-green-transition.css new file mode 100644 index 0000000000..3f68e53cd6 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/a-green-transition.css @@ -0,0 +1 @@ +.a { color: green; transition: 10s; transition-timing-function: step-end; } diff --git a/testing/web-platform/tests/css/css-transitions/support/a-green.css b/testing/web-platform/tests/css/css-transitions/support/a-green.css new file mode 100644 index 0000000000..b0dbb071d5 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/a-green.css @@ -0,0 +1 @@ +.a { color: green; } diff --git a/testing/web-platform/tests/css/css-transitions/support/b-green.css b/testing/web-platform/tests/css/css-transitions/support/b-green.css new file mode 100644 index 0000000000..a0473f5ca2 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/b-green.css @@ -0,0 +1 @@ +.b { color: green; }
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-transitions/support/c-red.css b/testing/web-platform/tests/css/css-transitions/support/c-red.css new file mode 100644 index 0000000000..d4ba5c64e9 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/c-red.css @@ -0,0 +1 @@ +.c { color: red; }
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-transitions/support/cat.png b/testing/web-platform/tests/css/css-transitions/support/cat.png Binary files differnew file mode 100644 index 0000000000..85dd732481 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/cat.png diff --git a/testing/web-platform/tests/css/css-transitions/support/generalParallelTest.js b/testing/web-platform/tests/css/css-transitions/support/generalParallelTest.js new file mode 100644 index 0000000000..f6e14128fc --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/generalParallelTest.js @@ -0,0 +1,231 @@ +(function(root) { +'use strict'; +// +var index = 0; +var suite = root.generalParallelTest = { + // prepare individual test + setup: function(data, options) { + suite._setupDom(data, options); + suite._setupEvents(data, options); + }, + // clone fixture and prepare data containers + _setupDom: function(data, options) { + // clone fixture into off-viewport test-canvas + data.fixture = document.getElementById('fixture').cloneNode(true); + data.fixture.id = 'test-' + (index++); + (document.getElementById('offscreen') || document.body).appendChild(data.fixture); + + // data container for #fixture > .container > .transition + data.transition = { + node: data.fixture.querySelector('.transition'), + values: [], + events: [], + computedStyle: function(property) { + return computedStyle(data.transition.node, property); + } + }; + + // data container for #fixture > .container + data.container = { + node: data.transition.node.parentNode, + values: [], + events: [], + computedStyle: function(property) { + return computedStyle(data.container.node, property); + } + }; + + // data container for #fixture > .container > .transition[:before | :after] + if (data.pseudo) { + data.pseudo = { + name: data.pseudo, + values: [], + computedStyle: function(property) { + return computedStyle(data.transition.node, property, ':' + data.pseudo.name); + } + }; + } + }, + // bind TransitionEnd event listeners + _setupEvents: function(data, options) { + ['transition', 'container'].forEach(function(elem) { + var handler = function(event) { + event.stopPropagation(); + var name = event.propertyName; + var time = Math.round(event.elapsedTime * 1000) / 1000; + var pseudo = event.pseudoElement ? (':' + event.pseudoElement) : ''; + data[elem].events.push(name + pseudo + ":" + time + "s"); + }; + data[elem].node.addEventListener('transitionend', handler, false); + data[elem]._events = {'transitionend': handler}; + }); + }, + // cleanup after individual test + teardown: function(data, options) { + // data.fixture.remove(); + if (data.fixture.parentNode) { + data.fixture.parentNode.removeChild(data.fixture); + } + }, + // invoked prior to running a slice of tests + sliceStart: function(options, tests) { + // inject styles into document + setStyle(options.styles); + // kick off value collection loop + generalParallelTest.startValueCollection(options); + }, + // invoked after running a slice of tests + sliceDone: function(options, tests) { + // stop value collection loop + generalParallelTest.stopValueCollection(options); + // reset styles cache + options.styles = {}; + }, + // called once all tests are done + done: function(options) { + // reset document styles + setStyle(); + reflow(); + }, + // add styles of individual test to slice cache + addStyles: function(data, options, styles) { + if (!options.styles) { + options.styles = {}; + } + + Object.keys(styles).forEach(function(key) { + var selector = '#' + data.fixture.id + // fixture must become #fixture.fixture rather than a child selector + + (key.substring(0, 8) === '.fixture' ? '' : ' ') + + key; + + options.styles[selector] = styles[key]; + }); + }, + // set style and compute values for container and transition + getStyle: function(data) { + reflow(); + // grab current styles: "initial state" + suite._getStyleFor(data, 'from'); + // apply target state + suite._addClass(data, 'to', true); + // grab current styles: "target state" + suite._getStyleFor(data, 'to'); + // remove target state + suite._removeClass(data, 'to', true); + + // clean up the mess created for value collection + data.container._values = []; + data.transition._values = []; + if (data.pseudo) { + data.pseudo._values = []; + } + }, + // grab current styles and store in respective element's data container + _getStyleFor: function(data, key) { + data.container[key] = data.container.computedStyle(data.property); + data.transition[key] = data.transition.computedStyle(data.property); + if (data.pseudo) { + data.pseudo[key] = data.pseudo.computedStyle(data.property); + } + }, + // add class to test's elements and possibly reflow + _addClass: function(data, className, forceReflow) { + data.container.node.classList.add(className); + data.transition.node.classList.add(className); + if (forceReflow) { + reflow(); + } + }, + // remove class from test's elements and possibly reflow + _removeClass: function(data, className, forceReflow) { + data.container.node.classList.remove(className); + data.transition.node.classList.remove(className); + if (forceReflow) { + reflow(); + } + }, + // add transition and to classes to container and transition + startTransition: function(data) { + // add transition-defining class + suite._addClass(data, 'how', true); + // add target state (without reflowing) + suite._addClass(data, 'to', false); + }, + // requestAnimationFrame runLoop to collect computed values + startValueCollection: function(options) { + var raf = window.requestAnimationFrame || function(callback){ + setTimeout(callback, 20); + }; + + // flag denoting if the runLoop should continue (true) or exit (false) + options._collectValues = true; + + function runLoop() { + if (!options._collectValues) { + // test's are done, stop annoying the CPU + return; + } + + // collect current style for test's elements + options.tests.forEach(function(data) { + if (!data.property) { + return; + } + + ['transition', 'container', 'pseudo'].forEach(function(elem) { + var pseudo = null; + if (!data[elem] || (elem === 'pseudo' && !data.pseudo)) { + return; + } + + var current = data[elem].computedStyle(data.property); + var values = data[elem].values; + var length = values.length; + if (!length || values[length - 1] !== current) { + values.push(current); + } + }); + }); + + // rinse and repeat + raf(runLoop); + } + + runLoop(); + }, + // stop requestAnimationFrame runLoop collecting computed values + stopValueCollection: function(options) { + options._collectValues = false; + }, + + // generate test.step function asserting collected events match expected + assertExpectedEventsFunc: function(data, elem, expected) { + return function() { + var _result = data[elem].events.sort().join(" "); + var _expected = typeof expected === 'string' ? expected : expected.sort().join(" "); + assert_equals(_result, _expected, "Expected TransitionEnd events triggered on ." + elem); + }; + }, + // generate test.step function asserting collected values are neither initial nor target + assertIntermediateValuesFunc: function(data, elem) { + return function() { + // the first value (index: 0) is always going to be the initial value + // the last value is always going to be the target value + var values = data[elem].values; + if (data.flags.discrete) { + // a discrete value will just switch from one state to another without having passed intermediate states. + assert_equals(values[0], data[elem].from, "must be initial value while transitioning on ." + elem); + assert_equals(values[1], data[elem].to, "must be target value after transitioning on ." + elem); + assert_equals(values.length, 2, "discrete property only has 2 values ." + elem); + } else { + assert_not_equals(values[1], data[elem].from, "may not be initial value while transitioning on ." + elem); + assert_not_equals(values[1], data[elem].to, "may not be target value while transitioning on ." + elem); + } + + // TODO: first value must be initial, last value must be target + }; + } +}; + +})(window); diff --git a/testing/web-platform/tests/css/css-transitions/support/helper.js b/testing/web-platform/tests/css/css-transitions/support/helper.js new file mode 100644 index 0000000000..a37aae9183 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/helper.js @@ -0,0 +1,326 @@ +// +// Simple Helper Functions For Testing CSS +// + +(function(root) { +'use strict'; + +// serialize styles object and dump to dom +// appends <style id="dynamic-style"> to <head> +// setStyle("#some-selector", {"some-style" : "value"}) +// setStyle({"#some-selector": {"some-style" : "value"}}) +root.setStyle = function(selector, styles) { + var target = document.getElementById('dynamic-style'); + if (!target) { + target = document.createElement('style'); + target.id = 'dynamic-style'; + target.type = "text/css"; + document.getElementsByTagName('head')[0].appendChild(target); + } + + var data = []; + // single selector/styles + if (typeof selector === 'string' && styles !== undefined) { + data = [selector, '{', serializeStyles(styles), '}']; + target.textContent = data.join("\n"); + return; + } + // map of selector/styles + for (var key in selector) { + if (Object.prototype.hasOwnProperty.call(selector, key)) { + var _data = [key, '{', serializeStyles(selector[key]), '}']; + data.push(_data.join('\n')); + } + } + + target.textContent = data.join("\n"); +}; + +function serializeStyles(styles) { + var data = []; + for (var property in styles) { + if (Object.prototype.hasOwnProperty.call(styles, property)) { + var prefixedProperty = addVendorPrefix(property); + data.push(prefixedProperty + ":" + styles[property] + ";"); + } + } + + return data.join('\n'); +} + + +// shorthand for computed style +root.computedStyle = function(element, property, pseudo) { + var prefixedProperty = addVendorPrefix(property); + return window + .getComputedStyle(element, pseudo || null) + .getPropertyValue(prefixedProperty); +}; + +// flush rendering buffer +root.reflow = function() { + document.body.offsetWidth; +}; + +// merge objects +root.extend = function(target /*, ..rest */) { + Array.prototype.slice.call(arguments, 1).forEach(function(obj) { + Object.keys(obj).forEach(function(key) { + target[key] = obj[key]; + }); + }); + + return target; +}; + +// dom fixture helper ("resetting dom test elements") +var _domFixture; +var _domFixtureSelector; +root.domFixture = function(selector) { + var fixture = document.querySelector(selector || _domFixtureSelector); + if (!fixture) { + throw new Error('fixture ' + (selector || _domFixtureSelector) + ' not found!'); + } + if (!_domFixture && selector) { + // save a copy + _domFixture = fixture.cloneNode(true); + _domFixtureSelector = selector; + } else if (_domFixture) { + // restore the copy + var tmp = _domFixture.cloneNode(true); + fixture.parentNode.replaceChild(tmp, fixture); + } else { + throw new Error('domFixture must be initialized first!'); + } +}; + +root.MS_PER_SEC = 1000; + +/* + * The recommended minimum precision to use for time values. + * + * Based on Web Animations: + * https://w3c.github.io/web-animations/#precision-of-time-values + */ +const TIME_PRECISION = 0.0005; // ms + +/* + * Allow implementations to substitute an alternative method for comparing + * times based on their precision requirements. + */ +root.assert_times_equal = function(actual, expected, description) { + assert_approx_equals(actual, expected, TIME_PRECISION, description); +}; + +/* + * Compare a time value based on its precision requirements with a fixed value. + */ +root.assert_time_equals_literal = (actual, expected, description) => { + assert_approx_equals(actual, expected, TIME_PRECISION, description); +}; + +/** + * Assert that CSSTransition event, |evt|, has the expected property values + * defined by |propertyName|, |elapsedTime|, and |pseudoElement|. + */ +root.assert_end_events_equal = function(evt, propertyName, elapsedTime, + pseudoElement = '') { + assert_equals(evt.propertyName, propertyName); + assert_times_equal(evt.elapsedTime, elapsedTime); + assert_equals(evt.pseudoElement, pseudoElement); +}; + +/** + * Assert that array of simultaneous CSSTransition events, |evts|, have the + * corresponding property names listed in |propertyNames|, and the expected + * |elapsedTimes| and |pseudoElement| members. + * + * |elapsedTimes| may be a single value if all events are expected to have the + * same elapsedTime, or an array parallel to |propertyNames|. + */ +root.assert_end_event_batch_equal = function(evts, propertyNames, elapsedTimes, + pseudoElement = '') { + assert_equals( + evts.length, + propertyNames.length, + 'Test harness error: should have waited for the correct number of events' + ); + assert_true( + typeof elapsedTimes === 'number' || + (Array.isArray(elapsedTimes) && + elapsedTimes.length === propertyNames.length), + 'Test harness error: elapsedTimes must either be a number or an array of' + + ' numbers with the same length as propertyNames' + ); + + if (typeof elapsedTimes === 'number') { + elapsedTimes = Array(propertyNames.length).fill(elapsedTimes); + } + const testPairs = propertyNames.map((propertyName, index) => ({ + propertyName, + elapsedTime: elapsedTimes[index] + })); + + const sortByPropertyName = (a, b) => + a.propertyName.localeCompare(b.propertyName); + evts.sort(sortByPropertyName); + testPairs.sort(sortByPropertyName); + + for (let evt of evts) { + const expected = testPairs.shift(); + assert_end_events_equal( + evt, + expected.propertyName, + expected.elapsedTime, + pseudoElement + ); + } +} + +/** + * Appends a div to the document body. + * + * @param t The testharness.js Test object. If provided, this will be used + * to register a cleanup callback to remove the div when the test + * finishes. + * + * @param attrs A dictionary object with attribute names and values to set on + * the div. + */ +root.addDiv = function(t, attrs) { + var div = document.createElement('div'); + if (attrs) { + for (var attrName in attrs) { + div.setAttribute(attrName, attrs[attrName]); + } + } + document.body.appendChild(div); + if (t && typeof t.add_cleanup === 'function') { + t.add_cleanup(function() { + if (div.parentNode) { + div.remove(); + } + }); + } + return div; +}; + +/** + * Appends a style div to the document head. + * + * @param t The testharness.js Test object. If provided, this will be used + * to register a cleanup callback to remove the style element + * when the test finishes. + * + * @param rules A dictionary object with selector names and rules to set on + * the style sheet. + */ +root.addStyle = (t, rules) => { + const extraStyle = document.createElement('style'); + document.head.appendChild(extraStyle); + if (rules) { + const sheet = extraStyle.sheet; + for (const selector in rules) { + sheet.insertRule(selector + '{' + rules[selector] + '}', + sheet.cssRules.length); + } + } + + if (t && typeof t.add_cleanup === 'function') { + t.add_cleanup(() => { + extraStyle.remove(); + }); + } + return extraStyle; +}; + +/** + * Promise wrapper for requestAnimationFrame. + */ +root.waitForFrame = () => { + return new Promise(resolve => { + window.requestAnimationFrame(resolve); + }); +}; + +/** + * Returns a Promise that is resolved after the given number of consecutive + * animation frames have occured (using requestAnimationFrame callbacks). + * + * @param frameCount The number of animation frames. + * @param onFrame An optional function to be processed in each animation frame. + */ +root.waitForAnimationFrames = (frameCount, onFrame) => { + const timeAtStart = document.timeline.currentTime; + return new Promise(resolve => { + function handleFrame() { + if (onFrame && typeof onFrame === 'function') { + onFrame(); + } + if (timeAtStart != document.timeline.currentTime && + --frameCount <= 0) { + resolve(); + } else { + window.requestAnimationFrame(handleFrame); // wait another frame + } + } + window.requestAnimationFrame(handleFrame); + }); +}; + +/** + * Wrapper that takes a sequence of N animations and returns: + * + * Promise.all([animations[0].ready, animations[1].ready, ... animations[N-1].ready]); + */ +root.waitForAllAnimations = animations => + Promise.all(animations.map(animation => animation.ready)); + +/** + * Utility that takes a Promise and a maximum number of frames to wait and + * returns a new Promise that behaves as follows: + * + * - If the provided Promise resolves _before_ the specified number of frames + * have passed, resolves with the result of the provided Promise. + * - If the provided Promise rejects _before_ the specified number of frames + * have passed, rejects with the error result of the provided Promise. + * - Otherwise, rejects with a 'Timed out' error message. If |message| is + * provided, it will be appended to the error message. + */ +root.frameTimeout = (promiseToWaitOn, framesToWait, message) => { + let framesRemaining = framesToWait; + let aborted = false; + + const timeoutPromise = new Promise(function waitAFrame(resolve, reject) { + if (aborted) { + resolve(); + return; + } + if (framesRemaining-- > 0) { + requestAnimationFrame(() => { + waitAFrame(resolve, reject); + }); + return; + } + let errorMessage = 'Timed out waiting for Promise to resolve'; + if (message) { + errorMessage += `: ${message}`; + } + reject(new Error(errorMessage)); + }); + + const wrappedPromiseToWaitOn = promiseToWaitOn.then(result => { + aborted = true; + return result; + }); + + return Promise.race([timeoutPromise, wrappedPromiseToWaitOn]); +}; + +root.supportsStartingStyle = () => { + let sheet = new CSSStyleSheet(); + sheet.replaceSync("@starting-style{}"); + return sheet.cssRules.length == 1; +}; + +})(window); diff --git a/testing/web-platform/tests/css/css-transitions/support/import-green.css b/testing/web-platform/tests/css/css-transitions/support/import-green.css new file mode 100644 index 0000000000..537104e663 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/import-green.css @@ -0,0 +1 @@ +.import { color: green; } diff --git a/testing/web-platform/tests/css/css-transitions/support/import-red.css b/testing/web-platform/tests/css/css-transitions/support/import-red.css new file mode 100644 index 0000000000..9945ef4711 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/import-red.css @@ -0,0 +1 @@ +.import { color: red; } diff --git a/testing/web-platform/tests/css/css-transitions/support/one.gif b/testing/web-platform/tests/css/css-transitions/support/one.gif Binary files differnew file mode 100644 index 0000000000..74cf7839c9 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/one.gif diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rgr-grg.png b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rgr-grg.png Binary files differnew file mode 100644 index 0000000000..9b88fbd811 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rgr-grg.png diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rrg-rgg.png b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rrg-rgg.png Binary files differnew file mode 100644 index 0000000000..fcf4f3fd7d --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rrg-rgg.png diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-rgr-grg-rgr.png b/testing/web-platform/tests/css/css-transitions/support/pattern-rgr-grg-rgr.png Binary files differnew file mode 100644 index 0000000000..d454e3a630 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/pattern-rgr-grg-rgr.png diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-tr.png b/testing/web-platform/tests/css/css-transitions/support/pattern-tr.png Binary files differnew file mode 100644 index 0000000000..8b4b25364e --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/pattern-tr.png diff --git a/testing/web-platform/tests/css/css-transitions/support/properties.js b/testing/web-platform/tests/css/css-transitions/support/properties.js new file mode 100644 index 0000000000..0c0057b39e --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/properties.js @@ -0,0 +1,410 @@ +(function(root){ + +/* + * General Value Types definition + * they return an object of arrays of type { <name>: [<start-value>, <end-value>], ... } + */ +var values = { + 'length' : function() { + // http://www.w3.org/TR/css3-values/#lengths + return { + // CSS Values and Module Level 3 + // ch: ['1ch', '10ch'], + // rem: ['1rem', '10rem'], + // vw: ['1vw', '10vw'], + // vh: ['1vh', '10vh'], + // vmin: ['1vmin', '10vmin'], + // vmax: ['1vmax', '10vmax'], + // CSS Values and Module Level 2 + pt: ['1pt', '10pt'], + pc: ['1pc', '10pc'], + px: ['1px', '10px'], + // CSS Values and Module Level 1 + em: ['1em', '10em'], + ex: ['1ex', '10ex'], + mm: ['1mm', '10mm'], + cm: ['1cm', '10cm'], + 'in': ['1in', '10in'] + }; + }, + 'length-em': function() { + return { + em: ['1.1em', '1.5em'] + }; + }, + 'percentage': function() { + // http://www.w3.org/TR/css3-values/#percentages + return { + '%': ['33%', '80%'] + }; + }, + 'color': function() { + // http://www.w3.org/TR/css3-values/#colors + // http://www.w3.org/TR/css3-color/ + return { + rgba: ['rgba(100,100,100,1)', 'rgba(10,10,10,0.4)'] + }; + }, + 'rectangle': function() { + // http://www.w3.org/TR/CSS2/visufx.html#value-def-shape + return { + rectangle: ['rect(10px,10px,10px,10px)', 'rect(15px,15px,5px,5px)'] + }; + }, + 'font-weight': function() { + // http://www.w3.org/TR/css3-fonts/#font-weight-prop + return { + keyword: ["normal", "bold"], + numeric: ["100", "900"] + }; + }, + 'number': function() { + // http://www.w3.org/TR/css3-values/#number + return { + integer: ["1", "10"], + decimal: ["1.1", "9.55"] + }; + }, + 'number[0,1]': function() { + // http://www.w3.org/TR/css3-values/#number + // applies to [0,1]-ranged properties like opacity + return { + "zero-to-one": ["0.2", "0.9"] + }; + }, + 'integer': function() { + // http://www.w3.org/TR/css3-values/#integer + return { + integer: ["1", "10"] + }; + }, + 'shadow': function() { + // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property + return { + shadow: ['rgba(0,0,0,0.1) 5px 6px 7px', 'rgba(10,10,10,0.9) 5px 6px 7px'] + }; + }, + 'visibility': function() { + // http://www.w3.org/TR/CSS2/visufx.html#visibility + return { + keyword: ['visible', 'hidden', {discrete: true}] + }; + }, + // types reqired for non-specified properties + 'border-radius': function() { + return { + px: ['1px', '10px'], + "px-px": ['1px 3px', '10px 13px'] + }; + }, + 'image' : function() { + var prefix = getValueVendorPrefix('background-image', 'linear-gradient(top, hsl(0, 80%, 70%), #bada55)'); + return { + // Chrome implements this + url: ['url(support/one.gif)', 'url(support/two.gif)'], + data: ['url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=)', 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==)'], + // A hunch, as from the spec: + // http://www.w3.org/TR/css3-transitions/#animatable-types + // gradient: interpolated via the positions and colors of each stop. They must have the same type (radial or linear) and same number of stops in order to be animated. Note: [CSS3-IMAGES] may extend this definition. + gradient: [prefix + 'linear-gradient(top, hsl(0, 80%, 70%), #bada55)', prefix + 'linear-gradient(top, #bada55, hsl(0, 80%, 70%))'] + }; + }, + 'background-size': function() { + return { + keyword: ['cover', 'contain'] + }; + }, + 'box-shadow': function() { + // http://www.w3.org/TR/css3-background/#ltshadowgt + return { + shadow: ['60px -16px teal', '60px -16px red'] + }; + }, + 'vertical': function() { + return { + keyword: ['top', 'bottom'] + }; + }, + 'horizontal': function() { + return { + keyword: ['left', 'right'] + }; + }, + 'font-stretch': function() { + return { + keyword: ['condensed', 'expanded'] + }; + }, + 'transform': function() { + return { + rotate: ['rotate(10deg)', 'rotate(20deg)'] + }; + }, + 'position': function() { + return { + 'static to absolute': ['static', 'absolute', {discrete: true}], + 'relative to absolute': ['relative', 'absolute', {discrete: true}], + 'absolute to fixed': ['absolute', 'fixed', {discrete: true}] + }; + }, + 'display': function() { + return { + 'static to absolute': ['none', 'block', {discrete: true}], + 'block to inline-block': ['block', 'inline-block', {discrete: true}] + }; + }, + 'object-view-box': function() { + return { + inset: ['inset(10% 10% 20% 20%)', 'inset(20% 20% 30% 30%)'], + rect: ['rect(10px 20px 30px 40px)', 'rect(20px 30px 40px 50px)'], + xywh: ['xywh(10px 20px 30px 40px)', 'xywh(20px 30px 40px 50px)'], + }; + } +}; + +/* + * Property to Type table + * (as stated in specification) + */ +var properties = { + 'background-color': ['color'], + 'background-position': ['length', 'percentage'], + + 'border-top-width': ['length'], + 'border-right-width': ['length'], + 'border-bottom-width': ['length'], + 'border-left-width': ['length'], + + 'border-top-color': ['color'], + 'border-right-color': ['color'], + 'border-bottom-color': ['color'], + 'border-left-color': ['color'], + + 'padding-bottom': ['length'], + 'padding-left': ['length'], + 'padding-right': ['length'], + 'padding-top': ['length'], + + 'margin-bottom': ['length'], + 'margin-left': ['length'], + 'margin-right': ['length'], + 'margin-top': ['length'], + + 'height': ['length', 'percentage'], + 'width': ['length', 'percentage'], + 'min-height': ['length', 'percentage'], + 'min-width': ['length', 'percentage'], + 'max-height': ['length', 'percentage'], + 'max-width': ['length', 'percentage'], + + 'top': ['length', 'percentage'], + 'right': ['length', 'percentage'], + 'bottom': ['length', 'percentage'], + 'left': ['length', 'percentage'], + + 'color': ['color'], + 'font-size': ['length', 'percentage'], + 'font-weight': ['font-weight'], + 'line-height': ['number', 'length', 'percentage'], + 'letter-spacing': ['length'], + // Note: percentage is Level3 and not implemented anywhere yet + // https://drafts.csswg.org/css3-text/#word-spacing + 'word-spacing': ['length', 'percentage'], + 'text-indent': ['length', 'percentage'], + 'text-shadow': ['shadow'], + + 'outline-color': ['color'], + // outline-offset <integer> used to be an error in the spec + 'outline-offset': ['length'], + 'outline-width': ['length'], + + 'clip': ['rectangle'], + + 'vertical-align': ['length', 'percentage'], + 'opacity': ['number[0,1]'], + 'visibility': ['visibility'], + 'z-index': ['integer'] +}; + +/* + * Property to Type table + * (missing value-types of specified properties) + */ +var missing_properties = { + 'margin-bottom': ['percentage'], + 'margin-left': ['percentage'], + 'margin-right': ['percentage'], + 'margin-top': ['percentage'], + 'padding-bottom': ['percentage'], + 'padding-left': ['percentage'], + 'padding-right': ['percentage'], + 'padding-top': ['percentage'], + 'vertical-align': ['vertical'] +}; + +/* + * Property to Type table + * (properties that haven't been specified but implemented) + */ +var unspecified_properties = { + // http://oli.jp/2010/css-animatable-properties/ + 'border-top-left-radius': ['border-radius'], + 'border-top-right-radius': ['border-radius'], + 'border-bottom-left-radius': ['border-radius'], + 'border-bottom-right-radius': ['border-radius'], + 'background-image': ['image'], + 'background-size': ['background-size'], + // https://drafts.csswg.org/css3-background/#the-box-shadow + // Animatable: yes, except between inner and outer shadows (Transition to/from an absent shadow is a transition to/from ‘0 0 transparent’ or ‘0 0 transparent inset’, as appropriate.) + 'box-shadow': ['box-shadow'], + 'font-size-adjust': ['number'], + 'font-stretch': ['font-stretch'], + 'text-decoration-color': ['color'], + 'column-count': ['integer'], + 'column-gap': ['length'], + 'column-rule-color': ['color'], + 'column-rule-width': ['length'], + 'column-width': ['length'], + 'transform': ['transform'], + 'transform-origin': ['horizontal'], + 'display': ['display'], + 'position': ['position'], + 'object-view-box': ['object-view-box'] +}; + +/* + * additional styles required to actually render + * (different browsers expect different environment) + */ +var additional_styles = { + // all browsers + 'border-top-width': {'border-top-style' : 'solid'}, + 'border-right-width': {'border-right-style' : 'solid'}, + 'border-bottom-width': {'border-bottom-style' : 'solid'}, + 'border-left-width': {'border-left-style' : 'solid'}, + 'top': {'position': 'absolute'}, + 'right': {'position': 'absolute'}, + 'bottom': {'position': 'absolute'}, + 'left': {'position': 'absolute'}, + 'z-index': {'position': 'absolute'}, + 'outline-offset': {'outline-style': 'solid'}, + 'outline-width': {'outline-style': 'solid'}, + 'word-spacing': {'width': '100px', 'height': '100px'}, + // unspecified properties + 'column-rule-width': {'column-rule-style': 'solid'}, + 'position': {'width': '50px', 'height': '50px', top: '10px', left: '50px'} +}; + +/* + * additional styles required *on the parent* to actually render + * (different browsers expect different environment) + */ +var parent_styles = { + 'border-top-width': {'border-top-style' : 'solid'}, + 'border-right-width': {'border-right-style' : 'solid'}, + 'border-bottom-width': {'border-bottom-style' : 'solid'}, + 'border-left-width': {'border-left-style' : 'solid'}, + 'height': {'width': '100px', 'height': '100px'}, + 'min-height': {'width': '100px', 'height': '100px'}, + 'max-height': {'width': '100px', 'height': '100px'}, + 'width': {'width': '100px', 'height': '100px'}, + 'min-width': {'width': '100px', 'height': '100px'}, + 'max-width': {'width': '100px', 'height': '100px'}, + // unspecified properties + 'position': {'position': 'relative', 'width': '100px', 'height': '100px'}, + // inheritance tests + 'top': {'width': '100px', 'height': '100px', 'position': 'relative'}, + 'right': {'width': '100px', 'height': '100px', 'position': 'relative'}, + 'bottom': {'width': '100px', 'height': '100px', 'position': 'relative'}, + 'left': {'width': '100px', 'height': '100px', 'position': 'relative'} +}; + + +function assemble(props) { + var tests = []; + + // assemble tests + for (var property in props) { + props[property].forEach(function(type) { + var _values = values[type](property); + Object.keys(_values).forEach(function(unit) { + var data = { + name: property + ' ' + type + '(' + unit + ')', + property: property, + valueType : type, + unit : unit, + parentStyle: extend({}, parent_styles[property] || {}), + from: extend({}, additional_styles[property] || {}), + to: {} + }; + + data.from[property] = _values[unit][0]; + data.to[property] = _values[unit][1]; + data.flags = _values[unit][2] || {}; + + tests.push(data); + }); + }); + } + + return tests; +} + +root.getPropertyTests = function() { + return assemble(properties); +}; + +root.getMissingPropertyTests = function() { + return assemble(missing_properties); +}; + +root.getUnspecifiedPropertyTests = function() { + return assemble(unspecified_properties); +}; + +root.getFontSizeRelativePropertyTests = function() { + var accepted = {}; + + for (var key in properties) { + if (!Object.prototype.hasOwnProperty.call(properties, key) || key === "font-size") { + continue; + } + + if (properties[key].indexOf('length') > -1) { + accepted[key] = ['length-em']; + } + } + + return assemble(accepted); +}; + +root.filterPropertyTests = function(tests, names) { + var allowed = {}; + var accepted = []; + + if (typeof names === "string") { + names = [names]; + } + + if (!(names instanceof RegExp)) { + names.forEach(function(name) { + allowed[name] = true; + }); + } + + tests.forEach(function(test) { + if (names instanceof RegExp) { + if (!test.name.match(names)) { + return; + } + } else if (!allowed[test.name]) { + return; + } + + accepted.push(test); + }); + + return accepted; +}; + +})(window); diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-h-50%.png b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50%.png Binary files differnew file mode 100644 index 0000000000..cf2eea6b43 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50%.png diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-h-50px.png b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50px.png Binary files differnew file mode 100644 index 0000000000..9f46583665 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50px.png diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-v-100px.png b/testing/web-platform/tests/css/css-transitions/support/ruler-v-100px.png Binary files differnew file mode 100644 index 0000000000..a837eca222 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/ruler-v-100px.png diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-v-50px.png b/testing/web-platform/tests/css/css-transitions/support/ruler-v-50px.png Binary files differnew file mode 100644 index 0000000000..8414102802 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/ruler-v-50px.png diff --git a/testing/web-platform/tests/css/css-transitions/support/runParallelAsyncHarness.js b/testing/web-platform/tests/css/css-transitions/support/runParallelAsyncHarness.js new file mode 100644 index 0000000000..de9b783790 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/runParallelAsyncHarness.js @@ -0,0 +1,148 @@ +(function(root){ +'use strict'; +// testharness doesn't know about async test queues, +// so this wrapper takes care of that + +/* USAGE: + runParallelAsyncHarness({ + // list of data to test, must be array of objects. + // each object must contain a "name" property to describe the test + // besides name, the object can contain whatever data you need + tests: [ + {name: "name of test 1", custom: "data"}, + {name: "name of test 2", custom: "data"}, + // ... + ], + + // number of tests (tests, not test-cases!) to run concurrently + testsPerSlice: 100, + + // time in milliseconds a test-run takes + duration: 1000, + + // test-cases to run for for the test - there must be at least one + // each case creates its separate async_test() instance + cases: { + // test case named "test1" + test1: { + // run as a async_test.step() this callback contains your primary assertions + start: function(testCaseKey, data, options){}, + // run as a async_test.step() this callback contains assertions to be run + // when the test ended, immediately before teardown + done: function(testCaseKey, data, options){} + }, + // ... + } + + // all callbacks are optional: + + // invoked for individual test before it starts so you can setup the environment + // like DOM, CSS, adding event listeners and such + setup: function(data, options){}, + + // invoked after a test ended, so you can clean up the environment + // like DOM, CSS, removing event listeners and such + teardown: function(data, options){}, + + // invoked before a batch of tests ("slice") are run concurrently + // tests is an array of test data objects + sliceStart: function(options, tests) + + // invoked after a batch of tests ("slice") were run concurrently + // tests is an array of test data objects + sliceDone: function(options, tests) + + // invoked once all tests are done + done: function(options){} + }) +*/ +root.runParallelAsyncHarness = function(options) { + if (!options.cases) { + throw new Error("Options don't contain test cases!"); + } + + var noop = function(){}; + + // add a 100ms buffer to the test timeout, just in case + var duration = Math.ceil(options.duration + 100); + + // names of individual tests + var cases = Object.keys(options.cases); + + // run tests in a batch of slices + // primarily not to overload weak devices (tablets, phones, …) + // with too many tests running simultaneously + var iteration = -1; + var testPerSlice = options.testsPerSlice || 100; + var slices = Math.ceil(options.tests.length / testPerSlice); + + // initialize all async test cases + // Note: satisfying testharness.js needs to know all async tests before load-event + options.tests.forEach(function(data, index) { + data.cases = {}; + cases.forEach(function(name) { + data.cases[name] = async_test(data.name + " / " + name); + }); + }); + + function runLoop() { + iteration++; + if (iteration >= slices) { + // no more slice, we're done + (options.done || noop)(options); + return; + } + + // grab a slice of testss and initialize them + var offset = iteration * testPerSlice; + var tests = options.tests.slice(offset, offset + testPerSlice); + tests.forEach(function(data) { + (options.setup || noop)(data, options); + + }); + + // kick off the current slice of tests + (options.sliceStart || noop)(options, tests); + + // perform individual "start" test-case + tests.forEach(function(data) { + cases.forEach(function(name) { + data.cases[name].step(function() { + (options.cases[name].start || noop)(data.cases[name], data, options); + }); + }); + }); + + // conclude slice (possibly abort) + var concludeSlice = function() { + tests.forEach(function(data) { + // perform individual "done" test-case + cases.forEach(function(name) { + data.cases[name].step(function() { + (options.cases[name].done || noop)(data.cases[name], data, options); + }); + }); + // clean up after individual test + (options.teardown || noop)(data, options); + // tell harness we're done with individual test-cases + cases.forEach(function(name) { + data.cases[name].done(); + }); + }); + + // finish the test for current slice of tests + (options.sliceDone || noop)(options, tests); + + // next test please, give the browser 50ms to do catch its breath + setTimeout(runLoop, 50); + } + + // wait on RAF before cleanup to make sure all queued event handlers have run + setTimeout(function() {requestAnimationFrame(concludeSlice)},duration); + } + + // allow DOMContentLoaded before actually doing something + setTimeout(runLoop, 100); +}; + +})(window); diff --git a/testing/web-platform/tests/css/css-transitions/support/square-purple.png b/testing/web-platform/tests/css/css-transitions/support/square-purple.png Binary files differnew file mode 100644 index 0000000000..0f522d7872 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/square-purple.png diff --git a/testing/web-platform/tests/css/css-transitions/support/square-teal.png b/testing/web-platform/tests/css/css-transitions/support/square-teal.png Binary files differnew file mode 100644 index 0000000000..e567f51b91 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/square-teal.png diff --git a/testing/web-platform/tests/css/css-transitions/support/square-white.png b/testing/web-platform/tests/css/css-transitions/support/square-white.png Binary files differnew file mode 100644 index 0000000000..5853cbb238 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/square-white.png diff --git a/testing/web-platform/tests/css/css-transitions/support/support/README b/testing/web-platform/tests/css/css-transitions/support/support/README new file mode 100644 index 0000000000..ea8cb9ef35 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/support/README @@ -0,0 +1,4 @@ +The swatch-green.png file in this directory is really a RED swatch, +and the swatch-red.png file is really a green swatch. + +This directory is used to test relative URIs.
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-transitions/support/support/swatch-green.png b/testing/web-platform/tests/css/css-transitions/support/support/swatch-green.png Binary files differnew file mode 100644 index 0000000000..1caf25c992 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/support/swatch-green.png diff --git a/testing/web-platform/tests/css/css-transitions/support/support/swatch-red.png b/testing/web-platform/tests/css/css-transitions/support/support/swatch-red.png Binary files differnew file mode 100644 index 0000000000..0aa79b0c86 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/support/swatch-red.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-blue.png b/testing/web-platform/tests/css/css-transitions/support/swatch-blue.png Binary files differnew file mode 100644 index 0000000000..bf2759634d --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-blue.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-green.png b/testing/web-platform/tests/css/css-transitions/support/swatch-green.png Binary files differnew file mode 100644 index 0000000000..0aa79b0c86 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-green.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-lime.png b/testing/web-platform/tests/css/css-transitions/support/swatch-lime.png Binary files differnew file mode 100644 index 0000000000..55fd7fdaed --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-lime.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-orange.png b/testing/web-platform/tests/css/css-transitions/support/swatch-orange.png Binary files differnew file mode 100644 index 0000000000..d3cd498b52 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-orange.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-red.png b/testing/web-platform/tests/css/css-transitions/support/swatch-red.png Binary files differnew file mode 100644 index 0000000000..1caf25c992 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-red.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-teal.png b/testing/web-platform/tests/css/css-transitions/support/swatch-teal.png Binary files differnew file mode 100644 index 0000000000..0293ce89de --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-teal.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-white.png b/testing/web-platform/tests/css/css-transitions/support/swatch-white.png Binary files differnew file mode 100644 index 0000000000..1a7d4323d7 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-white.png diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-yellow.png b/testing/web-platform/tests/css/css-transitions/support/swatch-yellow.png Binary files differnew file mode 100644 index 0000000000..1591aa0e2e --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/swatch-yellow.png diff --git a/testing/web-platform/tests/css/css-transitions/support/test-bl.png b/testing/web-platform/tests/css/css-transitions/support/test-bl.png Binary files differnew file mode 100644 index 0000000000..904e24e996 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/test-bl.png diff --git a/testing/web-platform/tests/css/css-transitions/support/test-br.png b/testing/web-platform/tests/css/css-transitions/support/test-br.png Binary files differnew file mode 100644 index 0000000000..f413ff5c1a --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/test-br.png diff --git a/testing/web-platform/tests/css/css-transitions/support/test-inner-half-size.png b/testing/web-platform/tests/css/css-transitions/support/test-inner-half-size.png Binary files differnew file mode 100644 index 0000000000..e473bf80ef --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/test-inner-half-size.png diff --git a/testing/web-platform/tests/css/css-transitions/support/test-outer.png b/testing/web-platform/tests/css/css-transitions/support/test-outer.png Binary files differnew file mode 100644 index 0000000000..82eeace7fc --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/test-outer.png diff --git a/testing/web-platform/tests/css/css-transitions/support/test-tl.png b/testing/web-platform/tests/css/css-transitions/support/test-tl.png Binary files differnew file mode 100644 index 0000000000..f6ac0ef7e8 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/test-tl.png diff --git a/testing/web-platform/tests/css/css-transitions/support/test-tr.png b/testing/web-platform/tests/css/css-transitions/support/test-tr.png Binary files differnew file mode 100644 index 0000000000..59843ae54b --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/test-tr.png diff --git a/testing/web-platform/tests/css/css-transitions/support/two.gif b/testing/web-platform/tests/css/css-transitions/support/two.gif Binary files differnew file mode 100644 index 0000000000..01435c8020 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/two.gif diff --git a/testing/web-platform/tests/css/css-transitions/support/vendorPrefix.js b/testing/web-platform/tests/css/css-transitions/support/vendorPrefix.js new file mode 100644 index 0000000000..1e7eed0481 --- /dev/null +++ b/testing/web-platform/tests/css/css-transitions/support/vendorPrefix.js @@ -0,0 +1,86 @@ +// +// Vendor-Prefix Helper Functions For Testing CSS +// + +(function(root) { +'use strict'; + +var prefixCache = {}; + +// convert "foo-bar" to "fooBar" +function camelCase(str) { + return str.replace(/\-(\w)/g, function(match, letter){ + return letter.toUpperCase(); + }); +} + +// vendor-prefix a css property +root.addVendorPrefix = function (name) { + var prefix = getVendorPrefix(name); + if (prefix === false) { + // property unknown to browser + return name; + } + + return prefix + name; +}; + +// vendor-prefix a css property value +root.addValueVendorPrefix = function (property, value) { + var prefix = getValueVendorPrefix(property, value); + if (prefix === false) { + // property unknown to browser + return name; + } + + return prefix + value; +}; + +// identify vendor-prefix for css property +root.getVendorPrefix = function(name) { + if (prefixCache[name] !== undefined) { + return prefixCache[name]; + } + + var elem = document.createElement("div"); + name = camelCase(name); + + if (name in elem.style) { + return prefixCache[name] = ""; + } + + var prefixes = ["Webkit", "Moz", "O", "ms"]; + var styles = ["-webkit-", "-moz-", "-o-", "-ms-"]; + var _name = name.substring(0, 1).toUpperCase() + name.substring(1); + + for (var i = 0, length = prefixes.length; i < length; i++) { + if (prefixes[i] + _name in elem.style) { + return prefixCache[name] = styles[i]; + } + } + + return prefixCache[name] = name in elem.style ? "" : false; +}; + +// identify vendor-prefix for css property value +root.getValueVendorPrefix = function(property, value) { + var elem = document.createElement("div"); + // note: webkit needs the element to be attached to the dom + document.body.appendChild(elem); + var styles = ["-webkit-", "-moz-", "-o-", "-ms-", ""]; + var _property = getVendorPrefix(property) + property; + for (var i=0, length = styles.length; i < length; i++) { + var _value = styles[i] + value; + elem.setAttribute('style', _property + ": " + _value); + var _computed = computedStyle(elem, _property); + if (_computed && _computed !== 'none') { + document.body.removeChild(elem); + return styles[i]; + } + } + document.body.removeChild(elem); + return false; +}; + + +})(window); |