| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>CSS Fonts Module Level 4: getComputedStyle().font</title> | |
| <link rel="help" href="https://drafts.csswg.org/css-fonts-4/#font-prop"> | |
| <meta name="assert" content="font computed value round-trips."> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script src="/css/support/computed-testcommon.js"></script> | |
| <style> | |
| #container { | |
| font-weight: 800; | |
| font-size: 40px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="container"> | |
| <div id="target"></div> | |
| </div> | |
| <script> | |
| 'use strict'; | |
| // Firefox and Edge 18 serialize these as supplied. | |
| // Blink and Safari have implementation-dependent or platform-dependent serializations. | |
| function test_system_font(keyword) { | |
| test(() => { | |
| const target = document.getElementById('target'); | |
| const previousValue = 'italic xx-large/0px fantasy'; | |
| target.style.font = previousValue; | |
| target.style.font = keyword; | |
| const readValue = getComputedStyle(target).font; | |
| assert_not_equals(readValue, '', 'font should be set'); | |
| assert_not_equals(readValue, previousValue, 'font should be updated'); | |
| target.style.font = previousValue; | |
| target.style.font = readValue; | |
| assert_equals(getComputedStyle(target).font, readValue, "serialization should round-trip"); | |
| }, keyword + ' should be a supported system font.'); | |
| } | |
| test_system_font('caption'); | |
| test_system_font('icon'); | |
| test_system_font('menu'); | |
| test_system_font('message-box'); | |
| test_system_font('small-caption'); | |
| test_system_font('status-bar'); | |
| // a value other than normal | |
| const generate_style = () => 'italic'; | |
| // value other than normal | |
| const generate_variant = () => 'small-caps'; | |
| // values other than normal | |
| const generate_weight = (() => { | |
| const alternatives = [ | |
| 'bold', | |
| 'bolder', | |
| 'lighter', | |
| '100', | |
| '900' | |
| ]; | |
| let counter = 0; | |
| return () => alternatives[counter++ % alternatives.length]; | |
| })(); | |
| const compute_weight = (() => { | |
| const cache = {} | |
| return (weight) => { | |
| if (!(weight in cache)) { | |
| const weight_reference = document.createElement('div'); | |
| document.getElementById('container').appendChild(weight_reference); | |
| weight_reference.style.fontWeight = weight; | |
| cache[weight] = getComputedStyle(weight_reference).fontWeight; | |
| weight_reference.remove(); | |
| } | |
| return cache[weight]; | |
| } | |
| })(); | |
| // values other than normal | |
| const generate_stretch = (() => { | |
| const alternatives = [ | |
| 'ultra-condensed', | |
| 'extra-condensed', | |
| 'condensed', | |
| 'semi-condensed', | |
| 'semi-expanded', | |
| 'expanded', | |
| 'extra-expanded', | |
| 'ultra-expanded' | |
| ]; | |
| let counter = 0; | |
| return () => alternatives[counter++ % alternatives.length]; | |
| })(); | |
| const generate_size = (() => { | |
| const alternatives = [ | |
| // <absolute-size> | |
| 'xx-small', | |
| 'medium', | |
| 'xx-large', | |
| // <relative-size> | |
| 'larger', | |
| 'smaller', | |
| // <length-percentage> | |
| '10px', | |
| '20%', | |
| 'calc(30% - 40px)', | |
| ]; | |
| let counter = 0; | |
| return () => alternatives[counter++ % alternatives.length]; | |
| })(); | |
| const generate_line_height = (() => { | |
| const alternatives = [ | |
| null, | |
| 'normal', | |
| '1.2', | |
| 'calc(120% + 1.2em)' | |
| ]; | |
| let counter = 0; | |
| return () => alternatives[counter++ % alternatives.length]; | |
| })(); | |
| const generate_family = (() => { | |
| const alternatives = [ | |
| 'serif', | |
| 'sans-serif', | |
| 'cursive', | |
| 'fantasy', | |
| 'monospace', | |
| 'Menu', | |
| '"Non-Generic Example Family Name"' | |
| ]; | |
| let counter = 0; | |
| return () => alternatives[counter++ % alternatives.length]; | |
| })(); | |
| function test_specific(prefix) { | |
| const reference = document.createElement('div'); | |
| document.getElementById('container').appendChild(reference); | |
| let parts = []; | |
| let canonical = []; | |
| let style = null; | |
| let variant = null; | |
| let weight = null; | |
| let stretch = null; | |
| for (let entry of prefix) { | |
| if (entry === 'style') { | |
| style = generate_style(); | |
| parts.push(style); | |
| } else if (entry === 'variant') { | |
| variant = generate_variant(); | |
| parts.push(variant); | |
| } else if (entry === 'weight') { | |
| weight = generate_weight(); | |
| parts.push(weight); | |
| } else if (entry === 'stretch') { | |
| stretch = generate_stretch(); | |
| parts.push(stretch); | |
| } else { | |
| // normal | |
| parts.push('normal'); | |
| } | |
| } | |
| if (style) { | |
| canonical.push(style); | |
| reference.style.fontStyle = style; | |
| } | |
| if (variant) { | |
| canonical.push(variant); | |
| reference.style.fontVariant = style; | |
| } | |
| if (weight) { | |
| canonical.push(compute_weight(weight)); | |
| reference.style.fontWeight = style; | |
| } | |
| if (stretch) { | |
| canonical.push(stretch); | |
| reference.style.fontStretch = style; | |
| } | |
| const size = generate_size(); | |
| reference.style.fontSize = size; | |
| const line_height = generate_line_height(); | |
| if (line_height) { | |
| parts.push(size + '/' + line_height); | |
| reference.style.lineHeight = line_height; | |
| } else { | |
| parts.push(size); | |
| } | |
| const family = generate_family(); | |
| parts.push(family); | |
| reference.style.fontFamily = family; | |
| if (!line_height || line_height === 'normal') { | |
| canonical.push(getComputedStyle(reference).fontSize); | |
| } else { | |
| // Implementations differ on adjacent space when serializing '/' | |
| // https://github.com/w3c/csswg-drafts/issues/4282 | |
| canonical.push(getComputedStyle(reference).fontSize + ' / ' + getComputedStyle(reference).lineHeight); | |
| } | |
| canonical.push(family); | |
| reference.remove(); | |
| test_computed_value('font', parts.join(' '), canonical.join(' ')); | |
| } | |
| // Font style, variant, weight and stretch may appear in any order. | |
| // Any or all may be omitted. Each accepts the keyword 'normal'. | |
| // We generate every permutation of these four properties, treating | |
| // the cases of a property value being omitted or being explicitly | |
| // 'normal' as being distinct permutations from when the property | |
| // has a value other than 'normal'. | |
| function test_various(prefix) { | |
| test_specific(prefix); | |
| if (prefix.length === 4) { | |
| // Font style, variant, weight and stretch may not appear | |
| // more than once. | |
| return; | |
| } | |
| const alternatives = [ | |
| 'normal', | |
| 'style', | |
| 'variant', | |
| 'weight', | |
| 'stretch' | |
| ]; | |
| for (let alternative of alternatives) { | |
| // Since this is called recursively, check prefix for existing | |
| // alternatives, otherwise we may have two styles or two variants, etc. | |
| if (alternative === 'normal' || !prefix.includes(alternative)) | |
| test_various(prefix.concat(alternative)); | |
| } | |
| } | |
| test_various([]); | |
| </script> | |
| </body> | |
| </html> |