mirror of
https://github.com/servo/servo
synced 2026-04-28 18:37:39 +02:00
450 lines
14 KiB
JavaScript
450 lines
14 KiB
JavaScript
(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);
|