font-variant-features.js (19601B)
1 // data associated with gsubtest test font for testing font features 2 3 // prefix 4 gPrefix = ""; 5 6 // equivalent properties 7 // setting prop: value should match the specific feature settings listed 8 // 9 // each of these tests evaluate whether a given feature is enabled as required 10 // and also whether features that shouldn't be enabled are or not. 11 var gPropertyData = [ 12 // font-variant (shorthand) 13 // valid values 14 { prop: "font-variant", value: "normal", features: {"smcp": 0} }, 15 { prop: "font-variant", value: "small-caps", features: {"smcp": 1, "c2sc": 0} }, 16 { prop: "font-variant", value: "none", features: {"liga": 0, "dlig": 0, "clig": 0, "calt": 0, "hlig": 0} }, 17 { prop: "font-variant", value: "all-small-caps", features: {"smcp": 1, "c2sc": 1, "pcap": 0} }, 18 { prop: "font-variant", value: "common-ligatures no-discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} }, 19 { prop: "font-variant", value: "proportional-nums slashed-zero diagonal-fractions oldstyle-nums ordinal", features: {"frac": 1, "afrc": 0, "tnum": 0, "pnum": 1, "onum": 1, "ordn": 1, "zero": 1} }, 20 { prop: "font-variant", value: "all-small-caps traditional", features: {"smcp": 1, "c2sc": 1, "pcap": 0, "trad": 1, "jp04": 0} }, 21 { prop: "font-variant", value: "styleset(out-of-bounds1, out-of-bounds2) traditional", features: {"ss00": 0, "ss01": 0, "ss99": 0, "trad": 1} }, // out-of-bounds values but not invalid syntax 22 { prop: "font-variant", value: "styleset(ok-alt-a, ok-alt-b) historical-forms", features: {"ss01": 1, "ss02": 0, "ss03": 1, "ss04": 0, "ss05": 1, "ss19": 1, "ss20": 0, "hist": 1, "hlig": 0} }, 23 { prop: "font-variant", value: "traditional historical-forms styleset(ok-alt-a, ok-alt-b)", features: {"trad": 1, "ss01": 1, "ss02": 0, "ss03": 1, "ss04": 0, "ss05": 1, "ss19": 1, "ss20": 0, "hist": 1, "hlig": 0} }, 24 { prop: "font-variant", value: "styleset(scope-test2)", features: {"ss23": 0, "ss24": 1, "ss01": 1} }, 25 { prop: "font-variant", value: "character-variant(scope-test2)", features: {"cv23": 2, "cv24": 0, "cv01": 0} }, 26 27 // invalid values 28 { prop: "font-variant", value: "normal small-caps", features: {"smcp": 0}, invalid: true }, 29 { prop: "font-variant", value: "common-ligatures none", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 30 { prop: "font-variant", value: "none common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 31 { prop: "font-variant", value: "small-caps potato", features: {"smcp": 0}, invalid: true }, 32 { prop: "font-variant", value: "common-ligatures traditional no-common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "trad": 0}, invalid: true }, 33 { prop: "font-variant", value: "common-ligatures traditional common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "trad": 0}, invalid: true }, 34 { prop: "font-variant", value: "small-caps jis83 all-small-caps", features: {"smcp": 0, "c2sc": 0, "jp83": 0}, invalid: true }, 35 { prop: "font-variant", value: "lining-nums traditional slashed-zero ordinal normal", features: {"lnum": 0, "onum": 0, "zero": 0, "trad": 0}, invalid: true }, 36 { prop: "font-variant", value: "diagonal-fractions stacked-fractions", features: {"frac": 0, "afrc": 0}, invalid: true }, 37 { prop: "font-variant", value: "stacked-fractions diagonal-fractions historical-ligatures", features: {"frac": 0, "afrc": 0, "hlig": 0}, invalid: true }, 38 { prop: "font-variant", value: "super sub", features: {"subs": 0, "sups": 0}, invalid: true }, 39 { prop: "font-variant", value: "super historical-ligatures sub", features: {"subs": 0, "sups": 0, "hlig": 0}, invalid: true }, 40 { prop: "font-variant", value: "annotation(circled) annotation(circled)", features: {"nalt": 0, "lnum": 0, "onum": 0, "pnum": 0}, invalid: true }, 41 42 // font-variant-alternates 43 // valid values 44 { prop: "font-variant-alternates", value: "normal", features: {"salt": 0, "swsh": 0} }, 45 { prop: "font-variant-alternates", value: "historical-forms", features: {"hist": 1, "hlig": 0} }, 46 { prop: "font-variant-alternates", value: "styleset(ok-alt-a, ok-alt-b)", features: {"ss01": 1, "ss02": 0, "ss03": 1, "ss04": 0, "ss05": 1, "ss19": 1, "ss20": 0} }, 47 { prop: "font-variant-alternates", value: "styleset(ok-alt-a, ok-alt-b) historical-forms", features: {"ss01": 1, "ss02": 0, "ss03": 1, "ss04": 0, "ss05": 1, "ss19": 1, "ss20": 0, "hist": 1, "hlig": 0} }, 48 { prop: "font-variant-alternates", value: "historical-forms styleset(ok-alt-a, ok-alt-b)", features: {"ss01": 1, "ss02": 0, "ss03": 1, "ss04": 0, "ss05": 1, "ss19": 1, "ss20": 0, "hist": 1, "hlig": 0} }, 49 { prop: "font-variant-alternates", value: "character-variant(ok-1)", features: {"cv78": 2, "cv79": 0, "cv77": 0} }, 50 { prop: "font-variant-alternates", value: "character-variant(ok-1, ok-3)", features: {"cv78": 2, "cv79": 0, "cv77": 0, "cv23": 1, "cv22": 0, "cv24": 0} }, 51 { prop: "font-variant-alternates", value: "annotation(circled)", features: {"nalt": 1} }, 52 { prop: "font-variant-alternates", value: "styleset(out-of-bounds1, out-of-bounds2)", features: {"ss00": 0, "ss01": 0, "ss99": 0} }, // out-of-bounds values but not invalid syntax 53 { prop: "font-variant-alternates", value: "styleset(circled)", features: {"nalt": 0, "ss00": 0, "ss01": 0} }, // circled defined for annotation not styleset 54 { prop: "font-variant-alternates", value: "styleset(scope-test1)", features: {"ss23": 1, "ss24": 0} }, 55 { prop: "font-variant-alternates", value: "character-variant(scope-test1)", features: {"cv23": 0, "cv24": 1} }, 56 { prop: "font-variant-alternates", value: "styleset(scope-test2)", features: {"ss23": 0, "ss24": 1, "ss01": 1} }, 57 { prop: "font-variant-alternates", value: "character-variant(scope-test2)", features: {"cv23": 2, "cv24": 0, "cv01": 0} }, 58 { prop: "font-variant-alternates", value: "character-variant(overlap1, overlap2)", features: {"cv23": 2} }, 59 { prop: "font-variant-alternates", value: "character-variant(overlap2, overlap1)", features: {"cv23": 1} }, 60 61 // invalid values 62 { prop: "font-variant-alternates", value: "historical-forms normal", features: {"hist": 0}, invalid: true }, 63 { prop: "font-variant-alternates", value: "historical-forms historical-forms", features: {"hist": 0}, invalid: true }, 64 { prop: "font-variant-alternates", value: "swash", features: {"swsh": 0}, invalid: true }, 65 { prop: "font-variant-alternates", value: "swash(3)", features: {"swsh": 0}, invalid: true }, 66 { prop: "font-variant-alternates", value: "annotation(a, b)", features: {"nalt": 0}, invalid: true }, 67 { prop: "font-variant-alternates", value: "ornaments(a,b)", features: {"ornm": 0, "nalt": 0}, invalid: true }, 68 69 // font-variant-caps 70 // valid values 71 { prop: "font-variant-caps", value: "normal", features: {"smcp": 0} }, 72 { prop: "font-variant-caps", value: "small-caps", features: {"smcp": 1, "c2sc": 0} }, 73 { prop: "font-variant-caps", value: "all-small-caps", features: {"smcp": 1, "c2sc": 1, "pcap": 0} }, 74 { prop: "font-variant-caps", value: "petite-caps", features: {"pcap": 1, "smcp": 0} }, 75 { prop: "font-variant-caps", value: "all-petite-caps", features: {"c2pc": 1, "pcap": 1, "smcp": 0} }, 76 { prop: "font-variant-caps", value: "titling-caps", features: {"titl": 1, "smcp": 0} }, 77 { prop: "font-variant-caps", value: "unicase", features: {"unic": 1, "titl": 0} }, 78 79 // invalid values 80 { prop: "font-variant-caps", value: "normal small-caps", features: {"smcp": 0}, invalid: true }, 81 { prop: "font-variant-caps", value: "small-caps potato", features: {"smcp": 0}, invalid: true }, 82 { prop: "font-variant-caps", value: "small-caps petite-caps", features: {"smcp": 0, "pcap": 0}, invalid: true }, 83 { prop: "font-variant-caps", value: "small-caps all-small-caps", features: {"smcp": 0, "c2sc": 0}, invalid: true }, 84 { prop: "font-variant-caps", value: "small-cap", features: {"smcp": 0}, invalid: true }, 85 86 // font-variant-east-asian 87 // valid values 88 { prop: "font-variant-east-asian", value: "jis78", features: {"jp78": 1, "jp04": 0} }, 89 { prop: "font-variant-east-asian", value: "jis83", features: {"jp83": 1, "jp04": 0} }, 90 { prop: "font-variant-east-asian", value: "jis90", features: {"jp90": 1, "jp04": 0} }, 91 { prop: "font-variant-east-asian", value: "jis04", features: {"jp04": 1, "jp78": 0} }, 92 { prop: "font-variant-east-asian", value: "simplified", features: {"smpl": 1, "jp04": 0} }, 93 { prop: "font-variant-east-asian", value: "traditional", features: {"trad": 1, "jp04": 0} }, 94 { prop: "font-variant-east-asian", value: "full-width", features: {"fwid": 1, "jp04": 0} }, 95 { prop: "font-variant-east-asian", value: "proportional-width", features: {"pwid": 1, "jp04": 0} }, 96 { prop: "font-variant-east-asian", value: "ruby", features: {"ruby": 1, "jp04": 0} }, 97 { prop: "font-variant-east-asian", value: "jis78 full-width", features: {"jp78": 1, "fwid": 1, "jp83": 0} }, 98 { prop: "font-variant-east-asian", value: "jis78 full-width ruby", features: {"jp78": 1, "fwid": 1, "jp83": 0, "ruby": 1} }, 99 { prop: "font-variant-east-asian", value: "simplified proportional-width", features: {"smpl": 1, "pwid": 1, "jp83": 0} }, 100 { prop: "font-variant-east-asian", value: "ruby simplified", features: {"ruby": 1, "smpl": 1, "trad": 0} }, 101 102 // invalid values 103 { prop: "font-variant-east-asian", value: "ruby normal", features: {"ruby": 0}, invalid: true }, 104 { prop: "font-variant-east-asian", value: "jis90 jis04", features: {"jp90": 0, "jp04": 0}, invalid: true }, 105 { prop: "font-variant-east-asian", value: "simplified traditional", features: {"smpl": 0, "trad": 0}, invalid: true }, 106 { prop: "font-variant-east-asian", value: "full-width proportional-width", features: {"fwid": 0, "pwid": 0}, invalid: true }, 107 { prop: "font-variant-east-asian", value: "ruby simplified ruby", features: {"ruby": 0, "smpl": 0, "jp04": 0}, invalid: true }, 108 { prop: "font-variant-east-asian", value: "jis78 ruby simplified", features: {"ruby": 0, "smpl": 0, "jp78": 0}, invalid: true }, 109 110 // font-variant-ligatures 111 // valid values 112 { prop: "font-variant-ligatures", value: "none", features: {"liga": 0, "dlig": 0, "clig": 0, "calt": 0, "hlig": 0} }, 113 { prop: "font-variant-ligatures", value: "normal", features: {"liga": 1, "dlig": 0} }, 114 { prop: "font-variant-ligatures", value: "common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} }, 115 { prop: "font-variant-ligatures", value: "no-common-ligatures", features: {"liga": 0, "clig": 0, "dlig": 0, "hlig": 0, "calt": 1} }, 116 { prop: "font-variant-ligatures", value: "discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 1, "hlig": 0, "calt": 1} }, 117 { prop: "font-variant-ligatures", value: "no-discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} }, 118 { prop: "font-variant-ligatures", value: "historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 1, "calt": 1} }, 119 { prop: "font-variant-ligatures", value: "no-historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} }, 120 { prop: "font-variant-ligatures", value: "contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} }, 121 { prop: "font-variant-ligatures", value: "no-contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 0} }, 122 { prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0, "calt": 1} }, 123 { prop: "font-variant-ligatures", value: "historical-ligatures no-common-ligatures", features: {"clig": 0, "liga": 0, "dlig": 0, "hlig": 1, "calt": 1} }, 124 { prop: "font-variant-ligatures", value: "no-historical-ligatures discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 1, "hlig": 0, "calt": 1} }, 125 { prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures historical-ligatures no-contextual", features: {"clig": 1, "dlig": 0, "hlig": 1, "liga": 1, "calt": 0} }, 126 127 // invalid values 128 { prop: "font-variant-ligatures", value: "common-ligatures none", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 129 { prop: "font-variant-ligatures", value: "none common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 130 { prop: "font-variant-ligatures", value: "common-ligatures normal", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 131 { prop: "font-variant-ligatures", value: "common-ligatures no-common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 132 { prop: "font-variant-ligatures", value: "common-ligatures common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 133 { prop: "font-variant-ligatures", value: "no-historical-ligatures historical-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0}, invalid: true }, 134 { prop: "font-variant-ligatures", value: "no-contextual contextual", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0}, invalid: true }, 135 { prop: "font-variant-ligatures", value: "no-discretionary-ligatures discretionary-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 136 { prop: "font-variant-ligatures", value: "common-ligatures no-discretionary-ligatures no-common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0}, invalid: true }, 137 138 // font-variant-numeric 139 // valid values 140 { prop: "font-variant-numeric", value: "normal", features: {"lnum": 0, "tnum": 0, "pnum": 0, "onum": 0} }, 141 { prop: "font-variant-numeric", value: "lining-nums", features: {"lnum": 1, "onum": 0, "pnum": 0} }, 142 { prop: "font-variant-numeric", value: "oldstyle-nums", features: {"lnum": 0, "onum": 1, "pnum": 0} }, 143 { prop: "font-variant-numeric", value: "proportional-nums", features: {"lnum": 0, "onum": 0, "pnum": 1, "tnum": 0} }, 144 { prop: "font-variant-numeric", value: "proportional-nums oldstyle-nums", features: {"lnum": 0, "onum": 1, "pnum": 1, "tnum": 0} }, 145 { prop: "font-variant-numeric", value: "tabular-nums", features: {"tnum": 1, "onum": 0, "pnum": 0} }, 146 { prop: "font-variant-numeric", value: "diagonal-fractions", features: {"frac": 1, "afrc": 0, "pnum": 0} }, 147 { prop: "font-variant-numeric", value: "stacked-fractions", features: {"frac": 0, "afrc": 1, "pnum": 0} }, 148 { prop: "font-variant-numeric", value: "slashed-zero", features: {"zero": 1, "pnum": 0} }, 149 { prop: "font-variant-numeric", value: "ordinal", features: {"ordn": 1, "pnum": 0} }, 150 { prop: "font-variant-numeric", value: "lining-nums diagonal-fractions", features: {"frac": 1, "afrc": 0, "lnum": 1} }, 151 { prop: "font-variant-numeric", value: "tabular-nums stacked-fractions", features: {"frac": 0, "afrc": 1, "tnum": 1} }, 152 { prop: "font-variant-numeric", value: "tabular-nums slashed-zero stacked-fractions", features: {"frac": 0, "afrc": 1, "tnum": 1, "zero": 1} }, 153 { prop: "font-variant-numeric", value: "proportional-nums slashed-zero diagonal-fractions oldstyle-nums ordinal", features: {"frac": 1, "afrc": 0, "tnum": 0, "pnum": 1, "onum": 1, "ordn": 1, "zero": 1} }, 154 155 // invalid values 156 { prop: "font-variant-numeric", value: "lining-nums normal", features: {"lnum": 0, "onum": 0}, invalid: true }, 157 { prop: "font-variant-numeric", value: "lining-nums oldstyle-nums", features: {"lnum": 0, "onum": 0}, invalid: true }, 158 { prop: "font-variant-numeric", value: "lining-nums normal slashed-zero ordinal", features: {"lnum": 0, "onum": 0, "zero": 0}, invalid: true }, 159 { prop: "font-variant-numeric", value: "proportional-nums tabular-nums", features: {"pnum": 0, "tnum": 0}, invalid: true }, 160 { prop: "font-variant-numeric", value: "diagonal-fractions stacked-fractions", features: {"frac": 0, "afrc": 0}, invalid: true }, 161 { prop: "font-variant-numeric", value: "slashed-zero diagonal-fractions slashed-zero", features: {"frac": 0, "afrc": 0, "zero": 0}, invalid: true }, 162 { prop: "font-variant-numeric", value: "lining-nums slashed-zero diagonal-fractions oldstyle-nums", features: {"frac": 0, "afrc": 0, "zero": 0, "onum": 0}, invalid: true }, 163 164 // font-variant-position 165 // valid values 166 { prop: "font-variant-position", value: "normal", features: {"subs": 0, "sups": 0} }, 167 168 // note: because of fallback, can *only* test activated features here 169 { prop: "font-variant-position", value: "super", features: {"sups": 1} }, 170 { prop: "font-variant-position", value: "sub", features: {"subs": 1} }, 171 172 // invalid values 173 { prop: "font-variant-position", value: "super sub", features: {"subs": 0, "sups": 0}, invalid: true }, 174 ]; 175 176 // note: the code below requires an array "gFeatures" from : 177 // layout/reftests/fonts/gsubtest/gsubtest-features.js 178 179 // The font defines feature lookups for all OpenType features for a 180 // specific set of PUA codepoints, as listed in the gFeatures array. 181 // Using these codepoints and feature combinations, tests can be 182 // constructed to detect when certain features are enabled or not. 183 184 // return a created table containing tests for a given property 185 // 186 // Ex: { prop: "font-variant-ligatures", value: "common-ligatures", features: {"liga": 1, "clig": 1, "dlig": 0, "hlig": 0} } 187 // 188 // This means that for the property 'font-variant-ligatures' with the value 'common-ligatures', the features listed should 189 // either be explicitly enabled or disabled. 190 191 // propData is the prop/value list with corresponding feature assertions 192 // whichProp is either "all" or a specific subproperty (i.e. "font-variant-position") 193 // isRef is true when this is the reference 194 // debug outputs the prop/value pair along with the tests 195 196 // default PASS codepoint used for reference rendering 197 // need to use a PUA codepoint to avoid problems related to Freetype auto-hinting 198 const kRefCodepoint = 0xe00c; 199 200 function createFeatureTestTable(propData, whichProp, isRef, debug) 201 { 202 var table = document.createElement("table"); 203 204 if (typeof(isRef) == "undefined") { 205 isRef = false; 206 } 207 208 if (typeof(debug) == "undefined") { 209 debug = false; 210 } 211 212 var doAll = (whichProp == "all"); 213 for (var i in propData) { 214 var data = propData[i]; 215 216 if (!doAll && data.prop != whichProp) continue; 217 218 var row = document.createElement("tr"); 219 var invalid = false; 220 if ("invalid" in data) { 221 invalid = true; 222 row.className = "invalid"; 223 } 224 225 var cell = document.createElement("td"); 226 cell.className = "prop"; 227 var styledecl = gPrefix + data.prop + ": " + data.value + ";"; 228 cell.innerHTML = styledecl; 229 row.appendChild(cell); 230 if (debug) { 231 table.appendChild(row); 232 } 233 234 row = document.createElement("tr"); 235 if (invalid) { 236 row.className = "invalid"; 237 } 238 239 cell = document.createElement("td"); 240 cell.className = "features"; 241 if (!isRef) { 242 cell.style.cssText = styledecl; 243 } 244 245 for (var f in data.features) { 246 var feature = data.features[f]; 247 248 var cp, unsupported = "F".charCodeAt(0); 249 var basecp = gFeatures[f]; 250 251 if (typeof(basecp) == "undefined") { 252 cp = unsupported; 253 } else { 254 switch(feature) { 255 case 0: 256 cp = basecp; 257 break; 258 case 1: 259 cp = basecp + 1; 260 break; 261 case 2: 262 cp = basecp + 2; 263 break; 264 case 3: 265 cp = basecp + 3; 266 break; 267 default: 268 cp = basecp + 1; 269 break; 270 } 271 } 272 273 var span = document.createElement("span"); 274 var cpOut = (isRef ? kRefCodepoint : cp); 275 span.innerHTML = "&#x" + cpOut.toString(16) + ";"; 276 span.title = f + "=" + feature; 277 cell.appendChild(span); 278 } 279 row.appendChild(cell); 280 table.appendChild(row); 281 } 282 283 return table; 284 }