| Index: third_party/WebKit/LayoutTests/animations/svg-attribute-interpolation/resources/interpolation-test.js
|
| diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-interpolation/resources/interpolation-test.js b/third_party/WebKit/LayoutTests/animations/svg-attribute-interpolation/resources/interpolation-test.js
|
| index 2e094ebdfc648140e366d87a7abce110a7d5a3c6..8cdfa8287feedcd95fb17fc634a0d2a9594315e3 100644
|
| --- a/third_party/WebKit/LayoutTests/animations/svg-attribute-interpolation/resources/interpolation-test.js
|
| +++ b/third_party/WebKit/LayoutTests/animations/svg-attribute-interpolation/resources/interpolation-test.js
|
| @@ -1,68 +1,23 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| +/* Copyright 2015 The Chromium Authors. All rights reserved.
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + *
|
| + * Exported function:
|
| + * - assertAttributeInterpolation({property, from, to}, [{at: fraction, is: value}])
|
| + * Constructs a test case for each fraction that asserts the expected value
|
| + * equals the value produced by interpolation between from and to using
|
| + * SMIL and Web Animations.
|
| +*/
|
| 'use strict';
|
| -(function() {
|
| - var testCount = 0;
|
| - var animationEventCount = 0;
|
| -
|
| - var durationSeconds = 0.001;
|
| - var iterationCount = 0.5;
|
| - var delaySeconds = 0;
|
| - var fragment = document.createDocumentFragment();
|
| - var fragmentAttachedListeners = [];
|
| - var style = document.createElement('style');
|
| - fragment.appendChild(style);
|
| -
|
| - var smilTestsDiv = document.createElement('div');
|
| - smilTestsDiv.id = 'smil-tests';
|
| - smilTestsDiv.textContent = 'SVG SMIL:';
|
| - fragment.appendChild(smilTestsDiv);
|
| -
|
| - var waTestsDiv = document.createElement('div');
|
| - waTestsDiv.id = 'web-animations-tests';
|
| - waTestsDiv.textContent = 'Web Animations API:';
|
| - fragment.appendChild(waTestsDiv);
|
| -
|
| - var updateScheduled = false;
|
| - function maybeScheduleUpdate() {
|
| - if (updateScheduled) {
|
| - return;
|
| - }
|
| - updateScheduled = true;
|
| - setTimeout(function() {
|
| - updateScheduled = false;
|
| - document.body.appendChild(fragment);
|
| - requestAnimationFrame(function () {
|
| - fragmentAttachedListeners.forEach(function(listener) {listener();});
|
| - });
|
| - }, 0);
|
| - }
|
| +(() => {
|
| + var interpolationTests = [];
|
|
|
| - function smilResults() {
|
| - var result = '\nSVG SMIL:\n';
|
| - var targets = document.querySelectorAll('.target.smil');
|
| - for (var i = 0; i < targets.length; i++) {
|
| - result += targets[i].getResultString() + '\n';
|
| + function createElement(tagName, container) {
|
| + var element = document.createElement(tagName);
|
| + if (container) {
|
| + container.appendChild(element);
|
| }
|
| - return result;
|
| - }
|
| -
|
| - function waResults() {
|
| - var result = '\nWeb Animations API:\n';
|
| - var targets = document.querySelectorAll('.target.web-animations');
|
| - for (var i = 0; i < targets.length; i++) {
|
| - result += targets[i].getResultString() + '\n';
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - function dumpResults() {
|
| - var results = document.createElement('pre');
|
| - results.id = 'results';
|
| - results.textContent = smilResults() + waResults();
|
| - document.body.appendChild(results);
|
| + return element;
|
| }
|
|
|
| // Constructs a timing function which produces 'y' at x = 0.5
|
| @@ -83,53 +38,10 @@
|
| return 'cubic-bezier(0, ' + b + ', 1, ' + b + ')';
|
| }
|
|
|
| - function createTestContainer(description, className) {
|
| - var testContainer = document.createElement('div');
|
| - testContainer.setAttribute('description', description);
|
| - testContainer.classList.add('test');
|
| - if (className) {
|
| - testContainer.classList.add(className);
|
| - }
|
| - return testContainer;
|
| - }
|
| -
|
| - function convertPropertyToCamelCase(property) {
|
| - return property.replace(/^-/, '').replace(/-\w/g, function(m) {return m[1].toUpperCase();});
|
| - }
|
| -
|
| - function describeSMILTest(params) {
|
| - return '<animate /> ' + convertPropertyToCamelCase(params.property) + ': from [' + params.from + '] to [' + params.to + ']';
|
| - }
|
| -
|
| - function describeWATest(params) {
|
| - return 'element.animate() ' + convertPropertyToCamelCase(params.property) + ': from [' + params.from + '] to [' + params.to + ']';
|
| - }
|
| -
|
| - var nextTestId = 0;
|
| function assertAttributeInterpolation(params, expectations) {
|
| - var testId = 'test-' + ++nextTestId;
|
| - var nextCaseId = 0;
|
| -
|
| - var smilTestContainer = createTestContainer(describeSMILTest(params), testId);
|
| - smilTestsDiv.appendChild(smilTestContainer);
|
| - expectations.forEach(function(expectation) {
|
| - if (expectation.at < 0 || expectation.at > 1)
|
| - return;
|
| - smilTestContainer.appendChild(makeInterpolationTest(
|
| - 'smil', expectation.at, testId, 'case-' + ++nextCaseId, params, expectation.is));
|
| - });
|
| -
|
| - var waTestContainer = createTestContainer(describeWATest(params), testId);
|
| - waTestsDiv.appendChild(waTestContainer);
|
| - expectations.forEach(function(expectation) {
|
| - waTestContainer.appendChild(makeInterpolationTest(
|
| - 'web-animations', expectation.at, testId, 'case-' + ++nextCaseId, params, expectation.is));
|
| - });
|
| -
|
| - maybeScheduleUpdate();
|
| + interpolationTests.push({params, expectations});
|
| }
|
|
|
| -
|
| function roundNumbers(value) {
|
| return value.
|
| // Round numbers to two decimal places.
|
| @@ -150,8 +62,8 @@
|
| replace(/\s+/g, ' ');
|
| }
|
|
|
| - function createTargetContainer(id) {
|
| - var targetContainer = document.createElement('div');
|
| + function createTarget(container) {
|
| + var targetContainer = createElement('div');
|
| var template = document.querySelector('#target-template');
|
| if (template) {
|
| targetContainer.appendChild(template.content.cloneNode(true));
|
| @@ -165,21 +77,20 @@
|
| // If the template contains just one element, use that rather than a wrapper div.
|
| if (targetContainer.children.length == 1 && targetContainer.childNodes.length == 1) {
|
| targetContainer = targetContainer.firstChild;
|
| - targetContainer.remove();
|
| }
|
| + container.appendChild(targetContainer);
|
| }
|
| var target = targetContainer.querySelector('.target') || targetContainer;
|
| - target.classList.add('target');
|
| - target.classList.add(id);
|
| - return targetContainer;
|
| + target.container = targetContainer;
|
| + return target;
|
| }
|
|
|
| + var anchor = createElement('a');
|
| function sanitizeUrls(value) {
|
| var matches = value.match(/url\([^\)]*\)/g);
|
| if (matches !== null) {
|
| for (var i = 0; i < matches.length; ++i) {
|
| var url = /url\(([^\)]*)\)/g.exec(matches[i])[1];
|
| - var anchor = document.createElement('a');
|
| anchor.href = url;
|
| anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.lastIndexOf('/'));
|
| value = value.replace(matches[i], 'url(' + anchor.href + ')');
|
| @@ -254,7 +165,7 @@
|
| }
|
|
|
| function getAttributeValue(element, attributeName) {
|
| - if (animatedNumberOptionalNumberAttributes.indexOf(attributeName) !== -1)
|
| + if (animatedNumberOptionalNumberAttributes.includes(attributeName))
|
| return getAttributeValue(element, attributeName + 'X') + ', ' + getAttributeValue(element, attributeName + 'Y');
|
|
|
| // The attribute 'class' is exposed in IDL as 'className'
|
| @@ -286,7 +197,7 @@
|
| if (attributeName === 'preserveAlpha')
|
| return 'false';
|
|
|
| - console.log('Unknown attribute, cannot get ' + element.className.baseVal + ' ' + attributeName);
|
| + console.error('Unknown attribute, cannot get ' + attributeName);
|
| return null;
|
| }
|
|
|
| @@ -306,7 +217,7 @@
|
| result = serializeSVGTransformList(result);
|
|
|
| if (typeof result !== 'string' && typeof result !== 'number' && typeof result !== 'boolean') {
|
| - console.log('Attribute value has unexpected type: ' + result);
|
| + console.error('Attribute value has unexpected type: ' + result);
|
| }
|
|
|
| return String(result);
|
| @@ -319,15 +230,10 @@
|
| && (attributeName !== 'in' || !element['in1'])
|
| && (attributeName !== 'orient' || !element['orientType'])
|
| && (animatedNumberOptionalNumberAttributes.indexOf(attributeName) === -1 || !element[attributeName + 'X'])) {
|
| - console.log('Unknown attribute, cannot set ' + element.className.baseVal + ' ' + attributeName);
|
| + console.error('Unknown attribute, cannot set ' + attributeName);
|
| return;
|
| }
|
|
|
| - if (attributeName === 'class') {
|
| - // Preserve the existing classes as we use them to select elements.
|
| - expectation = element['className'].baseVal + ' ' + expectation;
|
| - }
|
| -
|
| if (attributeName.toLowerCase().indexOf('transform') === -1) {
|
| var setElement = document.createElementNS(svgNamespace, 'set');
|
| setElement.setAttribute('attributeName', namespacedAttributeName(attributeName));
|
| @@ -339,196 +245,156 @@
|
| }
|
| }
|
|
|
| - function makeKeyframes(target, attributeName, params) {
|
| - // Replace 'transform' with 'svgTransform', etc. This avoids collisions with CSS properties or the Web Animations API (offset).
|
| - attributeName = 'svg' + attributeName[0].toUpperCase() + attributeName.slice(1);
|
| + function createAnimateElement(attributeName, from, to)
|
| + {
|
| + var animateElement;
|
| + if (attributeName.toLowerCase().includes('transform')) {
|
| + from = from.split(')');
|
| + to = to.split(')');
|
| + // Discard empty string at end.
|
| + from.pop();
|
| + to.pop();
|
| +
|
| + // SMIL requires separate animateTransform elements for each transform in the list.
|
| + if (from.length !== 1 || to.length !== 1) {
|
| + return null;
|
| + }
|
|
|
| - var keyframes = [{}, {}];
|
| - if (attributeName === 'svgClass') {
|
| - // Preserve the existing classes as we use them to select elements.
|
| - keyframes[0][attributeName] = target['className'].baseVal + ' ' + params.from;
|
| - keyframes[1][attributeName] = target['className'].baseVal + ' ' + params.to;
|
| - } else {
|
| - keyframes[0][attributeName] = params.from;
|
| - keyframes[1][attributeName] = params.to;
|
| - }
|
| - return keyframes;
|
| - }
|
| + from = from[0].split('(');
|
| + to = to[0].split('(');
|
| + if (from[0].trim() !== to[0].trim()) {
|
| + return null;
|
| + }
|
|
|
| - function appendAnimate(target, attributeName, from, to)
|
| - {
|
| - var animateElement = document.createElementNS(svgNamespace, 'animate');
|
| - animateElement.setAttribute('attributeName', namespacedAttributeName(attributeName));
|
| - animateElement.setAttribute('attributeType', 'XML');
|
| - if (attributeName === 'class') {
|
| - // Preserve the existing classes as we use them to select elements.
|
| - animateElement.setAttribute('from', target['className'].baseVal + ' ' + from);
|
| - animateElement.setAttribute('to', target['className'].baseVal + ' ' + to);
|
| + animateElement = document.createElementNS(svgNamespace, 'animateTransform');
|
| + animateElement.setAttribute('type', from[0].trim());
|
| + animateElement.setAttribute('from', from[1]);
|
| + animateElement.setAttribute('to', to[1]);
|
| } else {
|
| + animateElement = document.createElementNS(svgNamespace, 'animate');
|
| animateElement.setAttribute('from', from);
|
| animateElement.setAttribute('to', to);
|
| }
|
| - animateElement.setAttribute('begin', '0');
|
| - animateElement.setAttribute('dur', '1');
|
| - animateElement.setAttribute('fill', 'freeze');
|
| - target.appendChild(animateElement);
|
| - }
|
|
|
| - function appendAnimateTransform(target, attributeName, from, to)
|
| - {
|
| - var animateElement = document.createElementNS(svgNamespace, 'animate');
|
| animateElement.setAttribute('attributeName', namespacedAttributeName(attributeName));
|
| animateElement.setAttribute('attributeType', 'XML');
|
| - if (attributeName === 'class') {
|
| - // Preserve the existing classes as we use them to select elements.
|
| - animateElement.setAttribute('from', target['className'].baseVal + ' ' + from);
|
| - animateElement.setAttribute('to', target['className'].baseVal + ' ' + to);
|
| - } else {
|
| - animateElement.setAttribute('from', from);
|
| - animateElement.setAttribute('to', to);
|
| - }
|
| animateElement.setAttribute('begin', '0');
|
| animateElement.setAttribute('dur', '1');
|
| animateElement.setAttribute('fill', 'freeze');
|
| - target.appendChild(animateElement);
|
| - }
|
| + return animateElement;
|
| + }
|
| +
|
| + function createTestTarget(method, description, container, params, expectation) {
|
| + var target = createTarget(container);
|
| + var expected = createTarget(container);
|
| + setAttributeValue(expected, params.property, expectation.is);
|
| +
|
| + target.interpolate = function() {
|
| + switch (method) {
|
| + case 'SMIL':
|
| + var animateElement = createAnimateElement(params.property, params.from, params.to);
|
| + if (animateElement) {
|
| + target.appendChild(animateElement);
|
| + target.container.pauseAnimations();
|
| + target.container.setCurrentTime(expectation.at);
|
| + } else {
|
| + console.warn(`Unable to test SMIL from ${params.from} to ${params.to}`);
|
| + target.container.remove();
|
| + target.measure = function() {};
|
| + }
|
| + break;
|
| + case 'Web Animations':
|
| + // Replace 'transform' with 'svgTransform', etc. This avoids collisions with CSS properties or the Web Animations API (offset).
|
| + var prefixedProperty = 'svg' + params.property[0].toUpperCase() + params.property.slice(1);
|
| + target.animate([
|
| + {[prefixedProperty]: params.from},
|
| + {[prefixedProperty]: params.to},
|
| + ], {
|
| + fill: 'forwards',
|
| + duration: 1,
|
| + easing: createEasing(expectation.at),
|
| + delay: -0.5,
|
| + iterations: 0.5,
|
| + });
|
| + break;
|
| + default:
|
| + console.error('Unknown test method: ' + method);
|
| + }
|
| + };
|
|
|
| - // Append animateTransform elements to parents of target.
|
| - function appendAnimateTransform(target, attributeName, from, to)
|
| - {
|
| - var currentElement = target;
|
| - var parents = [];
|
| - from = from.split(')');
|
| - to = to.split(')');
|
| - // Discard empty string at end.
|
| - from.pop();
|
| - to.pop();
|
| -
|
| - // SMIL requires separate animateTransform elements for each transform in the list.
|
| - if (from.length !== 1 || to.length !== 1)
|
| - return;
|
| + target.measure = function() {
|
| + test(function() {
|
| + assert_equals(
|
| + normalizeValue(getAttributeValue(target, params.property)),
|
| + normalizeValue(getAttributeValue(expected, params.property)));
|
| + }, `${method}: ${description} at (${expectation.at}) is [${expectation.is}]`);
|
| + };
|
|
|
| - from = from[0].split('(');
|
| - to = to[0].split('(');
|
| - if (from[0].trim() !== to[0].trim())
|
| - return;
|
| -
|
| - var animateTransformElement = document.createElementNS(svgNamespace, 'animateTransform');
|
| - animateTransformElement.setAttribute('attributeName', namespacedAttributeName(attributeName));
|
| - animateTransformElement.setAttribute('attributeType', 'XML');
|
| - animateTransformElement.setAttribute('type', from[0].trim());
|
| - animateTransformElement.setAttribute('from', from[1]);
|
| - animateTransformElement.setAttribute('to', to[1]);
|
| - animateTransformElement.setAttribute('begin', '0');
|
| - animateTransformElement.setAttribute('dur', '1');
|
| - animateTransformElement.setAttribute('fill', 'freeze');
|
| - target.appendChild(animateTransformElement);
|
| + return target;
|
| }
|
|
|
| - function makeInterpolationTest(testType, fraction, testId, caseId, params, expectation) {
|
| - var attributeName = convertPropertyToCamelCase(params.property);
|
| + function createTestTargets(interpolationTests, container) {
|
| + var targets = [];
|
| + for (var interpolationTest of interpolationTests) {
|
| + var params = interpolationTest.params;
|
| + var description = `Interpolate attribute <${params.property}> from [${params.from}] to [${params.to}]`;
|
| + var expectations = interpolationTest.expectations;
|
|
|
| - var targetContainer = createTargetContainer(caseId);
|
| - var target = targetContainer.querySelector('.target') || targetContainer;
|
| - target.classList.add(testType);
|
| - var replicaContainer, replica;
|
| - {
|
| - replicaContainer = createTargetContainer(caseId);
|
| - replica = replicaContainer.querySelector('.target') || replicaContainer;
|
| - replica.classList.add('replica');
|
| - setAttributeValue(replica, params.property, expectation);
|
| - }
|
| - target.testType = testType;
|
| - target.getResultString = function() {
|
| - var value = getAttributeValue(this, params.property);
|
| - var result = '';
|
| - var reason = '';
|
| - var property = convertPropertyToCamelCase(params.property);
|
| - {
|
| - var parsedExpectation = getAttributeValue(replica, params.property);
|
| - if (attributeName === 'class') {
|
| - parsedExpectation = parsedExpectation.replace('replica', testType);
|
| + for (var method of ['SMIL', 'Web Animations']) {
|
| + createElement('pre', container).textContent = `${method}: ${description}`;
|
| + var smilContainer = createElement('div', container);
|
| + for (var expectation of expectations) {
|
| + if (method === 'SMIL' && (expectation.at < 0 || expectation.at > 1)) {
|
| + continue;
|
| + }
|
| + targets.push(createTestTarget(method, description, smilContainer, params, expectation));
|
| }
|
| - // console.log('expected ' + parsedExpectation + ', actual ' + value);
|
| - var pass = normalizeValue(value) === normalizeValue(parsedExpectation);
|
| - result = pass ? 'PASS: ' : 'FAIL: ';
|
| - reason = pass ? '' : ', expected [' + expectation + ']' +
|
| - (expectation === parsedExpectation ? '' : ' (parsed as [' + sanitizeUrls(roundNumbers(parsedExpectation)) + '])');
|
| - value = pass ? expectation : sanitizeUrls(value);
|
| }
|
| - return result + property + ' from [' + params.from + '] to ' +
|
| - '[' + params.to + '] was [' + value + ']' +
|
| - ' at ' + fraction + reason;
|
| - };
|
| - var easing = createEasing(fraction);
|
| - testCount++;
|
| - {
|
| - fragmentAttachedListeners.push(function() {
|
| - if (testType === 'smil') {
|
| - if (attributeName.toLowerCase().indexOf('transform') === -1)
|
| - appendAnimate(target, attributeName, params.from, params.to);
|
| - else
|
| - appendAnimateTransform(target, attributeName, params.from, params.to);
|
| -
|
| - targetContainer.pauseAnimations();
|
| - targetContainer.setCurrentTime(fraction);
|
| - } else if (testType === 'web-animations' && target.animate) {
|
| - target.animate(makeKeyframes(target, attributeName, params), {
|
| - fill: 'forwards',
|
| - duration: 1,
|
| - easing: easing,
|
| - delay: -0.5,
|
| - iterations: 0.5,
|
| - });
|
| - }
|
| - animationEnded();
|
| - });
|
| }
|
| - var testFragment = document.createDocumentFragment();
|
| - testFragment.appendChild(targetContainer);
|
| - testFragment.appendChild(replicaContainer);
|
| - testFragment.appendChild(document.createTextNode('\n'));
|
| - return testFragment;
|
| + return targets;
|
| }
|
|
|
| - var finished = false;
|
| - function finishTest() {
|
| - finished = true;
|
| - dumpResults();
|
| - if (window.testRunner) {
|
| - var results = document.querySelector('#results');
|
| - document.documentElement.textContent = '';
|
| - document.documentElement.appendChild(results);
|
| - testRunner.dumpAsText();
|
| -
|
| - testRunner.notifyDone();
|
| - }
|
| - }
|
| + function runTests() {
|
| + return new Promise((resolve) => {
|
| + var container = createElement('div', document.body);
|
| + var targets = createTestTargets(interpolationTests, container);
|
|
|
| - if (window.testRunner) {
|
| - testRunner.waitUntilDone();
|
| - }
|
| + requestAnimationFrame(() => {
|
| + for (var target of targets) {
|
| + target.interpolate();
|
| + }
|
|
|
| - function isLastAnimationEvent() {
|
| - return !finished && animationEventCount === testCount;
|
| - }
|
| + requestAnimationFrame(() => {
|
| + for (var target of targets) {
|
| + target.measure();
|
| + }
|
|
|
| - function animationEnded() {
|
| - animationEventCount++;
|
| - if (!isLastAnimationEvent()) {
|
| - return;
|
| - }
|
| - requestAnimationFrame(finishTest);
|
| + if (window.testRunner) {
|
| + container.style.display = 'none';
|
| + }
|
| +
|
| + resolve();
|
| + });
|
| + });
|
| + });
|
| }
|
|
|
| - if (!window.testRunner) {
|
| - setTimeout(function() {
|
| - if (finished) {
|
| - return;
|
| - }
|
| - finishTest();
|
| - }, 5000);
|
| + function loadScript(url) {
|
| + return new Promise(function(resolve) {
|
| + var script = createElement('script', document.head);
|
| + script.src = url;
|
| + script.onload = resolve;
|
| + });
|
| }
|
|
|
| + loadScript('../../resources/testharness.js').then(() => {
|
| + return loadScript('../../resources/testharnessreport.js');
|
| + }).then(() => {
|
| + var asyncHandle = async_test('This test uses interpolation-test.js.')
|
| + requestAnimationFrame(() => {
|
| + runTests().then(() => asyncHandle.done());
|
| + });
|
| + });
|
| +
|
| window.assertAttributeInterpolation = assertAttributeInterpolation;
|
| })();
|
|
|