d2b5c9b87970980829712373716cf91d2efd4574.js
1 "use strict";var assert;module.watch(require('assert'),{default(v){assert=v}},0);var hex,unhex;module.watch(require('./testutil'),{hex(v){hex=v},unhex(v){unhex=v}},1);var decode,encode,sizeOf;module.watch(require('../src/types'),{decode(v){decode=v},encode(v){encode=v},sizeOf(v){sizeOf=v}},2); 2 3 4 5 describe('types.js', function() { 6 it('can handle BYTE', function() { 7 assert.equal(hex(encode.BYTE(0xFE)), 'FE'); 8 assert.equal(sizeOf.BYTE(0xFE), 1); 9 }); 10 11 it('can handle CHAR', function() { 12 assert.equal(hex(encode.CHAR('@')), '40'); 13 assert.equal(sizeOf.CHAR('@'), 1); 14 }); 15 16 it('can handle CHARARRAY', function() { 17 assert.equal(hex(encode.CHARARRAY('A/B')), '41 2F 42'); 18 assert.equal(sizeOf.CHARARRAY('A/B'), 3); 19 }); 20 21 it('can handle USHORT', function() { 22 assert.equal(hex(encode.USHORT(0xCAFE)), 'CA FE'); 23 assert.equal(sizeOf.USHORT(0xCAFE), 2); 24 }); 25 26 it('can handle SHORT', function() { 27 assert.equal(hex(encode.USHORT(-345)), 'FE A7'); 28 assert.equal(sizeOf.SHORT(-345), 2); 29 }); 30 31 it('can handle UINT24', function() { 32 assert.equal(hex(encode.UINT24(0xABCDEF)), 'AB CD EF'); 33 assert.equal(sizeOf.UINT24(0xABCDEF), 3); 34 }); 35 36 it('can handle ULONG', function() { 37 assert.equal(hex(encode.ULONG(0xDEADBEEF)), 'DE AD BE EF'); 38 assert.equal(sizeOf.ULONG(0xDEADBEEF), 4); 39 }); 40 41 it('can handle LONG', function() { 42 assert.equal(hex(encode.LONG(-123456789)), 'F8 A4 32 EB'); 43 assert.equal(sizeOf.LONG(-123456789), 4); 44 }); 45 46 it('can handle FIXED', function() { 47 assert.equal(hex(encode.FIXED(0xBEEFCAFE)), 'BE EF CA FE'); 48 assert.equal(sizeOf.FIXED(0xBEEFCAFE), 4); 49 }); 50 51 it('can handle FWORD', function() { 52 assert.equal(hex(encode.FWORD(-8193)), 'DF FF'); 53 assert.equal(sizeOf.FWORD(-8193), 2); 54 }); 55 56 it('can handle UFWORD', function() { 57 assert.equal(hex(encode.UFWORD(0xDEED)), 'DE ED'); 58 assert.equal(sizeOf.UFWORD(0xDEED), 2); 59 }); 60 61 // FIXME: Test LONGDATETIME when it gets implemented. 62 63 it('can handle TAG', function() { 64 assert.equal(hex(encode.TAG('Font')), '46 6F 6E 74'); 65 assert.equal(sizeOf.TAG('Font'), 4); 66 }); 67 68 it('can handle Card8', function() { 69 assert.equal(hex(encode.Card8(0xFE)), 'FE'); 70 assert.equal(sizeOf.Card8(0xFE), 1); 71 }); 72 73 it('can handle Card16', function() { 74 assert.equal(hex(encode.Card16(0xCAFE)), 'CA FE'); 75 assert.equal(sizeOf.Card16(0xCAFE), 2); 76 }); 77 78 it('can handle OffSize', function() { 79 assert.equal(hex(encode.OffSize(0xFE)), 'FE'); 80 assert.equal(sizeOf.OffSize(0xFE), 1); 81 }); 82 83 it('can handle SID', function() { 84 assert.equal(hex(encode.SID(0xCAFE)), 'CA FE'); 85 assert.equal(sizeOf.SID(0xCAFE), 2); 86 }); 87 88 it('can handle NUMBER', function() { 89 assert.equal(hex(encode.NUMBER(-32769)), '1D FF FF 7F FF'); 90 assert.equal(hex(encode.NUMBER(-32768)), '1C 80 00'); 91 assert.equal(hex(encode.NUMBER(-32767)), '1C 80 01'); 92 assert.equal(hex(encode.NUMBER(-1133)), '1C FB 93'); 93 assert.equal(hex(encode.NUMBER(-1132)), '1C FB 94'); 94 assert.equal(hex(encode.NUMBER(-1131)), 'FE FF'); 95 assert.equal(hex(encode.NUMBER(-109)), 'FB 01'); 96 assert.equal(hex(encode.NUMBER(-108)), 'FB 00'); 97 assert.equal(hex(encode.NUMBER(-107)), '20'); 98 assert.equal(hex(encode.NUMBER(-106)), '21'); 99 assert.equal(hex(encode.NUMBER(0)), '8B'); 100 assert.equal(hex(encode.NUMBER(107)), 'F6'); 101 assert.equal(hex(encode.NUMBER(108)), 'F7 00'); 102 assert.equal(hex(encode.NUMBER(109)), 'F7 01'); 103 assert.equal(hex(encode.NUMBER(1131)), 'FA FF'); 104 assert.equal(hex(encode.NUMBER(1132)), '1C 04 6C'); 105 assert.equal(hex(encode.NUMBER(1133)), '1C 04 6D'); 106 assert.equal(hex(encode.NUMBER(32767)), '1C 7F FF'); 107 assert.equal(hex(encode.NUMBER(32768)), '1D 00 00 80 00'); 108 assert.equal(hex(encode.NUMBER(32769)), '1D 00 00 80 01'); 109 110 assert.equal(sizeOf.NUMBER(-32769), 5); 111 assert.equal(sizeOf.NUMBER(-32768), 3); 112 assert.equal(sizeOf.NUMBER(-32767), 3); 113 assert.equal(sizeOf.NUMBER(-1133), 3); 114 assert.equal(sizeOf.NUMBER(-1132), 3); 115 assert.equal(sizeOf.NUMBER(-1131), 2); 116 assert.equal(sizeOf.NUMBER(-109), 2); 117 assert.equal(sizeOf.NUMBER(-108), 2); 118 assert.equal(sizeOf.NUMBER(-107), 1); 119 assert.equal(sizeOf.NUMBER(-106), 1); 120 assert.equal(sizeOf.NUMBER(0), 1); 121 assert.equal(sizeOf.NUMBER(107), 1); 122 assert.equal(sizeOf.NUMBER(108), 2); 123 assert.equal(sizeOf.NUMBER(109), 2); 124 assert.equal(sizeOf.NUMBER(1131), 2); 125 assert.equal(sizeOf.NUMBER(1132), 3); 126 assert.equal(sizeOf.NUMBER(1133), 3); 127 assert.equal(sizeOf.NUMBER(32767), 3); 128 assert.equal(sizeOf.NUMBER(32768), 5); 129 assert.equal(sizeOf.NUMBER(32769), 5); 130 }); 131 132 it('can handle NUMBER16', function() { 133 assert.equal(hex(encode.NUMBER16(-32768)), '1C 80 00'); 134 assert.equal(hex(encode.NUMBER16(-1133)), '1C FB 93'); 135 assert.equal(hex(encode.NUMBER16(-108)), '1C FF 94'); 136 assert.equal(hex(encode.NUMBER16(0)), '1C 00 00'); 137 assert.equal(hex(encode.NUMBER16(108)), '1C 00 6C'); 138 assert.equal(hex(encode.NUMBER16(1133)), '1C 04 6D'); 139 assert.equal(hex(encode.NUMBER16(32767)), '1C 7F FF'); 140 141 assert.equal(sizeOf.NUMBER16(-32768), 3); 142 assert.equal(sizeOf.NUMBER16(-1133), 3); 143 assert.equal(sizeOf.NUMBER16(-108), 3); 144 assert.equal(sizeOf.NUMBER16(0), 3); 145 assert.equal(sizeOf.NUMBER16(108), 3); 146 assert.equal(sizeOf.NUMBER16(1133), 3); 147 assert.equal(sizeOf.NUMBER16(32767), 3); 148 }); 149 150 it('can handle NUMBER32', function() { 151 assert.equal(hex(encode.NUMBER32(-1)), '1D FF FF FF FF'); 152 assert.equal(hex(encode.NUMBER32(0)), '1D 00 00 00 00'); 153 assert.equal(hex(encode.NUMBER32(0xDEADBEEF)), '1D DE AD BE EF'); 154 155 assert.equal(sizeOf.NUMBER32(-1), 5); 156 assert.equal(sizeOf.NUMBER32(0), 5); 157 assert.equal(sizeOf.NUMBER32(0xDEADBEEF), 5); 158 }); 159 160 it('can handle REAL', function() { 161 // FIXME: It would be good if somebody who actually understands 162 // how REAL.encode() works could write tests for edge cases. 163 assert.equal(hex(encode.REAL(0.0)), '1E 0F'); 164 assert.equal(sizeOf.REAL(0.0), 2); 165 166 assert.equal(hex(encode.REAL(0.1)), '1E 0A 1F'); 167 assert.equal(sizeOf.REAL(0.1), 3); 168 169 assert.equal(hex(encode.REAL(99.999)), '1E 99 A9 99 FF'); 170 assert.equal(sizeOf.REAL(99.999), 5); 171 172 assert.equal(hex(encode.REAL(-123456.78)), '1E E1 23 45 6A 78 FF'); 173 assert.equal(sizeOf.REAL(-123456.78), 7); 174 }); 175 176 it('can handle NAME', function() { 177 assert.equal(hex(encode.NAME('hello')), '68 65 6C 6C 6F'); 178 assert.equal(sizeOf.NAME('hello'), 5); 179 }); 180 181 it('can handle STRING', function() { 182 assert.equal(hex(encode.STRING('hello')), '68 65 6C 6C 6F'); 183 assert.equal(sizeOf.STRING('hello'), 5); 184 }); 185 186 it('can handle UTF16', function() { 187 assert.equal(decode.UTF16(unhex('DE AD 5B 57 4F 53'), 2, 4), '字体'); 188 assert.equal(hex(encode.UTF16('字体')), '5B 57 4F 53'); 189 assert.equal(sizeOf.UTF16('字体'), 4); 190 191 // In JavaScript, characters outside the Basic Multilingual Plane 192 // are represented with surrogate pairs. For example, U+1F404 COW 193 // is stored as the surrogate pair U+D83D U+DC04. This is also 194 // exactly what we need for representing U+1F404 in UTF-16. 195 assert.equal(decode.UTF16(unhex('DE AD D8 3D DC 04'), 2, 4), '\uD83D\uDC04'); 196 assert.equal(hex(encode.UTF16('\uD83D\uDC04')), 'D8 3D DC 04'); 197 assert.equal(sizeOf.UTF16('\uD83D\uDC04'), 4); 198 }); 199 200 it('can handle MACSTRING in Central European encoding', function() { 201 const encoding = 'x-mac-ce'; 202 const data = '42 65 74 F5 74 92 70 75 73'; 203 204 assert.equal( 205 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 9, encoding), 206 'Betűtípus'); 207 208 assert.equal(hex(encode.MACSTRING('Betűtípus', encoding)), data); // not in cache 209 assert.equal(hex(encode.MACSTRING('Betűtípus', encoding)), data); // likely cached 210 assert.equal(encode.MACSTRING('Betűtípus 字体', encoding), undefined); // not encodable 211 212 assert.equal(sizeOf.MACSTRING('Betűtípus', encoding), 9); 213 assert.equal(sizeOf.MACSTRING('Betűtípus 字体', encoding), 0); 214 }); 215 216 it('can handle MACSTRING in Croatian encoding', function() { 217 const encoding = 'x-mac-croatian'; 218 const data = 'A9 74 61 6D 70 61 E8'; 219 220 assert.equal( 221 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 7, encoding), 222 'Štampač'); 223 224 assert.equal(hex(encode.MACSTRING('Štampač', encoding)), data); // not in cache 225 assert.equal(hex(encode.MACSTRING('Štampač', encoding)), data); // likely cached 226 assert.equal(encode.MACSTRING('Štampač 字体', encoding), undefined); // not encodable 227 228 assert.equal(sizeOf.MACSTRING('Štampač', encoding), 7); 229 assert.equal(sizeOf.MACSTRING('Štampač 字体', encoding), 0); 230 }); 231 232 it('can handle MACSTRING in Cyrillic encoding', function() { 233 const encoding = 'x-mac-cyrillic'; 234 const data = '98 F0 E8 F4 F2 20 46 6F 6F'; 235 236 assert.equal( 237 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 9, encoding), 238 'Шрифт Foo'); 239 240 assert.equal(hex(encode.MACSTRING('Шрифт Foo', encoding)), data); // not in cache 241 assert.equal(hex(encode.MACSTRING('Шрифт Foo', encoding)), data); // likely cached 242 assert.equal(encode.MACSTRING('Шрифт 字体', encoding), undefined); // not encodable 243 244 assert.equal(sizeOf.MACSTRING('Шрифт Foo', encoding), 9); 245 assert.equal(sizeOf.MACSTRING('Шрифт 字体', encoding), 0); 246 }); 247 248 it('can handle MACSTRING in Gaelic encoding', function() { 249 const encoding = 'x-mac-gaelic'; 250 const data = '44 9C 69 E0 B6 92'; 251 252 assert.equal( 253 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 6, encoding), 254 'Dúiṫċí'); 255 256 assert.equal(hex(encode.MACSTRING('Dúiṫċí', encoding)), data); // not in cache 257 assert.equal(hex(encode.MACSTRING('Dúiṫċí', encoding)), data); // likely cached 258 assert.equal(encode.MACSTRING('Dúiṫċí 字体', encoding), undefined); 259 260 assert.equal(sizeOf.MACSTRING('Dúiṫċí Foo', encoding), 10); 261 assert.equal(sizeOf.MACSTRING('Dúiṫċí 字体', encoding), 0); 262 }); 263 264 it('can handle MACSTRING in Greek encoding', function() { 265 const encoding = 'x-mac-greek'; 266 const data = 'A1 F2 E1 ED ED E1 F4 EF F3 E5 E9 F2 C0 20 2E 85 2E'; 267 268 assert.equal( 269 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 17, encoding), 270 'Γραμματοσειρά .Ö.'); 271 272 assert.equal(hex(encode.MACSTRING('Γραμματοσειρά .Ö.', encoding)), data); // not in cache 273 assert.equal(hex(encode.MACSTRING('Γραμματοσειρά .Ö.', encoding)), data); // likely cached 274 assert.equal(encode.MACSTRING('Γραμματοσειρά 字体', encoding), undefined); // not encodable 275 276 assert.equal(sizeOf.MACSTRING('Γραμματοσειρά .Ö.', encoding), 17); 277 assert.equal(sizeOf.MACSTRING('Γραμματοσειρά 字体', encoding), 0); 278 }); 279 280 it('can handle MACSTRING in Icelandic encoding', function() { 281 const encoding = 'x-mac-icelandic'; 282 const data = 'DE 97 72 69 73 64 97 74 74 69 72 20 DF 97 20 61 DD 8E 67'; 283 284 assert.equal( 285 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 19, encoding), 286 'Þórisdóttir þó aðég'); 287 288 assert.equal(hex(encode.MACSTRING('Þórisdóttir þó aðég', encoding)), data); // not in cache 289 assert.equal(hex(encode.MACSTRING('Þórisdóttir þó aðég', encoding)), data); // likely cached 290 assert.equal(encode.MACSTRING('Þórisdóttir 字体', encoding), undefined); // not encodable 291 292 assert.equal(sizeOf.MACSTRING('Þórisdóttir þó aðég', encoding), 19); 293 assert.equal(sizeOf.MACSTRING('Þórisdóttir 字体', encoding), 0); 294 }); 295 296 it('can handle MACSTRING in Inuit encoding', function() { 297 const encoding = 'x-mac-inuit'; 298 const data = '8A 80 8C 8B AB DA CC C6 93'; 299 300 assert.equal( 301 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 9, encoding), 302 'ᐸᐃᑉᐹᒨᕆᔾᔪᑦ'); 303 304 assert.equal(hex(encode.MACSTRING('ᐸᐃᑉᐹᒨᕆᔾᔪᑦ', encoding)), data); // not in cache 305 assert.equal(hex(encode.MACSTRING('ᐸᐃᑉᐹᒨᕆᔾᔪᑦ', encoding)), data); // likely cached 306 assert.equal(encode.MACSTRING('ᐸᐃᑉᐹᒨᕆᔾᔪᑦ 字体', encoding), undefined); 307 308 assert.equal(sizeOf.MACSTRING('ᐸᐃᑉᐹᒨᕆᔾᔪᑦ Foo', encoding), 13); 309 assert.equal(sizeOf.MACSTRING('ᐸᐃᑉᐹᒨᕆᔾᔪᑦ 字体', encoding), 0); 310 }); 311 312 it('can handle MACSTRING in Roman encoding', function() { 313 const encoding = 'macintosh'; 314 const data = '86 65 74 6C 69 62 8A 72 67'; 315 316 assert.equal( 317 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 9, encoding), 318 'Üetlibärg'); 319 320 assert.equal(hex(encode.MACSTRING('Üetlibärg', encoding)), data); // not in cache 321 assert.equal(hex(encode.MACSTRING('Üetlibärg', encoding)), data); // likely cached 322 assert.equal(encode.MACSTRING('Üetlibärg 字体', encoding), undefined); // not encodable 323 324 assert.equal(sizeOf.MACSTRING('Üetlibärg', encoding), 9); 325 assert.equal(sizeOf.MACSTRING('Üetlibärg 字体', encoding), 0); 326 }); 327 328 it('can handle MACSTRING in Romanian encoding', function() { 329 const encoding = 'x-mac-romanian'; 330 const data = '54 69 70 BE 72 69 72 65'; 331 332 assert.equal( 333 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 8, encoding), 334 'Tipărire'); 335 336 assert.equal(hex(encode.MACSTRING('Tipărire', encoding)), data); // not in cache 337 assert.equal(hex(encode.MACSTRING('Tipărire', encoding)), data); // likely cached 338 assert.equal(encode.MACSTRING('Tipărire 字体', encoding), undefined); // not encodable 339 340 assert.equal(sizeOf.MACSTRING('Tipărire', encoding), 8); 341 assert.equal(sizeOf.MACSTRING('Tipărire 字体', encoding), 0); 342 }); 343 344 it('can handle MACSTRING in Turkish encoding', function() { 345 const encoding = 'x-mac-turkish'; 346 const data = '42 61 73 DD 6C 6D DD DF'; 347 348 assert.equal( 349 decode.MACSTRING(unhex('DE AD BE EF ' + data), 4, 8, encoding), 350 'Basılmış'); 351 352 assert.equal(hex(encode.MACSTRING('Basılmış', encoding)), data); // not in cache 353 assert.equal(hex(encode.MACSTRING('Basılmış', encoding)), data); // likely cached 354 assert.equal(encode.MACSTRING('Basılmış 字体', encoding), undefined); // not encodable 355 356 assert.equal(sizeOf.MACSTRING('Basılmış', encoding), 8); 357 assert.equal(sizeOf.MACSTRING('Basılmış 字体', encoding), 0); 358 }); 359 360 it('rejects MACSTRING in unsupported encodings', function() { 361 const encoding = 'KOI8-R'; 362 assert.equal(decode.MACSTRING(unhex('41 42'), 0, 1, encoding), undefined); 363 assert.equal(encode.MACSTRING('AB', encoding), undefined); 364 assert.equal(sizeOf.MACSTRING('AB', encoding), 0); 365 }); 366 367 it('can handle INDEX', function() { 368 assert.equal(hex(encode.INDEX([])), '00 00'); 369 assert.equal(sizeOf.INDEX([]), 2); 370 371 const foo = {name: 'foo', type: 'STRING', value: 'hello'}; 372 const bar = {name: 'bar', type: 'NUMBER', value: 23}; 373 assert.equal(hex(encode.INDEX([foo, bar])), 374 '00 02 01 01 06 07 68 65 6C 6C 6F A2'); 375 assert.equal(sizeOf.INDEX([foo, bar]), 12); 376 }); 377 378 it('can handle DICT', function() { 379 assert.equal(hex(encode.DICT({})), ''); 380 assert.equal(sizeOf.DICT({}), 0); 381 382 const foo = {name: 'foo', type: 'number', value: -1131}; 383 const bar = {name: 'bar', type: 'number', value: 1131}; 384 assert.equal(hex(encode.DICT({7: foo, 42: bar})), 'FE FF 07 FA FF 2A'); 385 assert.equal(sizeOf.DICT({7: foo, 42: bar}), 6); 386 }); 387 388 it('can handle OPERATOR', function() { 389 // FIXME: Somebody who knows CFF should double-check this. 390 // Are there edge cases we should test here? 391 assert.deepEqual(encode.OPERATOR(1199), [1199]); 392 assert.deepEqual(encode.OPERATOR(1200), [12, 0]); 393 assert.deepEqual(encode.OPERATOR(2399), [12, 1199]); 394 }); 395 396 it('can handle OPERAND', function() { 397 // FIXME: Somebody who knows CFF should double-check this. 398 // Is it really the case that a SID operand becomes a single byte, 399 // even though encode.SID would return '00 A2' here? 400 assert.equal(hex(encode.OPERAND(23, 'SID')), 'A2'); 401 assert.equal(hex(encode.OPERAND(23, 'offset')), '1D 00 00 00 17'); 402 assert.equal(hex(encode.OPERAND(23, 'number')), 'A2'); 403 assert.equal(hex(encode.OPERAND(23.0, 'real')), '1E 23 FF'); 404 }); 405 406 it('can handle OP', function() { 407 assert.equal(hex(encode.OP(0x42)), '42'); 408 assert.equal(sizeOf.OP(0x42), 1); 409 }); 410 411 it('can handle CHARSTRING', function() { 412 assert.equal(hex(encode.CHARSTRING([])), ''); 413 assert.equal(sizeOf.CHARSTRING([]), 0); 414 415 // FIXME: Somebody who knows CFF should double-check this; 416 // the result seems a little short. 417 const ops = [ 418 {name: 'width', type: 'NUMBER', value: 42}, 419 {name: 'dx', type: 'NUMBER', value: 17}, 420 {name: 'dy', type: 'NUMBER', value: -23}, 421 {name: 'rlineto', type: 'OP', value: 5} 422 ]; 423 424 // Because encode.CHARSTRING uses a cache, we call it twice 425 // for testing both the uncached and the (likely) cached case. 426 assert.equal(hex(encode.CHARSTRING(ops)), 'B5 9C 74 05'); 427 assert.equal(hex(encode.CHARSTRING(ops)), 'B5 9C 74 05'); 428 assert.equal(sizeOf.CHARSTRING(ops), 4); 429 }); 430 431 it('can handle OBJECT', function() { 432 const obj = {type: 'TAG', value: 'Font'}; 433 assert.equal(hex(encode.OBJECT(obj)), '46 6F 6E 74'); 434 assert.equal(sizeOf.OBJECT(obj), 4); 435 }); 436 437 it('can handle TABLE', function() { 438 const table = { 439 fields: [ 440 {name: 'version', type: 'FIXED', value: 0x01234567}, 441 {name: 'flags', type: 'USHORT', value: 0xBEEF} 442 ] 443 }; 444 assert.equal(hex(encode.TABLE(table)), '01 23 45 67 BE EF'); 445 assert.equal(sizeOf.TABLE(table), 6); 446 }); 447 448 it('can handle subTABLEs', function() { 449 const table = { 450 fields: [ 451 {name: 'version', type: 'FIXED', value: 0x01234567}, 452 { 453 name: 'subtable', type: 'TABLE', value: { 454 fields: [ 455 {name: 'flags', type: 'USHORT', value: 0xBEEF} 456 ] 457 } 458 } 459 ] 460 }; 461 assert.equal(hex(encode.TABLE(table)), '01 23 45 67 00 06 BE EF'); 462 assert.equal(sizeOf.TABLE(table), 8); 463 }); 464 465 it('can handle deeply nested TABLEs', function() { 466 // First 58 bytes of Roboto-Black.ttf GSUB table. 467 const expected = '00 01 00 00 00 0A 00 20 00 3A ' + // header 468 '00 01 44 46 4C 54 00 08 00 04 00 00 00 00 FF FF 00 02 00 00 00 01 ' + // script list 469 '00 02 6C 69 67 61 00 0E 73 6D 63 70 00 14 00 00 00 01 00 01 00 00 00 01 00 00'; // feature list 470 471 const table = { 472 fields: [ 473 {name: 'version', type: 'FIXED', value: 0x00010000}, 474 {name: 'scriptList', type: 'TABLE'}, 475 {name: 'featureList', type: 'TABLE'}, 476 {name: 'lookupList', type: 'TABLE'} 477 ], 478 scriptList: { 479 fields: [ 480 {name: 'scriptCount', type: 'USHORT', value: 1}, 481 {name: 'scriptTag_0', type: 'TAG', value: 'DFLT'}, 482 { 483 name: 'script_0', type: 'TABLE', value: { 484 fields: [ 485 { 486 name: 'defaultLangSys', type: 'TABLE', value: { 487 fields: [ 488 {name: 'lookupOrder', type: 'USHORT', value: 0}, 489 {name: 'reqFeatureIndex', type: 'USHORT', value: 0xffff}, 490 {name: 'featureCount', type: 'USHORT', value: 2}, 491 {name: 'featureIndex_0', type: 'USHORT', value: 0}, 492 {name: 'featureIndex_1', type: 'USHORT', value: 1} 493 ] 494 } 495 }, 496 {name: 'langSysCount', type: 'USHORT', value: 0} 497 ] 498 } 499 } 500 ] 501 }, 502 featureList: { 503 fields: [ 504 {name: 'featureCount', type: 'USHORT', value: 2}, 505 {name: 'featureTag_0', type: 'TAG', value: 'liga'}, 506 { 507 name: 'feature_0', type: 'TABLE', value: { 508 fields: [ 509 {name: 'featureParams', type: 'USHORT', value: 0}, 510 {name: 'lookupCount', type: 'USHORT', value: 1}, 511 {name: 'lookupListIndex', type: 'USHORT', value: 1} 512 ] 513 } 514 }, 515 {name: 'featureTag_1', type: 'TAG', value: 'smcp'}, 516 { 517 name: 'feature_1', type: 'TABLE', value: { 518 fields: [ 519 {name: 'featureParams', type: 'USHORT', value: 0}, 520 {name: 'lookupCount', type: 'USHORT', value: 1}, 521 {name: 'lookupListIndex', type: 'USHORT', value: 0} 522 ] 523 } 524 } 525 ] 526 }, 527 lookupList: {fields: []} 528 }; 529 530 assert.equal(hex(encode.TABLE(table)), expected); 531 assert.equal(sizeOf.TABLE(table), 58); 532 }); 533 534 it('can handle RECORD', function() { 535 const table = { 536 fields: [ 537 {name: 'version', type: 'FIXED', value: 0x01234567}, 538 {name: 'record', type: 'RECORD'} 539 ] 540 }; 541 542 table.record = { 543 fields: [ 544 {name: 'flags_0', type: 'USHORT', value: 0xDEAF}, 545 {name: 'flags_1', type: 'USHORT', value: 0xCAFE} 546 ] 547 }; 548 549 assert.equal(hex(encode.TABLE(table)), '01 23 45 67 DE AF CA FE'); 550 assert.equal(sizeOf.TABLE(table), 8); 551 }); 552 553 it('can handle LITERAL', function() { 554 assert.equal(hex(encode.LITERAL([])), ''); 555 assert.equal(sizeOf.LITERAL([]), 0); 556 557 assert.equal(hex(encode.LITERAL([0xff, 0x23, 0xA7])), 'FF 23 A7'); 558 assert.equal(sizeOf.LITERAL([0xff, 0x23, 0xA7]), 3); 559 }); 560 561 it('can encode VARDELTAS', function() { 562 const e = function (deltas) { 563 return hex(encode.VARDELTAS(deltas)); 564 }; 565 assert.equal(e([]), ''); 566 567 // zeroes 568 assert.equal(e([0]), '80'); 569 assert.equal(e(new Array(64).fill(0)), 'BF'); 570 assert.equal(e(new Array(65).fill(0)), 'BF 80'); 571 assert.equal(e(new Array(100).fill(0)), 'BF A3'); 572 assert.equal(e(new Array(256).fill(0)), 'BF BF BF BF'); 573 574 // bytes 575 assert.equal(e([1]), '00 01'); 576 assert.equal(e([1, 2, 3, 127, -128, -1, -2]), '06 01 02 03 7F 80 FF FE'); 577 assert.equal(e(new Array(64).fill(127)), 578 '3F ' + (new Array(64).fill('7F')).join(' ')); 579 assert.equal(e(new Array(65).fill(127)), 580 '3F ' + (new Array(64).fill('7F')).join(' ') + ' 00 7F'); 581 582 // words 583 assert.equal(e([0x6666]), '40 66 66'); 584 assert.equal(e([0x6666, 32767, -1, -32768]), '43 66 66 7F FF FF FF 80 00'); 585 assert.equal(e(new Array(64).fill(0x1122)), 586 '7F ' + (new Array(64).fill('11 22')).join(' ')); 587 assert.equal(e(new Array(65).fill(0x1122)), 588 '7F ' + (new Array(64).fill('11 22')).join(' ') + ' 40 11 22'); 589 590 // bytes, zeroes 591 assert.equal(e([1, 0]), '01 01 00'); 592 assert.equal(e([1, 0, 0]), '00 01 81'); 593 594 // bytes, zeroes, bytes: 595 // a single zero is more compact when encoded within the bytes run 596 assert.equal(e([127, 127, 0, 127, 127]), '04 7F 7F 00 7F 7F'); 597 // multiple zeroes are more compact when encoded into their own run 598 assert.equal(e([127, 127, 0, 0, 127, 127]), '01 7F 7F 81 01 7F 7F'); 599 assert.equal(e([127, 127, 0, 0, 0, 127, 127]), '01 7F 7F 82 01 7F 7F'); 600 assert.equal(e([127, 127, 0, 0, 0, 0, 127, 127]), '01 7F 7F 83 01 7F 7F'); 601 602 // words, zeroes 603 assert.equal(e([0x6789, 0]), '40 67 89 80'); 604 assert.equal(e([0x6666, 0, 0]), '40 66 66 81'); 605 606 // words, zeroes, bytes 607 assert.equal(e([0x6666, 0, 1, 2, 3]), '40 66 66 80 02 01 02 03'); 608 assert.equal(e([0x6666, 0, 0, 1, 2, 3]), '40 66 66 81 02 01 02 03'); 609 assert.equal(e([0x6666, 0, 0, 0, 1, 2, 3]), '40 66 66 82 02 01 02 03'); 610 611 // words, zeroes, words 612 assert.equal(e([0x6666, 0, 0x7777]), '40 66 66 80 40 77 77'); 613 assert.equal(e([0x6666, 0, 0, 0x7777]), '40 66 66 81 40 77 77'); 614 assert.equal(e([0x6666, 0, 0, 0, 0x7777]), '40 66 66 82 40 77 77'); 615 616 // words, bytes, words: 617 // a single byte-encodable word is more compact when encoded within the words run 618 assert.equal(e([0x6666, 2, 0x7777]), '42 66 66 00 02 77 77'); 619 // multiple byte-encodable words are more compacted when forming their own run 620 assert.equal(e([0x6666, 2, 2, 0x7777]), '40 66 66 01 02 02 40 77 77'); 621 }); 622 });