serialize-values.html (19827B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>CSSOM serialize values</title> 4 <link rel="help" href="https://drafts.csswg.org/cssom/#serializing-css-values"> 5 <meta name="author" title="Josh Matthews" href="mailto:josh@joshmatthews.net"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <body> 9 <div id="log"></div> 10 <div id="parent"></div> 11 <script> 12 function iterable(values) { 13 var i = 0; 14 return function() { 15 if (i < values.length) { 16 return values[i++]; 17 } 18 return null; 19 } 20 } 21 22 function color() { 23 var colors = ['black', 'red', 'rgb(50, 75, 100)', 'rgba(5, 7, 10, 0.5)']; 24 return iterable(colors); 25 } 26 27 function percentage() { 28 var values = ["5%", {actual: ".5%", serialized: "0.5%"}]; 29 return iterable(values); 30 } 31 32 function negative_percentage() { 33 var values = ["-5%", {actual: "-.5%", serialized: "-0.5%"}]; 34 return iterable(values); 35 } 36 37 function length() { 38 var values = ["0px", "1px", {actual: ".1em", serialized: "0.1em"}]; 39 return iterable(values); 40 } 41 42 function negative_length() { 43 var values = [{actual: "-0px", serialized: "0px"}, 44 "-1px", {actual: "-.1em", serialized: "-0.1em"}]; 45 return iterable(values); 46 } 47 48 function degree() { 49 var values = ["87deg"]; 50 return iterable(values); 51 } 52 53 function uri() { 54 var values = ["url(\"http://localhost/\")", 55 {actual: "url(http://localhost/)", 56 serialized: "url(\"http://localhost/\")"}]; 57 return iterable(values); 58 } 59 60 function border_style() { 61 var values = ['none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 62 'inset', 'outset']; 63 return iterable(values); 64 } 65 66 function border_style_without_hidden() { 67 var values = ['none', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 68 'inset', 'outset']; 69 return iterable(values); 70 } 71 72 function integer() { 73 var values = ['0', '101', '-51']; 74 return iterable(values); 75 } 76 77 function nonzero_positive_integer() { 78 var values = ['101']; 79 return iterable(values); 80 } 81 82 function shape() { 83 var values = ['rect(1em, auto, 0.5px, 2000em)']; 84 return iterable(values); 85 } 86 87 function string() { 88 var values = ['"string"', {actual: "'string'", serialized: '"string"'}]; 89 return iterable(values); 90 } 91 92 function counter() { 93 var values = ['counter(par-num)', 94 { actual: 'counter(par-num, decimal)', serialized: 'counter(par-num)' }, 95 'counter(par-num, upper-roman)']; 96 return iterable(values); 97 } 98 99 function attr() { 100 var values = ['attr(foo-bar)', 'attr(foo_bar)', 101 {actual: "attr(|bar)", serialized: "attr(bar)"}, 102 {actual: "attr( |bar )", serialized: "attr(bar)"}]; 103 return iterable(values); 104 } 105 106 function attr_fallback() { 107 var values = ['attr(foo-bar, "fallback")', 'attr(foo_bar, "fallback")', 108 {actual: 'attr(|bar, "fallback")', serialized: 'attr(bar, "fallback")'}, 109 {actual: 'attr(foo, "")', serialized: 'attr(foo, "")'}, 110 {actual: 'attr( |foo , "" )', serialized: 'attr(foo)'}]; 111 return iterable(values); 112 } 113 114 function family_name() { 115 var values = ['Arial', {actual: "'Lucida Grande'", serialized: '"Lucida Grande"'}]; 116 return iterable(values); 117 } 118 119 function generic_family() { 120 var values = ['serif', 'sans-serif']; 121 return iterable(values); 122 } 123 124 function absolute_size() { 125 var values = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large']; 126 return iterable(values); 127 } 128 129 function relative_size() { 130 var values = ['larger', 'smaller']; 131 return iterable(values); 132 } 133 134 function number() { 135 var values = ['0', {'actual': '-0', serialized: '0'}, '1000', '-5123', '0.9', '-0.09']; 136 return iterable(values); 137 } 138 139 function positive_number() { 140 var values = ['0', {'actual': '-0', serialized: '0'}, '1000', '0.9']; 141 return iterable(values); 142 } 143 144 function generate_inline_style(name, value) { 145 if (value) { 146 return {'declaration': name + ": " + value.actual, 147 'value': value.actual, 148 'result': value.expected}; 149 } 150 return null; 151 } 152 153 var minimal_results = { 154 }; 155 156 function create_result(propertyName, actual, expected) { 157 var key = propertyName + ": " + expected 158 if (key in minimal_results) 159 expected = minimal_results[key] 160 return {actual: actual, expected: expected} 161 } 162 163 function all_values(propertyName, values) { 164 var results = []; 165 for (var i = 0; i < values.length; i++) { 166 var value = values[i]; 167 if (typeof value == "function") { 168 var f = value(); 169 var result; 170 while ((result = f()) != null) { 171 if (typeof result == "object" && 'serialized' in result) { 172 results.push(create_result(propertyName, result.actual, result.serialized)); 173 } else { 174 results.push(create_result(propertyName, result, result)); 175 } 176 } 177 } else if (typeof value == "string") { 178 results.push(create_result(propertyName, value, value)); 179 } else if (value instanceof Array) { 180 var subresults = []; 181 for (var j = 0; j < value.length; j++) { 182 var subresult = all_values(propertyName, value[j]); 183 if (!(subresult instanceof Array)) { 184 subresult = [subresult]; 185 } 186 subresults.push(subresult); 187 } 188 if (subresults.length > 1) { 189 function choose_slices(vecs) { 190 if (vecs.length == 1) { 191 return vecs[0].map(function(v) { return [v]; }); 192 } 193 var slice_results = []; 194 var rest = choose_slices(vecs.slice(1, vecs.length)); 195 for (var a = 0; a < vecs[0].length; a++) { 196 for (var b = 0; b < rest.length; b++) { 197 var result = vecs[0][a]; 198 slice_results.push([result].concat(rest[b])); 199 } 200 } 201 return slice_results; 202 } 203 204 subresults = choose_slices(subresults).map(function (a) { 205 var actual = a.map(function(a) { return a.actual }); 206 var expected = a.map(function(a) { return a.expected }); 207 return create_result(propertyName, actual.join(' '), expected.join(' ')) 208 }); 209 } 210 for (var j = 0; j < subresults.length; j++) { 211 results = results.concat(subresults[j]); 212 } 213 } else if (value instanceof Object && 'serialized' in value) { 214 results.push(create_result(propertyName, value.actual, value.serialized)); 215 } else if (typeof value == "number") { 216 results.push(create_result(propertyName, value.toString(), value.toString())); 217 } else { 218 throw "unexpected value type: " + typeof(value); 219 } 220 } 221 return results; 222 } 223 224 function create_value_generator(propertyName, property) { 225 var results = all_values(propertyName, property.values); 226 return iterable(results); 227 } 228 229 function to_idl(property) { 230 return property.replace(/-\w/g, function(x){return x[1].toUpperCase()}); 231 } 232 233 function run_individual_test(property, generator, initial) { 234 var elem = document.createElement('div'); 235 document.getElementById('parent').appendChild(elem); 236 var test_data = generator(); 237 var style = generate_inline_style(property, test_data); 238 if (!style) { 239 return false; 240 } 241 var t = async_test(style.declaration); 242 243 t.add_cleanup(function() { 244 document.getElementById('parent').removeChild(elem); 245 }); 246 247 t.step(function() { 248 elem.setAttribute('style', style.declaration); 249 var expected = style.result; 250 var serialized = elem.style[to_idl(property)]; 251 assert_equals(serialized, expected, property + ' raw inline style declaration'); 252 elem.setAttribute('style', ''); 253 elem.style[to_idl(property)] = style.value; 254 assert_equals(elem.style[to_idl(property)], expected, property + ' style property'); 255 }); 256 t.done(); 257 return true; 258 } 259 260 function test_property(property) { 261 var generator = create_value_generator(property[0], property[1]); 262 while (run_individual_test(property[0], generator, property[1].initial)) { 263 } 264 } 265 266 var properties = [ 267 ['background-attachment', { 268 'values': ['scroll', 'fixed', 'inherit'], 269 'initial': 'scroll', 270 }], 271 ['background-color', { 272 'values': [color, 'transparent', 'inherit'], 273 'initial': 'transparent', 274 }], 275 ['background-image', { 276 'values': [uri, 'none', 'inherit'], 277 'initial': 'none', 278 }], 279 ['background-position', { 280 'values': [[[percentage, negative_percentage, length, negative_length, 281 'left', 'center', 'right'], 282 [percentage, negative_percentage, length, negative_length, 283 'top', 'center', 'bottom']], 284 'inherit'], 285 'initial': '0% 0%', 286 }], 287 ['background-repeat', { 288 'values': ['repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'inherit'], 289 'initial': 'repeat', 290 }], 291 //background 292 ['border-collapse', { 293 'values': ['collapse', 'separate', 'inherit'], 294 'initial': 'separate', 295 }], 296 //border-color 297 ['border-spacing', { 298 'values': [length, 'inherit'], 299 'initial': '0', 300 }], 301 //border-style 302 //border-top, border-right, border-bottom, border-left 303 ['border-top-color', { 304 'values': [color, 'transparent', 'inherit'], 305 'initial': 'black', //FIXME 306 }], 307 ['border-right-color', { 308 'values': [color, 'transparent', 'inherit'], 309 'initial': 'black', //FIXME 310 }], 311 ['border-bottom-color', { 312 'values': [color, 'transparent', 'inherit'], 313 'initial': 'black', //FIXME 314 }], 315 ['border-left-color', { 316 'values': [color, 'transparent', 'inherit'], 317 'initial': 'black', //FIXME 318 }], 319 ['border-top-style', { 320 'values': [border_style, 'inherit'], 321 'initial': null, 322 }], 323 ['border-right-style', { 324 'values': [border_style, 'inherit'], 325 'initial': null, 326 }], 327 ['border-bottom-style', { 328 'values': [border_style, 'inherit'], 329 'initial': null, 330 }], 331 ['border-left-style', { 332 'values': [border_style, 'inherit'], 333 'initial': null, 334 }], 335 ['border-top-width', { 336 'values': ['thin', 'medium', 'thick', length, 'inherit'], 337 'initial': 'medium', 338 }], 339 ['border-right-width', { 340 'values': ['thin', 'medium', 'thick', length, 'inherit'], 341 'initial': 'medium', 342 }], 343 ['border-bottom-width', { 344 'values': ['thin', 'medium', 'thick', length, 'inherit'], 345 'initial': 'medium', 346 }], 347 ['border-left-width', { 348 'values': ['thin', 'medium', 'thick', length, 'inherit'], 349 'initial': 'medium', 350 }], 351 //border-width 352 //border 353 ['bottom', { 354 'values': [length, percentage, 'auto', 'inherit'], 355 'initial': 'auto', 356 }], 357 ['caption-side', { 358 'values': ['top', 'bottom', 'inherit'], 359 'initial': 'top', 360 }], 361 ['clear', { 362 'values': ['none', 'left', 'right', 'both', 'inherit'], 363 'initial': 'none', 364 }], 365 ['clip', { 366 'values': [shape, 'auto', 'inherit'], 367 'initial': 'auto', 368 }], 369 ['color', { 370 'values': [color, 'inherit'], 371 'initial': 'black', //FIXME depends on user agent 372 }], 373 ['content', { 374 'values': ['normal', 'none', string, uri, counter, attr, attr_fallback, 'inherit'], //FIXME 375 'initial': 'normal', 376 }], 377 //counter-increment 378 //counter-reset 379 ['cursor', { 380 'values': [ 'auto', 'crosshair', 'default', 'pointer', 'move', 'e-resize', 'ne-resize', 381 'nw-resize', 'n-resize', 'se-resize', 'sw-resize', 's-resize', 'w-resize', 382 'text', 'wait', 'help', 'progress', 'inherit'], 383 'initial': 'auto', 384 }], 385 ['direction', { 386 'values': ['ltr', 'rtl', 'inherit'], 387 'initial': 'ltr', 388 }], 389 ['display', { 390 'values': ['inline', 'block', 'list-item', 'inline-block', 'table', 'inline-table', 391 'table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 392 'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none', 393 'inherit'], 394 'initial': 'inline', 395 }], 396 ['empty-cells', { 397 'values': ['show', 'hide', 'inherit'], 398 'initial': 'show', 399 }], 400 ['float', { 401 'values': ['left', 'right', 'none', 'inherit'], 402 'initial': 'none', 403 'property': 'cssFloat', 404 }], 405 ['font-family', { 406 'values': [family_name, generic_family, 'inherit'], 407 'initial': 'sans-serif', //FIXME depends on user agent 408 }], 409 ['font-size', { 410 'values': [absolute_size, relative_size, length, percentage, 'inherit'], 411 'initial': 'medium', 412 }], 413 ['font-style', { 414 'values': ['normal', 'italic', 'oblique', 'inherit'], 415 'initial': 'normal', 416 }], 417 ['font-variant', { 418 'values': ['normal', 'small-caps', 'inherit'], 419 'initial': 'normal', 420 }], 421 ['font-weight', { 422 'values': ['normal', 'bold', 'bolder', 'lighter', 100, 200, 300, 400, 500, 600, 423 700, 800, 900, 'inherit'], 424 'initial': 'normal', 425 }], 426 //font 427 ['height', { 428 'values': [length, percentage, 'auto', 'inherit'], 429 'initial': 'auto', 430 }], 431 ['left', { 432 'values': [length, percentage, 'auto', 'inherit'], 433 'initial': 'auto', 434 }], 435 ['letter-spacing', { 436 'values': ['normal', length, 'inherit'], 437 'initial': 'normal', 438 }], 439 ['line-height', { 440 'values': ['normal', positive_number, length, percentage, 'inherit'], 441 'initial': 'normal', 442 }], 443 ['list-style-image', { 444 'values': [uri, 'none', 'inherit'], 445 'initial': 'none', 446 }], 447 ['list-style-position', { 448 'values': ['inside', 'outside', 'inherit'], 449 'initial': 'outside', 450 }], 451 ['list-style-type', { 452 'values': ['disc', 'circle', 'square', 'disclosure-open', 'disclosure-closed', 453 'decimal', 'decimal-leading-zero', 'lower-roman', 454 'upper-roman', 'lower-greek', 'lower-latin', 'upper-latin', 'armenian', 'georgian', 455 'lower-alpha', 'upper-alpha', 'none', 'inherit'], 456 'initial': 'disc', 457 }], 458 //list-style 459 ['margin-right', { 460 'values': [length, percentage, 'auto', 'inherit'], 461 'initial': 0, 462 }], 463 ['margin-left', { 464 'values': [length, percentage, 'auto', 'inherit'], 465 'initial': 0, 466 }], 467 ['margin-top', { 468 'values': [length, percentage, 'auto', 'inherit'], 469 'initial': 0, 470 }], 471 ['margin-bottom', { 472 'values': [length, percentage, 'auto', 'inherit'], 473 'initial': 0, 474 }], 475 //margin 476 ['max-height', { 477 'values': [length, percentage, 'none', 'inherit'], 478 'initial': 'none', 479 }], 480 ['max-width', { 481 'values': [length, percentage, 'none', 'inherit'], 482 'initial': 'none', 483 }], 484 ['min-height', { 485 'values': [length, percentage, 'inherit'], 486 'initial': 0, 487 }], 488 ['min-width', { 489 'values': [length, percentage, 'inherit'], 490 'initial': 0, 491 }], 492 ['orphans', { 493 'values': [nonzero_positive_integer, 'inherit'], 494 'initial': 2, 495 }], 496 ['outline-color', { 497 'values': [color, 'invert', 'inherit'], 498 'initial': 'invert', 499 }], 500 ['outline-style', { 501 'values': [border_style_without_hidden, 'inherit'], 502 'initial': 'none', 503 }], 504 ['outline-width', { 505 'values': ['thin', 'medium', 'thick', length, 'inherit'], 506 'initial': 'medium', 507 }], 508 //outline 509 ['overflow', { 510 'values': ['visible', 'hidden', 'scroll', 'auto', 'inherit'], 511 'initial': 'visible', 512 }], 513 ['padding-top', { 514 'values': [length, percentage, 'inherit'], 515 'initial': 0, 516 }], 517 ['padding-right', { 518 'values': [length, percentage, 'inherit'], 519 'initial': 0, 520 }], 521 ['padding-bottom', { 522 'values': [length, percentage, 'inherit'], 523 'initial': 0, 524 }], 525 ['padding-left', { 526 'values': [length, percentage, 'inherit'], 527 'initial': 0, 528 }], 529 //padding 530 ['page-break-after', { 531 'values': ['auto', 'always', 'avoid', 'left', 'right', 'inherit'], 532 'initial': 'auto', 533 }], 534 ['page-break-before', { 535 'values': ['auto', 'always', 'avoid', 'left', 'right', 'inherit'], 536 'initial': 'auto', 537 }], 538 ['page-break-inside', { 539 'values': ['avoid', 'auto', 'inherit'], 540 'initial': 'auto', 541 }], 542 ['position', { 543 'values': ['static', 'relative', 'absolute', 'fixed', 'inherit'], 544 'initial': 'static', 545 }], 546 //FIXME quotes 547 ['right', { 548 'values': [length, percentage, 'auto', 'inherit'], 549 'initial': 'auto', 550 }], 551 ['table-layout', { 552 'values': ['auto', 'fixed', 'inherit'], 553 'initial': 'auto', 554 }], 555 ['text-align', { 556 'values': ['left', 'right', 'center', 'justify', 'inherit'], 557 'initial': null, 558 }], 559 ['text-decoration', { 560 'values': ['none', 'underline', 'overline', 'line-through', 'blink', 'inherit'], 561 'initial': 'none', 562 }], 563 ['text-indent', { 564 'values': [length, percentage, 'inherit'], 565 'initial': 0, 566 }], 567 ['text-transform', { 568 'values': ['capitalize', 'uppercase', 'lowercase', 'none', 'inherit'], 569 'initial': 'none', 570 }], 571 ['top', { 572 'values': [length, percentage, 'auto', 'inherit'], 573 'initial': 'auto', 574 }], 575 ['unicode-bidi', { 576 'values': ['normal', 'embed', 'bidi-override', 'inherit'], 577 'initial': 'normal', 578 }], 579 ['vertical-align', { 580 'values': ['baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom', 581 percentage, length, 'inherit'], 582 'initial': 'baseline', 583 }], 584 ['visibility', { 585 'values': ['visible', 'hidden', 'collapse', 'inherit'], 586 'initial': 'visible', 587 }], 588 ['white-space', { 589 'values': ['normal', 'pre', 'nowrap', 'pre-wrap', 'pre-line', 'inherit'], 590 'initial': 'normal', 591 }], 592 ['widows', { 593 'values': [nonzero_positive_integer, 'inherit'], 594 'initial': 2, 595 }], 596 ['width', { 597 'values': [length, percentage, 'auto', 'inherit'], 598 'initial': 'auto', 599 }], 600 ['word-spacing', { 601 'values': ['normal', length, 'inherit'], 602 'initial': 'normal', 603 }], 604 ['z-index', { 605 'values': ['auto', integer, 'inherit'], 606 'initial': 'auto', 607 }], 608 ] 609 610 for (var index = 0; index < properties.length; index++) { 611 test_property(properties[index]); 612 } 613 </script> 614 </body>