Update CSS tests to revision d13905941293af83ea8c3c1750dba652e0423fb0

This commit is contained in:
Ms2ger 2015-10-31 14:35:08 +01:00
parent b492a3e8b1
commit 5450053b02
842 changed files with 42936 additions and 27 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<title>One region in body</title>
<style>
html, body {
margin: 0;
padding: 0;
}
.content {
margin: 10px;
font-family: Ahem;
font-size: 20px;
line-height: 1em;
color: green;
}
</style>
</head>
<body>
<div class="content">
xxxx<br>
xxxx<br>
xxxx<br>
xxxx
</div>
<div class="content">
xxxx<br>
xxxx<br>
xxxx<br>
xxxx
</div>
</body></html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<title>One region in body</title>
<style>
html, body {
margin: 0;
padding: 0;
}
#content {
font-family: Ahem;
font-size: 20px;
line-height: 1em;
color: green;
float: right;
}
</style>
</head>
<body>
<div id="content">
xxxx<br>
xxxx<br>
xxxx<br>
xxxx
</div>
</body></html>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<title>One region in body</title>
<style>
html, body {
margin: 0;
padding: 0;
}
#content {
font-family: Ahem;
font-size: 20px;
line-height: 1em;
color: green;
}
</style>
</head>
<body>
<div id="content">
xxxx<br>
xxxx<br>
xxxx<br>
xxxx
</div>
</body></html>

View file

@ -0,0 +1,29 @@
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-gg-gr.png 20x20
pattern-grg-rgr-grg.png 20x20
pattern-rgr-grg-rgr.png 20x20
pattern-tr.png 15x15
pattern-grg-rrg-rgg.png 15x15

View file

@ -0,0 +1 @@
.a { color: green; }

View file

@ -0,0 +1 @@
.b { color: green; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

View file

@ -0,0 +1 @@
.c { color: red; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -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);

View file

@ -0,0 +1,96 @@
//
// 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!');
}
};
})(window);

View file

@ -0,0 +1 @@
.import { color: green; }

View file

@ -0,0 +1 @@
.import { color: red; }

View file

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<title>iframe containing the meat of the test</title>
<style>
body {
margin: 0;
overflow: hidden;
}
/* green div that should cover the red divs */
#green {
position: absolute;
left: 0;
top: 0;
background-color: green;
width: 100%;
height: 600px;
}
.spacer {
height: 98px;
width: 20px;
}
.item {
background-color: red;
display: block;/* property under test */
/* border to aid understanding of boundaries between items */
border-style: solid;
border-width: 1px;
border-color: red;/* Note: if you're trying to debug this, use a different color here */
}
/* 100px = 10*(1 + 8 + 1) */
@media (min-width: 100px) {
#green {
width: 100px;
height: 100px;/* = 1 + 98 + 1 */
}
.item {
display: table-cell;/* property and value under test */
}
}
</style>
</head>
<body>
<div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
<div class="item"><div class="spacer"></div></div>
</div>
<div id="green"></div>
</body></html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

View file

@ -0,0 +1,866 @@
var ParsingUtils = (function() {
function testInlineStyle(value, expected) {
var div = document.createElement('div');
div.style.setProperty('shape-outside', value);
var actual = div.style.getPropertyValue('shape-outside');
assert_equals(actual, expected);
}
function testComputedStyle(value, expected) {
var div = document.createElement('div');
div.style.setProperty('shape-outside', value);
document.body.appendChild(div);
var style = getComputedStyle(div);
var actual = style.getPropertyValue('shape-outside');
actual = roundResultStr(actual);
document.body.removeChild(div);
// Some of the tests in this suite have either/or expected results
// so this check allows for testing that at least one of them passes.
// Description of the 2 expecteds is below near calcTestValues.
if(Object.prototype.toString.call( expected ) === '[object Array]' && expected.length == 2) {
assert_true(expected[0] == actual || expected[1] == actual)
} else {
assert_equals(actual, typeof expected !== 'undefined' ? expected : value);
}
}
function testShapeMarginInlineStyle(value, expected) {
var div = document.createElement('div');
div.style.setProperty('shape-outside', "border-box inset(10px)");
div.style.setProperty('shape-margin', value);
var actual = div.style.getPropertyValue('shape-margin');
assert_equals(actual, expected);
}
function testShapeMarginComputedStyle(value, expected) {
var outerDiv = document.createElement('div');
outerDiv.style.setProperty('width', '100px');
var innerDiv = document.createElement('div');
innerDiv.style.setProperty('shape-outside', "border-box inset(10px)");
innerDiv.style.setProperty('shape-margin', value);
outerDiv.appendChild(innerDiv);
document.body.appendChild(outerDiv);
var style = getComputedStyle(innerDiv);
var actual = style.getPropertyValue('shape-margin');
assert_not_equals(actual, null);
if(actual.indexOf('calc') == -1 )
actual = roundResultStr(actual);
document.body.removeChild(outerDiv);
// See comment above about multiple expected results
if(Object.prototype.toString.call( expected ) === '[object Array]' && expected.length == 2) {
assert_true(expected[0] == actual || expected[1] == actual)
} else {
assert_equals(actual, !expected ? '0px' : expected);
}
}
function testShapeThresholdInlineStyle(value, expected) {
var div = document.createElement('div');
div.style.setProperty('shape-outside', 'url(someimage.png)');
div.style.setProperty('shape-image-threshold', value);
var actual = div.style.getPropertyValue('shape-image-threshold');
assert_equals(actual, expected);
}
function testShapeThresholdComputedStyle(value, expected) {
var div = document.createElement('div');
div.style.setProperty('shape-outside', 'url(someimage.png)');
div.style.setProperty('shape-image-threshold', value);
document.body.appendChild(div);
var style = getComputedStyle(div);
var actual = style.getPropertyValue('shape-image-threshold');
assert_not_equals(actual, null);
if(actual.indexOf('calc') == -1 )
actual = roundResultStr(actual);
document.body.removeChild(div);
// See comment above about multiple expected results
if(Object.prototype.toString.call( expected ) === '[object Array]' && expected.length == 2) {
assert_true(expected[0] == actual || expected[1] == actual)
} else {
assert_equals(actual, !expected ? '0' : expected);
}
}
// Builds an array of test cases to send to testharness.js where one test case is: [name, actual, expected]
// These test cases will verify results from testInlineStyle() or testComputedStyle()
function buildTestCases(testCases, testType) {
var results = [];
// If test_type isn't specified, test inline style
var type = typeof testType == 'undefined' ? 'invalid': testType;
testCases.forEach(function(test) {
oneTestCase = [];
// name - annotated by type (inline vs. computed)
if ( test.hasOwnProperty('name') ) {
oneTestCase.push(test['name'] +' - '+ type);
} else {
// If test_name isn't specified, use the actual
oneTestCase.push(test['actual'] +' - '+ type);
}
// actual
oneTestCase.push(test['actual'])
// expected
if( type.indexOf('invalid') != -1 ){
oneTestCase.push(null)
} else if( type == 'inline' ) {
oneTestCase.push(test['expected_inline']);
} else if( type == 'computed' ){
oneTestCase.push( convertToPx(test['expected_computed']) );
}
results.push(oneTestCase);
});
return results;
}
function buildPositionTests(shape, valid, type, units) {
var results = new Array();
var convert = type.indexOf('computed') != -1 ? true : false;
if(Object.prototype.toString.call( units ) === '[object Array]') {
units.forEach(function(unit) {
positionTests = buildPositionTests(shape, valid, type, unit);
results = results.concat(positionTests);
});
} else {
if (valid) {
validPositions.forEach(function(test) {
var testCase = [], testName, actual, expected;
// skip if this isn't explicitly testing length units
if( !(type.indexOf('lengthUnit') != -1 && test[0].indexOf("u1") == -1)) {
// actual
actual = shape + '(at ' + setUnit(test[0], false, units) +')';
// expected
// if(convert && shape == 'circle')
// expected = shape + '(at ' + setUnit(test[1], convert, units) +')';
// else if(convert && shape == 'ellipse')
// expected = shape + '(at ' + setUnit(test[1], convert, units) +')';
// else
expected = shape + '(at ' + setUnit(test[1], convert, units) +')';
// name
if (type == 'lengthUnit + inline')
testName = 'test unit (inline): ' + units +' - '+ actual;
else if (type == 'lengthUnit + computed')
testName = 'test unit (computed): ' + units +' - '+ actual;
else
testName = (actual + ' serializes as ' + expected +' - '+ type);
testCase.push(testName)
testCase.push(actual);
testCase.push(expected);
results.push(testCase);
}
});
} else {
invalidPositions.forEach(function(test) {
var testValue = shape + '(at ' + setUnit(test, false, units) +')';
testCase = new Array();
testCase.push(testValue + ' is invalid');
testCase.push(testValue);
testCase.push(null);
results.push(testCase);
});
}
}
return unique(results);
}
function buildRadiiTests(shape, type, units) {
var results = new Array();
var testUnits = typeof units == 'undefined' ? 'px': units;
var convert = type.indexOf('computed') != -1 ? true : false;
if(Object.prototype.toString.call( testUnits ) === '[object Array]') {
testUnits.forEach(function(unit) {
radiiTests = buildRadiiTests(shape, type, unit);
results = results.concat(radiiTests);
});
} else {
var validRadii = shape == 'circle' ? validCircleRadii : validEllipseRadii;
validRadii.forEach(function(test) {
var testCase = [], name, actual, expected;
// skip if this isn't explicitly testing length units
if( !(type.indexOf('lengthUnit') != -1 && test[0].indexOf("u1") == -1) ) {
actual = shape + '(' + setUnit(test[0], false, testUnits) +')';
// name
if (type.indexOf('lengthUnit') != -1) {
name = 'test unit: ' + units +' - '+ actual;
if(type.indexOf('computed') != -1)
name = name + ' - computed';
else
name = name + ' - inline';
}
else
name = actual +' - '+ type;
testCase.push(name);
// actual
testCase.push(actual);
// expected
if(type.indexOf('computed') != -1 && test.length == 3) {
expected = shape + '(' + setUnit(test[2], convert, testUnits) +')';
} else {
expected = shape + '(' + setUnit(test[1], convert, testUnits) +')';
}
testCase.push(expected);
results.push(testCase);
}
});
}
return unique(results);
}
function buildInsetTests(unit1, unit2, type) {
var results = new Array();
var convert = type == 'computed' ? true : false;
if(Object.prototype.toString.call( unit1 ) === '[object Array]') {
unit1.forEach(function(unit) {
insetTests = buildInsetTests(unit, unit2, type);
results = results.concat(insetTests);
});
} else {
validInsets.forEach(function(test) {
var testCase = [], name, actual, expected;
name = setUnit(test[0], false, unit1, unit2) +' - '+ type;
actual = 'inset(' + setUnit(test[1], convert, unit1, unit2) +')';
expected = actual;
testCase.push(name);
testCase.push(actual);
testCase.push(expected);
results.push(testCase);
});
}
return unique(results);
}
function buildPolygonTests(unitSet, type) {
var results = new Array();
var convert = type == 'computed' ? true : false;
unitSet.forEach(function(set) {
validPolygons.forEach(function(test) {
var testCase = [];
// name
testCase.push(setUnit(test[0], false, set[0], set[1], set[2]) +' - '+ type);
// actual
testCase.push('polygon(' + setUnit(test[1], false, set[0], set[1], set[2]) +')');
// expected
testCase.push('polygon(' + setUnit(test[1], convert, set[0], set[1], set[2]) +')');
results.push(testCase);
});
});
return unique(results);
}
function buildCalcTests(testCases, type) {
var results = new Array();
testCases.forEach(function(test){
var testCase = [];
if(type == 'computed') {
testCase.push(test[0] + ' - computed style');
testCase.push(test[0]);
testCase.push(test[2]);
}
else {
testCase.push(test[0] + ' - inline style');
testCase.push(test[0]);
testCase.push(test[1]);
}
testCase.push(type);
results.push(testCase)
});
return unique(results);
}
function unique(tests) {
var list = tests.concat();
for(var i = 0; i< list.length; ++i) {
for(var j = i+1; j < list.length; ++j) {
if(list[i][0] === list[j][0])
list.splice(j--, 1);
}
}
return list;
}
function setUnit(str, convert, unit1, unit2, unit3) {
var retStr = str;
if(typeof unit1 !== 'undefined') {
retStr = retStr.replace(new RegExp('u1', 'g'), unit1);
}
if(typeof unit2 !== 'undefined') {
retStr = retStr.replace(new RegExp("u2", 'g'), unit2);
}
if(typeof unit3 !== 'undefined') {
retStr = retStr.replace(new RegExp("u3", 'g'), unit3);
}
retStr = convert ? convertToPx(retStr) : retStr;
return retStr;
}
function convertToPx(origValue) {
var valuesToConvert = origValue.match(/[0-9]+(\.[0-9]+)?([a-z]{2,4}|%)/g);
if(!valuesToConvert)
return origValue;
var retStr = origValue;
for(var i = 0; i < valuesToConvert.length; i++) {
var unit = valuesToConvert[i].match(/[a-z]{2,4}|%/).toString();
var numberStr = valuesToConvert[i].match(/[0-9]+(\.[0-9]+)?/)[0];
var number = parseFloat(numberStr);
var convertedUnit = 'px';
if( typeof number !== 'NaN' )
{
if (unit == 'in') {
number = (96 * number);
} else if (unit == 'cm') {
number = (37.795275591 * number);
} else if (unit == 'mm') {
number = (3.779527559 * number);
} else if (unit == 'pt') {
number = (1.333333333333 * number);
} else if (unit == 'pc') {
number = (16 * number);
} else if (unit == 'em') {
number = (16 * number);
} else if (unit == 'ex') {
number = (7.1796875 * number);
} else if (unit == 'ch') {
number = (8 * number);
} else if (unit == 'rem') {
number = (16 * number);
} else if (unit == 'vw') {
number = ((.01 * window.innerWidth) * number);
} else if (unit == 'vh') {
number = ((.01 * window.innerHeight) * number);
} else if (unit == 'vmin') {
number = Math.min( (.01 * window.innerWidth), (.01 * window.innerHeight) ) * number;
} else if (unit == 'vmax') {
number = Math.max( (.01 * window.innerWidth), (.01 * window.innerHeight) ) * number;
}
else {
convertedUnit = unit;
}
number = Math.round(number * 1000) / 1000;
var find = valuesToConvert[i];
var replace = number.toString() + convertedUnit;
retStr = retStr.replace(valuesToConvert[i], number.toString() + convertedUnit);
}
}
return retStr.replace(',,', ',');
}
function roundResultStr(str) {
if(Object.prototype.toString.call( str ) !== '[object String]')
return str;
var numbersToRound = str.match(/[0-9]+\.[0-9]+/g);
if(!numbersToRound)
return str;
var retStr = str;
for(var i = 0; i < numbersToRound.length; i++) {
num = parseFloat(numbersToRound[i]);
if( !isNaN(num) ) {
roundedNum = Math.round(num*1000)/1000;
retStr = retStr.replace(numbersToRound[i].toString(), roundedNum.toString());
}
}
return retStr;
}
function generateInsetRoundCases(units, testType) {
var convert = testType.indexOf('computed') != -1 ? true : false;
var testUnit = units;
var sizes = [
'10' + units,
'20' + units,
'30' + units,
'40' + units
];
function insetRound(value) {
return 'inset(10' +testUnit+ ' round ' + value + ')';
}
function serializedInsetRound(lhsValues, rhsValues, convert) {
var retStr = '';
if(!rhsValues)
retStr = 'inset(10' +testUnit+ ' round ' + lhsValues +')';
else
retStr = 'inset(10' +testUnit+ ' round ' + lhsValues +' / '+ rhsValues +')';
if(convert)
return convertToPx(retStr);
return retStr;
}
var results = [], left, lhs, right, rhs;
for (left = 1; left <= 4; left++) {
lhs = sizes.slice(0, left).join(' ');
results.push([insetRound(lhs) +' - '+ testType, insetRound(lhs), serializedInsetRound(lhs, null, convert)]);
for (right = 1; right <= 4; right++) {
rhs = sizes.slice(0, right).join(' ');
if(lhs == rhs)
results.push([insetRound(lhs + ' / ' + rhs) +' - '+ testType, insetRound(lhs + ' / ' + rhs), serializedInsetRound(lhs, null, convert)]);
else
results.push([insetRound(lhs + ' / ' + rhs) +' - '+ testType, insetRound(lhs + ' / ' + rhs), serializedInsetRound(lhs, rhs, convert)]);
}
}
return results;
}
var validUnits = [
"cm","mm","in","pt","pc", // Absolute length units (omitting px b/c we default to that in all tests)
"em","ex","ch","rem", // Font relative length units
"vw","vh","vmin","vmax" // Viewport percentage units
]
/// [actual, expected]
var validPositions = [
/// [ percent ], [ length ], [ percent | percent ], [ percent | length ], [ length | percent ], [ length | length ]
["50%", "50% 50%"],
["50u1", "50u1 50%"],
["50% 50%", "50% 50%"],
["50% 50u1", "50% 50u1"],
["50u1 50%", "50u1 50%"],
["50u1 50u1", "50u1 50u1"],
///// [ keyword ], [ keyword keyword ] x 5 keywords
["left", "0% 50%"],
["top", "50% 0%"],
["right", "100% 50%"],
["bottom", "50% 100%"],
["center", "50% 50%"],
["left top", "0% 0%"],
["left bottom", "0% 100%"],
["left center", "0% 50%"],
["top left", "0% 0%"],
["top right", "100% 0%"],
["top center", "50% 0%"],
["right top", "100% 0%"],
["right bottom", "100% 100%"],
["right center", "100% 50%"],
["bottom left", "0% 100%"],
["bottom right", "100% 100%"],
["bottom center", "50% 100%"],
["center top", "50% 0%"],
["center left", "0% 50%"],
["center right", "100% 50%"],
["center bottom", "50% 100%"],
["center center", "50% 50%"],
////// [ keyword | percent ], [ keyword | length ], [ percent | keyword ], [ length | keyword ] x 5 keywords
["left 50%", "0% 50%"],
["left 50u1", "0% 50u1"],
["50% top", "50% 0%"],
["50u1 top", "50u1 0%"],
["right 80%", "100% 80%"],
["right 80u1", "100% 80u1"],
["70% bottom", "70% 100%"],
["70u1 bottom", "70u1 100%"],
["center 60%", "50% 60%"],
["center 60u1", "50% 60u1"],
["60% center", "60% 50%"],
["60u1 center", "60u1 50%"],
////// [ keyword | keyword percent ], [ keyword | keyword length ] x 5 keywords
["center top 50%", "50% 50%"],
["center top 50u1", "50% 50u1"],
["center left 50%", "50% 50%"],
["center left 50u1", "50u1 50%"],
["center right 70%", "30% 50%"],
["center right 70u1", "right 70u1 top 50%"],
["center bottom 70%", "50% 30%"],
["center bottom 70u1", "left 50% bottom 70u1"],
["left top 50%", "0% 50%"],
["left top 50u1", "0% 50u1"],
["left bottom 70%", "0% 30%"],
["left bottom 70u1", "left 0% bottom 70u1"],
["top left 50%", "50% 0%"],
["top left 50u1", "50u1 0%"],
["top right 70%", "30% 0%"],
["top right 70u1", "right 70u1 top 0%"],
["bottom left 50%", "50% 100%"],
["bottom left 50u1", "50u1 100%"],
["bottom right 70%", "30% 100%"],
["bottom right 70u1", "right 70u1 top 100%"],
["right bottom 70%", "100% 30%"],
["right bottom 70u1", "left 100% bottom 70u1"],
["right top 50%", "100% 50%"],
["right top 50u1", "100% 50u1"],
////// [ keyword percent | keyword], [ keyword length | keyword ] x 5 keywords
["left 50% center", "50% 50%"],
["left 50u1 center", "50u1 50%"],
["left 50% top", "50% 0%"],
["left 50u1 top", "50u1 0%"],
["left 50% bottom", "50% 100%"],
["left 50u1 bottom", "50u1 100%"],
["top 50% center", "50% 50%"],
["top 50u1 center", "50% 50u1"],
["top 50% left", "0% 50%"],
["top 50u1 left", "0% 50u1"],
["top 50% right", "100% 50%"],
["top 50u1 right", "100% 50u1"],
["bottom 70% center", "50% 30%"],
["bottom 70u1 center", "left 50% bottom 70u1"],
["bottom 70% left", "0% 30%"],
["bottom 70u1 left", "left 0% bottom 70u1"],
["bottom 70% right", "100% 30%"],
["bottom 70u1 right", "left 100% bottom 70u1"],
["right 80% center", "20% 50%"],
["right 80u1 center", "right 80u1 top 50%"],
["right 80% bottom", "20% 100%"],
["right 80u1 bottom", "right 80u1 top 100%"],
["right 80% top", "20% 0%"],
["right 80u1 top", "right 80u1 top 0%"],
////// [ keyword percent | keyword percent], [ keyword percent | keyword length],
////// [ keyword length | keyword length], [ keyword length | keyword percent] x 5 keywords
["left 50% top 50%", "50% 50%"],
["left 50% top 50u1", "50% 50u1"],
["left 50% bottom 70%", "50% 30%"],
["left 50% bottom 70u1", "left 50% bottom 70u1"],
["left 50u1 top 50%", "50u1 50%"],
["left 50u1 top 50u1", "50u1 50u1"],
["left 50u1 bottom 70%", "50u1 30%"],
["left 50u1 bottom 70u1", "left 50u1 bottom 70u1"],
["top 50% left 50%", "50% 50%"],
["top 50% left 50u1", "50u1 50%"],
["top 50% right 80%", "20% 50%"],
["top 50% right 80u1", "right 80u1 top 50%"],
["top 50u1 left 50%", "50% 50u1"],
["top 50u1 left 50u1", "50u1 50u1"],
["top 50u1 right 80%", "20% 50u1"],
["top 50u1 right 80u1", "right 80u1 top 50u1"],
["bottom 70% left 50%", "50% 30%"],
["bottom 70% left 50u1", "50u1 30%"],
["bottom 70% right 80%", "20% 30%"],
["bottom 70% right 80u1", "right 80u1 top 30%"],
["bottom 70u1 left 50%", "left 50% bottom 70u1"],
["bottom 70u1 left 50u1", "left 50u1 bottom 70u1"],
["bottom 70u1 right 80%", "left 20% bottom 70u1"],
["bottom 70u1 right 80u1", "right 80u1 bottom 70u1"],
["right 80% top 50%", "20% 50%"],
["right 80% top 50u1", "20% 50u1"],
["right 80% bottom 70%", "20% 30%"],
["right 80% bottom 70u1", "left 20% bottom 70u1"],
["right 80u1 top 50%", "right 80u1 top 50%"],
["right 80u1 top 50u1", "right 80u1 top 50u1"],
["right 80u1 bottom 70%", "right 80u1 top 30%"],
["right 80u1 bottom 70u1", "right 80u1 bottom 70u1"],
];
var invalidPositions = [
////// [ keyword | percent ], [ keyword | length ], [ percent | keyword ], [ length | keyword ] x 5 keywords
"50% left",
"50px left",
"top 50%",
"80% right",
"80px right",
"bottom 70%",
"bottom 70px",
////// [ keyword | keyword percent ], [ keyword | keyword length ] x 5 keywords
"center center 60%",
"center center 60px",
"left center 60%",
"left center 60px",
"left right 80%",
"left right 80px",
"left left 50%",
"left left 50px",
"top center 60%",
"top center 60px",
"top bottom 80%",
"top bottom 80px",
"top top 50%",
"top top 50px",
"bottom center 60%",
"bottom center 60px",
"bottom top 50%",
"bottom top 50px",
"bottom bottom 50%",
"bottom bottom 50px",
"right center 60%",
"right center 60px",
"right left 50%",
"right left 50px",
"right right 70%",
"right right 70px",
////// [ keyword percent | keyword], [ keyword length | keyword ] x 5 keywords
"center 60% top",
"center 60px top",
"center 60% bottom",
"center 60px bottom",
"center 60% left",
"center 60px left",
"center 60% right",
"center 60px right",
"center 60% center",
"center 60px center",
"left 50% right",
"left 50px right",
"left 50% left",
"left 50px left",
"top 50% bottom",
"top 50px bottom",
"top 50% top",
"top 50px top",
"bottom 70% top",
"bottom 70px top",
"bottom 70% bottom",
"bottom 70px bottom",
"right 80% left",
"right 80px left",
////// [ keyword percent | keyword percent], [ keyword percent | keyword length],
////// [ keyword length | keyword length], [ keyword length | keyword percent] x 5 keywords
"center 60% top 50%",
"center 60% top 50px",
"center 60% bottom 70%",
"center 60% bottom 70px",
"center 60% left 50%",
"center 60% left 50px",
"center 60% right 70%",
"center 60% right 70px",
"center 60% center 65%",
"center 60% center 65px",
"center 60px top 50%",
"center 60px top 50px",
"center 60px bottom 70%",
"center 60px bottom 70px",
"center 60px left 50%",
"center 60px left 50px",
"center 60px right 70%",
"center 60px right 70px",
"center 60px center 65%",
"center 60px center 65px",
"left 50% center 60%",
"left 50% center 60px",
"left 50% right 80%",
"left 50% right 80px",
"left 50% left 50%",
"left 50% left 50px",
"left 50px center 60%",
"left 50px center 60px",
"left 50px right 80%",
"left 50px right 80px",
"left 50px left 50%",
"left 50px left 50px",
"top 50% center 60%",
"top 50% center 60px",
"top 50% bottom 50%",
"top 50% bottom 50px",
"top 50% top 50%",
"top 50% top 50px",
"top 50px center 60%",
"top 50px center 60px",
"top 50px bottom 70%",
"top 50px bottom 70px",
"top 50px top 50%",
"top 50px top 50px",
"bottom 70% center 60%",
"bottom 70% center 60px",
"bottom 70% top 50%",
"bottom 70% top 50px",
"bottom 70% bottom 50%",
"bottom 70% bottom 50px",
"bottom 70px center 60%",
"bottom 70px center 60px",
"bottom 70px top 50%",
"bottom 70px top 50px",
"bottom 70px bottom 50%",
"bottom 70px bottom 50px",
"right 80% center 60%",
"right 80% center 60px",
"right 80% left 50%",
"right 80% left 50px",
"right 80% right 85%",
"right 80% right 85px",
"right 80px center 60%",
"right 80px center 60px",
"right 80px left 50%",
"right 80px left 50px",
"right 80px right 85%",
"right 80px right 85px"
];
// valid radii values for circle + ellipse
// [value, expected_inline, [expected_computed?]]
var validCircleRadii = [
['', 'at 50% 50%', 'at 50% 50%'],
['50u1', '50u1 at 50% 50%'],
['50%', '50% at 50% 50%'],
['closest-side', 'at 50% 50%'],
['farthest-side', 'farthest-side at 50% 50%']
]
var validEllipseRadii = [
['', 'at 50% 50%', 'at 50% 50%'],
['50u1', '50u1 at 50% 50%', '50u1 at 50% 50%'],
['50%', '50% at 50% 50%', '50% at 50% 50%'],
['closest-side', 'at 50% 50%', 'at 50% 50%'],
['farthest-side', 'farthest-side at 50% 50%', 'farthest-side at 50% 50%'],
['50u1 100u1', '50u1 100u1 at 50% 50%'],
['100u1 100px', '100u1 100px at 50% 50%'],
['25% 50%', '25% 50% at 50% 50%'],
['50u1 25%', '50u1 25% at 50% 50%'],
['25% 50u1', '25% 50u1 at 50% 50%'],
['25% closest-side', '25% at 50% 50%'],
['25u1 closest-side', '25u1 at 50% 50%'],
['closest-side 75%', 'closest-side 75% at 50% 50%'],
['closest-side 75u1', 'closest-side 75u1 at 50% 50%'],
['25% farthest-side', '25% farthest-side at 50% 50%'],
['25u1 farthest-side', '25u1 farthest-side at 50% 50%'],
['farthest-side 75%', 'farthest-side 75% at 50% 50%'],
['farthest-side 75u1', 'farthest-side 75u1 at 50% 50%'],
['closest-side closest-side', 'at 50% 50%'],
['farthest-side farthest-side', 'farthest-side farthest-side at 50% 50%'],
['closest-side farthest-side', 'closest-side farthest-side at 50% 50%'],
['farthest-side closest-side', 'farthest-side at 50% 50%']
]
var validInsets = [
["One arg - u1", "10u1"],
["One arg - u2", "10u2"],
["Two args - u1 u1", "10u1 20u1"],
["Two args - u1 u2", "10u1 20u2"],
["Two args - u2 u1", "10u2 20u1"],
["Two args - u2 u2", "10u2 20u2"],
["Three args - u1 u1 u1", "10u1 20u1 30u1"],
["Three args - u1 u1 u2", "10u1 20u1 30u2"],
["Three args - u1 u2 u1", "10u1 20u2 30u1"],
["Three args - u1 u2 u2 ", "10u1 20u2 30u2"],
["Three args - u2 u1 u1", "10u2 20u1 30u1"],
["Three args - u2 u1 u2 ", "10u2 20u1 30u2"],
["Three args - u2 u2 u1 ", "10u2 20u2 30u1"],
["Three args - u2 u2 u2 ","10u2 20u2 30u2"],
["Four args - u1 u1 u1 u1", "10u1 20u1 30u1 40u1"],
["Four args - u1 u1 u1 u2", "10u1 20u1 30u1 40u2"],
["Four args - u1 u1 u2 u1", "10u1 20u1 30u2 40u1"],
["Four args - u1 u1 u2 u2", "10u1 20u1 30u2 40u2"],
["Four args - u1 u2 u1 u1", "10u1 20u2 30u1 40u1"],
["Four args - u1 u2 u1 u2", "10u1 20u2 30u1 40u2"],
["Four args - u1 u2 u2 u1", "10u1 20u2 30u2 40u1"],
["Four args - u1 u2 u2 u2", "10u1 20u2 30u2 40u2"],
["Four args - u2 u1 u1 u1", "10u2 20u1 30u1 40u1"],
["Four args - u2 u1 u1 u2", "10u2 20u1 30u1 40u2"],
["Four args - u2 u1 u2 u1", "10u2 20u1 30u2 40u1"],
["Four args - u2 u1 u2 u2", "10u2 20u1 30u2 40u2"],
["Four args - u2 u2 u1 u1", "10u2 20u2 30u1 40u1"],
["Four args - u2 u2 u1 u2", "10u2 20u2 30u1 40u2"],
["Four args - u2 u2 u2 u1", "10u2 20u2 30u2 40u1"],
["Four args - u2 u2 u2 u2", "10u2 20u2 30u2 40u2"]
]
var validPolygons = [
["One vertex - u1 u1", "10u1 20u1"],
["One vertex - u1 u2", "10u1 20u2"],
["Two vertices - u1 u1, u1 u1", "10u1 20u1, 30u1 40u1"],
["Two vertices - u1 u1, u2 u2", "10u1 20u1, 30u2 40u2"],
["Two vertices - u2 u2, u1 u1", "10u2 20u2, 30u1 40u1"],
["Two vertices - u1 u2, u2 u1", "10u1 20u2, 30u2 40u1"],
["Three vertices - u1 u1, u1 u1, u1 u1", "10u1 20u1, 30u1 40u1, 50u1 60u1"],
["Three vertices - u2 u2, u2 u2, u2 u2", "10u2 20u2, 30u2 40u2, 50u2 60u2"],
["Three vertices - u3 u3, u3 u3, u3 u3", "10u3 20u3, 30u3 40u3, 50u3 60u3"],
["Three vertices - u1 u1, u2 u2, u3 u3", "10u1 20u1, 30u2 40u2, 50u3 60u3"],
["Three vertices - u3 u3, u1, u1, u2 u2", "10u3 20u3, 30u1 40u1, 50u2 60u2"],
]
// [test value, expected property value, expected computed style]
var calcTestValues = [
["calc(10in)", "calc(10in)", "960px"],
["calc(10in + 20px)", "calc(980px)", "980px"],
["calc(30%)", "calc(30%)", "30%"],
["calc(100%/4)", "calc(25%)", "25%"],
["calc(25%*3)", "calc(75%)", "75%"],
// These following two test cases represent an either/or situation in the spec
// computed value is always supposed to be, at most, a tuple of a length and a percentage.
// the computed value of a calc() expression can be represented as either a number or a tuple
// of a dimension and a percentage.
// http://www.w3.org/TR/css3-values/#calc-notation
["calc(25%*3 - 10in)", "calc(75% - 10in)", ["calc(75% - 960px)", "calc(-960px + 75%)"]],
["calc((12.5%*6 + 10in) / 4)", "calc((75% + 10in) / 4)", ["calc((75% + 960px) / 4)", "calc(240px + 18.75%)"]]
]
return {
testInlineStyle: testInlineStyle,
testComputedStyle: testComputedStyle,
testShapeMarginInlineStyle: testShapeMarginInlineStyle,
testShapeMarginComputedStyle: testShapeMarginComputedStyle,
testShapeThresholdInlineStyle: testShapeThresholdInlineStyle,
testShapeThresholdComputedStyle: testShapeThresholdComputedStyle,
buildTestCases: buildTestCases,
buildRadiiTests: buildRadiiTests,
buildPositionTests: buildPositionTests,
buildInsetTests: buildInsetTests,
buildPolygonTests: buildPolygonTests,
generateInsetRoundCases: generateInsetRoundCases,
buildCalcTests: buildCalcTests,
validUnits: validUnits,
calcTestValues: calcTestValues,
roundResultStr: roundResultStr
}
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

View file

@ -0,0 +1,449 @@
(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}]
};
},
'auto': function(property) {
var types = properties[property] || unspecified_properties[property];
var val = values[types[0]](property);
var key = Object.keys(val).shift();
return {
to: [val[key][1], 'auto'],
from: ['auto', val[key][1]]
};
},
// 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}]
};
}
};
/*
* 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'],
// Note: doesn't seem implemented anywhere
'crop': ['rectangle'],
'vertical-align': ['length', 'percentage'],
'opacity': ['number[0,1]'],
'visibility': ['visibility'],
'z-index': ['integer']
};
/*
* Property to auto-value mapping
* (lazily taken from http://www.siliconbaytraining.com/pages/csspv.html)
*/
var properties_auto = [
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'height',
'width',
'clip',
'marker-offset',
'top',
'right',
'left',
'bottom',
'z-index'
];
/*
* 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'],
'marker-offset': ['length'],
'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'],
'zoom': ['number'],
'outline-radius-topleft': ['length', 'percentage'],
'outline-radius-topright': ['length', 'percentage'],
'outline-radius-bottomright': ['length', 'percentage'],
'outline-radius-bottomleft': ['length', 'percentage'],
'display': ['display'],
'position': ['position']
};
/*
* 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.getAutoPropertyTests = function() {
var accepted = {};
for (var i = 0, key; key = properties_auto[i]; i++) {
accepted[key] = ['auto'];
}
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);

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<title>One region in body</title>
<style>
html, body {
margin: 0;
padding: 0;
}
#container {
background: red;
}
#content {
flow-into: flow;
font-family: Ahem;
font-size: 20px;
line-height: 1em;
color: green;
}
#region {
flow-from: flow;
}
</style>
<script src="util.js" type="text/javascript"></script>
</head>
<body>
<div id="container">
<!-- The &#8203; entity is a zerowidth space. It enables me to create nicely reflowing rectangles of Ahem text -->
<div id="content">
xxxx&#x200B;xxxx&#x200B;xxxx&#x200B;xxxx
</div>
</div>
<div id="region">
</div>
</body></html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<title>One region in body</title>
<style>
html, body {
margin: 0;
padding: 0;
}
#container {
background: red;
}
#content {
flow-into: flow;
font-family: Ahem;
font-size: 20px;
line-height: 1em;
color: green;
}
#region {
flow-from: flow;
}
</style>
</head>
<body>
<div id="container">
<!-- The &#8203; entity is a zerowidth space. It enables me to create nicely reflowing rectangles of Ahem text -->
<div id="content">
xxxx&#x200B;xxxx&#x200B;xxxx&#x200B;xxxx
</div>
</div>
<div id="region-parent">
<div id="region">
</div>
</div>
<script src="util.js" type="text/javascript"></script>
</body></html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

View file

@ -0,0 +1,145 @@
(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, {timeout: options.timeout || 60000});
});
});
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 test (possibly abort)
setTimeout(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);
}, duration);
}
// allow DOMContentLoaded before actually doing something
setTimeout(runLoop, 100);
};
})(window);

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<title>One region in body</title>
<style>
html, body {
margin: 0;
padding: 0;
}
#container {
background: red;
}
#content {
flow-into: flow;
font-family: Ahem;
font-size: 20px;
line-height: 1em;
color: green;
}
#region1, #region2 {
flow-from: flow;
}
</style>
</head>
<body>
<div id="container">
<!-- The &#8203; entity is a zerowidth space. It enables me to create nicely reflowing rectangles of Ahem text -->
<div id="content">
xxxx&#x200B;xxxx&#x200B;xxxx&#x200B;xxxx&#x200B;xxxx&#x200B;xxxx&#x200B;xxxx&#x200B;xxxx
</div>
</div>
<div id="region-parent">
<div id="region1"></div>
<div id="region2"></div>
</div>
<script src="util.js" type="text/javascript"></script>
</body></html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

View file

@ -0,0 +1,29 @@
function resizeViewportTo(viewportSelector, width, height) {
var iframe = document.querySelector(viewportSelector);
// Commonly used trick to trigger a layout
iframe.contentWindow.document.body.offsetTop;
iframe.width = width;
iframe.height = height;
iframe.contentWindow.document.body.offsetTop;
}
function injectStylesInIFrame(styleSelector, frameSelector) {
var style = document.querySelector(styleSelector),
frame = document.querySelector(frameSelector);
frame.contentWindow.addNewStyles(style.textContent);
}
if (window.parent != window) {
// we're in an iframe, so expose the bits that allow setting styles inside
window.addNewStyles = function (cssText) {
var styleTag = document.createElement("style"),
textNode = document.createTextNode(cssText);
styleTag.appendChild(textNode);
document.head.appendChild(styleTag);
}
}

View file

@ -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);