cff_parser_spec.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /* Copyright 2017 Mozilla Foundation
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. 'use strict';
  16. var coreCFFParser = require('../../core/cff_parser.js');
  17. var coreFonts = require('../../core/fonts.js');
  18. var coreStream = require('../../core/stream.js');
  19. var CFFParser = coreCFFParser.CFFParser;
  20. var CFFIndex = coreCFFParser.CFFIndex;
  21. var CFFStrings = coreCFFParser.CFFStrings;
  22. var CFFCompiler = coreCFFParser.CFFCompiler;
  23. var SEAC_ANALYSIS_ENABLED = coreFonts.SEAC_ANALYSIS_ENABLED;
  24. var Stream = coreStream.Stream;
  25. describe('CFFParser', function () {
  26. function createWithNullProto(obj) {
  27. var result = Object.create(null);
  28. for (var i in obj) {
  29. result[i] = obj[i];
  30. }
  31. return result;
  32. }
  33. var fontData, parser, cff;
  34. beforeAll(function (done) {
  35. var exampleFont = '0100040100010101134142434445462b' + '54696d65732d526f6d616e000101011f' + 'f81b00f81c02f81d03f819041c6f000d' + 'fb3cfb6efa7cfa1605e911b8f1120003' + '01010813183030312e30303754696d65' + '7320526f6d616e54696d657300000002' + '010102030e0e7d99f92a99fb7695f773' + '8b06f79a93fc7c8c077d99f85695f75e' + '9908fb6e8cf87393f7108b09a70adf0b' + 'f78e14';
  36. var fontArr = [];
  37. for (var i = 0, ii = exampleFont.length; i < ii; i += 2) {
  38. var hex = exampleFont.substr(i, 2);
  39. fontArr.push(parseInt(hex, 16));
  40. }
  41. fontData = new Stream(fontArr);
  42. done();
  43. });
  44. afterAll(function () {
  45. fontData = null;
  46. });
  47. beforeEach(function (done) {
  48. parser = new CFFParser(fontData, {}, SEAC_ANALYSIS_ENABLED);
  49. cff = parser.parse();
  50. done();
  51. });
  52. afterEach(function (done) {
  53. parser = cff = null;
  54. done();
  55. });
  56. it('parses header', function () {
  57. var header = cff.header;
  58. expect(header.major).toEqual(1);
  59. expect(header.minor).toEqual(0);
  60. expect(header.hdrSize).toEqual(4);
  61. expect(header.offSize).toEqual(1);
  62. });
  63. it('parses name index', function () {
  64. var names = cff.names;
  65. expect(names.length).toEqual(1);
  66. expect(names[0]).toEqual('ABCDEF+Times-Roman');
  67. });
  68. it('sanitizes name index', function () {
  69. var index = new CFFIndex();
  70. index.add([
  71. '['.charCodeAt(0),
  72. 'a'.charCodeAt(0)
  73. ]);
  74. var names = parser.parseNameIndex(index);
  75. expect(names).toEqual(['_a']);
  76. index = new CFFIndex();
  77. var longName = [];
  78. for (var i = 0; i < 129; i++) {
  79. longName.push(0);
  80. }
  81. index.add(longName);
  82. names = parser.parseNameIndex(index);
  83. expect(names[0].length).toEqual(127);
  84. });
  85. it('parses string index', function () {
  86. var strings = cff.strings;
  87. expect(strings.count).toEqual(3);
  88. expect(strings.get(0)).toEqual('.notdef');
  89. expect(strings.get(391)).toEqual('001.007');
  90. });
  91. it('parses top dict', function () {
  92. var topDict = cff.topDict;
  93. expect(topDict.getByName('version')).toEqual(391);
  94. expect(topDict.getByName('FullName')).toEqual(392);
  95. expect(topDict.getByName('FamilyName')).toEqual(393);
  96. expect(topDict.getByName('Weight')).toEqual(389);
  97. expect(topDict.getByName('UniqueID')).toEqual(28416);
  98. expect(topDict.getByName('FontBBox')).toEqual([
  99. -168,
  100. -218,
  101. 1000,
  102. 898
  103. ]);
  104. expect(topDict.getByName('CharStrings')).toEqual(94);
  105. expect(topDict.getByName('Private')).toEqual([
  106. 45,
  107. 102
  108. ]);
  109. });
  110. it('refuses to add topDict key with invalid value (bug 1068432)', function () {
  111. var topDict = cff.topDict;
  112. var defaultValue = topDict.getByName('UnderlinePosition');
  113. topDict.setByKey(3075, [NaN]);
  114. expect(topDict.getByName('UnderlinePosition')).toEqual(defaultValue);
  115. });
  116. it('ignores reserved commands in parseDict, and refuses to add privateDict ' + 'keys with invalid values (bug 1308536)', function () {
  117. var bytes = new Uint8Array([
  118. 64,
  119. 39,
  120. 31,
  121. 30,
  122. 252,
  123. 114,
  124. 137,
  125. 115,
  126. 79,
  127. 30,
  128. 197,
  129. 119,
  130. 2,
  131. 99,
  132. 127,
  133. 6
  134. ]);
  135. parser.bytes = bytes;
  136. var topDict = cff.topDict;
  137. topDict.setByName('Private', [
  138. bytes.length,
  139. 0
  140. ]);
  141. var parsePrivateDict = function () {
  142. parser.parsePrivateDict(topDict);
  143. };
  144. expect(parsePrivateDict).not.toThrow();
  145. var privateDict = topDict.privateDict;
  146. expect(privateDict.getByName('BlueValues')).toBeNull();
  147. });
  148. it('parses a CharString having cntrmask', function () {
  149. var bytes = new Uint8Array([
  150. 0,
  151. 1,
  152. 1,
  153. 0,
  154. 38,
  155. 149,
  156. 149,
  157. 149,
  158. 149,
  159. 149,
  160. 149,
  161. 149,
  162. 149,
  163. 149,
  164. 149,
  165. 149,
  166. 149,
  167. 149,
  168. 149,
  169. 149,
  170. 149,
  171. 1,
  172. 149,
  173. 149,
  174. 149,
  175. 149,
  176. 149,
  177. 149,
  178. 149,
  179. 149,
  180. 149,
  181. 149,
  182. 149,
  183. 149,
  184. 149,
  185. 149,
  186. 149,
  187. 149,
  188. 3,
  189. 20,
  190. 22,
  191. 22,
  192. 14
  193. ]);
  194. parser.bytes = bytes;
  195. var charStringsIndex = parser.parseIndex(0).obj;
  196. var charStrings = parser.parseCharStrings(charStringsIndex).charStrings;
  197. expect(charStrings.count).toEqual(1);
  198. expect(charStrings.get(0).length).toEqual(38);
  199. });
  200. it('parses a CharString endchar with 4 args w/seac enabled', function () {
  201. var parser = new CFFParser(fontData, {}, true);
  202. parser.parse();
  203. var bytes = new Uint8Array([
  204. 0,
  205. 1,
  206. 1,
  207. 0,
  208. 237,
  209. 247,
  210. 22,
  211. 247,
  212. 72,
  213. 204,
  214. 247,
  215. 86,
  216. 14
  217. ]);
  218. parser.bytes = bytes;
  219. var charStringsIndex = parser.parseIndex(0).obj;
  220. var result = parser.parseCharStrings(charStringsIndex);
  221. expect(result.charStrings.count).toEqual(1);
  222. expect(result.charStrings.get(0).length).toEqual(1);
  223. expect(result.seacs.length).toEqual(1);
  224. expect(result.seacs[0].length).toEqual(4);
  225. expect(result.seacs[0][0]).toEqual(130);
  226. expect(result.seacs[0][1]).toEqual(180);
  227. expect(result.seacs[0][2]).toEqual(65);
  228. expect(result.seacs[0][3]).toEqual(194);
  229. });
  230. it('parses a CharString endchar with 4 args w/seac disabled', function () {
  231. var parser = new CFFParser(fontData, {}, false);
  232. parser.parse();
  233. var bytes = new Uint8Array([
  234. 0,
  235. 1,
  236. 1,
  237. 0,
  238. 237,
  239. 247,
  240. 22,
  241. 247,
  242. 72,
  243. 204,
  244. 247,
  245. 86,
  246. 14
  247. ]);
  248. parser.bytes = bytes;
  249. var charStringsIndex = parser.parseIndex(0).obj;
  250. var result = parser.parseCharStrings(charStringsIndex);
  251. expect(result.charStrings.count).toEqual(1);
  252. expect(result.charStrings.get(0).length).toEqual(9);
  253. expect(result.seacs.length).toEqual(0);
  254. });
  255. it('parses a CharString endchar no args', function () {
  256. var bytes = new Uint8Array([
  257. 0,
  258. 1,
  259. 1,
  260. 0,
  261. 14
  262. ]);
  263. parser.bytes = bytes;
  264. var charStringsIndex = parser.parseIndex(0).obj;
  265. var result = parser.parseCharStrings(charStringsIndex);
  266. expect(result.charStrings.count).toEqual(1);
  267. expect(result.charStrings.get(0)[0]).toEqual(14);
  268. expect(result.seacs.length).toEqual(0);
  269. });
  270. it('parses predefined charsets', function () {
  271. var charset = parser.parseCharsets(0, 0, null, true);
  272. expect(charset.predefined).toEqual(true);
  273. });
  274. it('parses charset format 0', function () {
  275. var bytes = new Uint8Array([
  276. 0x00,
  277. 0x00,
  278. 0x00,
  279. 0x00,
  280. 0x00,
  281. 0x02
  282. ]);
  283. parser.bytes = bytes;
  284. var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
  285. expect(charset.charset[1]).toEqual('exclam');
  286. charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
  287. expect(charset.charset[1]).toEqual(2);
  288. });
  289. it('parses charset format 1', function () {
  290. var bytes = new Uint8Array([
  291. 0x00,
  292. 0x00,
  293. 0x00,
  294. 0x01,
  295. 0x00,
  296. 0x08,
  297. 0x01
  298. ]);
  299. parser.bytes = bytes;
  300. var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
  301. expect(charset.charset).toEqual([
  302. '.notdef',
  303. 'quoteright',
  304. 'parenleft'
  305. ]);
  306. charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
  307. expect(charset.charset).toEqual([
  308. '.notdef',
  309. 8,
  310. 9
  311. ]);
  312. });
  313. it('parses charset format 2', function () {
  314. var bytes = new Uint8Array([
  315. 0x00,
  316. 0x00,
  317. 0x00,
  318. 0x02,
  319. 0x00,
  320. 0x08,
  321. 0x00,
  322. 0x01
  323. ]);
  324. parser.bytes = bytes;
  325. var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
  326. expect(charset.charset).toEqual([
  327. '.notdef',
  328. 'quoteright',
  329. 'parenleft'
  330. ]);
  331. charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
  332. expect(charset.charset).toEqual([
  333. '.notdef',
  334. 8,
  335. 9
  336. ]);
  337. });
  338. it('parses encoding format 0', function () {
  339. var bytes = new Uint8Array([
  340. 0x00,
  341. 0x00,
  342. 0x00,
  343. 0x01,
  344. 0x08
  345. ]);
  346. parser.bytes = bytes;
  347. var encoding = parser.parseEncoding(2, {}, new CFFStrings(), null);
  348. expect(encoding.encoding).toEqual(createWithNullProto({ 0x8: 1 }));
  349. });
  350. it('parses encoding format 1', function () {
  351. var bytes = new Uint8Array([
  352. 0x00,
  353. 0x00,
  354. 0x01,
  355. 0x01,
  356. 0x07,
  357. 0x01
  358. ]);
  359. parser.bytes = bytes;
  360. var encoding = parser.parseEncoding(2, {}, new CFFStrings(), null);
  361. expect(encoding.encoding).toEqual(createWithNullProto({
  362. 0x7: 0x01,
  363. 0x08: 0x02
  364. }));
  365. });
  366. it('parses fdselect format 0', function () {
  367. var bytes = new Uint8Array([
  368. 0x00,
  369. 0x00,
  370. 0x01
  371. ]);
  372. parser.bytes = bytes.slice();
  373. var fdSelect = parser.parseFDSelect(0, 2);
  374. expect(fdSelect.fdSelect).toEqual([
  375. 0,
  376. 1
  377. ]);
  378. expect(fdSelect.raw).toEqual(bytes);
  379. });
  380. it('parses fdselect format 3', function () {
  381. var bytes = new Uint8Array([
  382. 0x03,
  383. 0x00,
  384. 0x02,
  385. 0x00,
  386. 0x00,
  387. 0x09,
  388. 0x00,
  389. 0x02,
  390. 0x0a,
  391. 0x00,
  392. 0x04
  393. ]);
  394. parser.bytes = bytes.slice();
  395. var fdSelect = parser.parseFDSelect(0, 4);
  396. expect(fdSelect.fdSelect).toEqual([
  397. 9,
  398. 9,
  399. 0xa,
  400. 0xa
  401. ]);
  402. expect(fdSelect.raw).toEqual(bytes);
  403. });
  404. it('parses invalid fdselect format 3 (bug 1146106)', function () {
  405. var bytes = new Uint8Array([
  406. 0x03,
  407. 0x00,
  408. 0x02,
  409. 0x00,
  410. 0x01,
  411. 0x09,
  412. 0x00,
  413. 0x02,
  414. 0x0a,
  415. 0x00,
  416. 0x04
  417. ]);
  418. parser.bytes = bytes.slice();
  419. var fdSelect = parser.parseFDSelect(0, 4);
  420. expect(fdSelect.fdSelect).toEqual([
  421. 9,
  422. 9,
  423. 0xa,
  424. 0xa
  425. ]);
  426. bytes[3] = bytes[4] = 0x00;
  427. expect(fdSelect.raw).toEqual(bytes);
  428. });
  429. });
  430. describe('CFFCompiler', function () {
  431. it('encodes integers', function () {
  432. var c = new CFFCompiler();
  433. expect(c.encodeInteger(0)).toEqual([0x8b]);
  434. expect(c.encodeInteger(100)).toEqual([0xef]);
  435. expect(c.encodeInteger(-100)).toEqual([0x27]);
  436. expect(c.encodeInteger(1000)).toEqual([
  437. 0xfa,
  438. 0x7c
  439. ]);
  440. expect(c.encodeInteger(-1000)).toEqual([
  441. 0xfe,
  442. 0x7c
  443. ]);
  444. expect(c.encodeInteger(10000)).toEqual([
  445. 0x1c,
  446. 0x27,
  447. 0x10
  448. ]);
  449. expect(c.encodeInteger(-10000)).toEqual([
  450. 0x1c,
  451. 0xd8,
  452. 0xf0
  453. ]);
  454. expect(c.encodeInteger(100000)).toEqual([
  455. 0x1d,
  456. 0x00,
  457. 0x01,
  458. 0x86,
  459. 0xa0
  460. ]);
  461. expect(c.encodeInteger(-100000)).toEqual([
  462. 0x1d,
  463. 0xff,
  464. 0xfe,
  465. 0x79,
  466. 0x60
  467. ]);
  468. });
  469. it('encodes floats', function () {
  470. var c = new CFFCompiler();
  471. expect(c.encodeFloat(-2.25)).toEqual([
  472. 0x1e,
  473. 0xe2,
  474. 0xa2,
  475. 0x5f
  476. ]);
  477. expect(c.encodeFloat(5e-11)).toEqual([
  478. 0x1e,
  479. 0x5c,
  480. 0x11,
  481. 0xff
  482. ]);
  483. });
  484. });