2
0

font_renderer.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  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. Object.defineProperty(exports, "__esModule", {
  17. value: true
  18. });
  19. exports.FontRendererFactory = undefined;
  20. var _util = require('../shared/util');
  21. var _cff_parser = require('./cff_parser');
  22. var _glyphlist = require('./glyphlist');
  23. var _encodings = require('./encodings');
  24. var _stream = require('./stream');
  25. var FontRendererFactory = function FontRendererFactoryClosure() {
  26. function getLong(data, offset) {
  27. return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
  28. }
  29. function getUshort(data, offset) {
  30. return data[offset] << 8 | data[offset + 1];
  31. }
  32. function parseCmap(data, start, end) {
  33. var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) : getLong(data, start + 16);
  34. var format = getUshort(data, start + offset);
  35. var ranges, p, i;
  36. if (format === 4) {
  37. getUshort(data, start + offset + 2);
  38. var segCount = getUshort(data, start + offset + 6) >> 1;
  39. p = start + offset + 14;
  40. ranges = [];
  41. for (i = 0; i < segCount; i++, p += 2) {
  42. ranges[i] = { end: getUshort(data, p) };
  43. }
  44. p += 2;
  45. for (i = 0; i < segCount; i++, p += 2) {
  46. ranges[i].start = getUshort(data, p);
  47. }
  48. for (i = 0; i < segCount; i++, p += 2) {
  49. ranges[i].idDelta = getUshort(data, p);
  50. }
  51. for (i = 0; i < segCount; i++, p += 2) {
  52. var idOffset = getUshort(data, p);
  53. if (idOffset === 0) {
  54. continue;
  55. }
  56. ranges[i].ids = [];
  57. for (var j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
  58. ranges[i].ids[j] = getUshort(data, p + idOffset);
  59. idOffset += 2;
  60. }
  61. }
  62. return ranges;
  63. } else if (format === 12) {
  64. getLong(data, start + offset + 4);
  65. var groups = getLong(data, start + offset + 12);
  66. p = start + offset + 16;
  67. ranges = [];
  68. for (i = 0; i < groups; i++) {
  69. ranges.push({
  70. start: getLong(data, p),
  71. end: getLong(data, p + 4),
  72. idDelta: getLong(data, p + 8) - getLong(data, p)
  73. });
  74. p += 12;
  75. }
  76. return ranges;
  77. }
  78. (0, _util.error)('not supported cmap: ' + format);
  79. }
  80. function parseCff(data, start, end, seacAnalysisEnabled) {
  81. var properties = {};
  82. var parser = new _cff_parser.CFFParser(new _stream.Stream(data, start, end - start), properties, seacAnalysisEnabled);
  83. var cff = parser.parse();
  84. return {
  85. glyphs: cff.charStrings.objects,
  86. subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && cff.topDict.privateDict.subrsIndex.objects,
  87. gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
  88. };
  89. }
  90. function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
  91. var itemSize, itemDecode;
  92. if (isGlyphLocationsLong) {
  93. itemSize = 4;
  94. itemDecode = function fontItemDecodeLong(data, offset) {
  95. return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
  96. };
  97. } else {
  98. itemSize = 2;
  99. itemDecode = function fontItemDecode(data, offset) {
  100. return data[offset] << 9 | data[offset + 1] << 1;
  101. };
  102. }
  103. var glyphs = [];
  104. var startOffset = itemDecode(loca, 0);
  105. for (var j = itemSize; j < loca.length; j += itemSize) {
  106. var endOffset = itemDecode(loca, j);
  107. glyphs.push(glyf.subarray(startOffset, endOffset));
  108. startOffset = endOffset;
  109. }
  110. return glyphs;
  111. }
  112. function lookupCmap(ranges, unicode) {
  113. var code = unicode.charCodeAt(0),
  114. gid = 0;
  115. var l = 0,
  116. r = ranges.length - 1;
  117. while (l < r) {
  118. var c = l + r + 1 >> 1;
  119. if (code < ranges[c].start) {
  120. r = c - 1;
  121. } else {
  122. l = c;
  123. }
  124. }
  125. if (ranges[l].start <= code && code <= ranges[l].end) {
  126. gid = ranges[l].idDelta + (ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code) & 0xFFFF;
  127. }
  128. return {
  129. charCode: code,
  130. glyphId: gid
  131. };
  132. }
  133. function compileGlyf(code, cmds, font) {
  134. function moveTo(x, y) {
  135. cmds.push({
  136. cmd: 'moveTo',
  137. args: [x, y]
  138. });
  139. }
  140. function lineTo(x, y) {
  141. cmds.push({
  142. cmd: 'lineTo',
  143. args: [x, y]
  144. });
  145. }
  146. function quadraticCurveTo(xa, ya, x, y) {
  147. cmds.push({
  148. cmd: 'quadraticCurveTo',
  149. args: [xa, ya, x, y]
  150. });
  151. }
  152. var i = 0;
  153. var numberOfContours = (code[i] << 24 | code[i + 1] << 16) >> 16;
  154. var flags;
  155. var x = 0,
  156. y = 0;
  157. i += 10;
  158. if (numberOfContours < 0) {
  159. do {
  160. flags = code[i] << 8 | code[i + 1];
  161. var glyphIndex = code[i + 2] << 8 | code[i + 3];
  162. i += 4;
  163. var arg1, arg2;
  164. if (flags & 0x01) {
  165. arg1 = (code[i] << 24 | code[i + 1] << 16) >> 16;
  166. arg2 = (code[i + 2] << 24 | code[i + 3] << 16) >> 16;
  167. i += 4;
  168. } else {
  169. arg1 = code[i++];
  170. arg2 = code[i++];
  171. }
  172. if (flags & 0x02) {
  173. x = arg1;
  174. y = arg2;
  175. } else {
  176. x = 0;
  177. y = 0;
  178. }
  179. var scaleX = 1,
  180. scaleY = 1,
  181. scale01 = 0,
  182. scale10 = 0;
  183. if (flags & 0x08) {
  184. scaleX = scaleY = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
  185. i += 2;
  186. } else if (flags & 0x40) {
  187. scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
  188. scaleY = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824;
  189. i += 4;
  190. } else if (flags & 0x80) {
  191. scaleX = (code[i] << 24 | code[i + 1] << 16) / 1073741824;
  192. scale01 = (code[i + 2] << 24 | code[i + 3] << 16) / 1073741824;
  193. scale10 = (code[i + 4] << 24 | code[i + 5] << 16) / 1073741824;
  194. scaleY = (code[i + 6] << 24 | code[i + 7] << 16) / 1073741824;
  195. i += 8;
  196. }
  197. var subglyph = font.glyphs[glyphIndex];
  198. if (subglyph) {
  199. cmds.push({ cmd: 'save' });
  200. cmds.push({
  201. cmd: 'transform',
  202. args: [scaleX, scale01, scale10, scaleY, x, y]
  203. });
  204. compileGlyf(subglyph, cmds, font);
  205. cmds.push({ cmd: 'restore' });
  206. }
  207. } while (flags & 0x20);
  208. } else {
  209. var endPtsOfContours = [];
  210. var j, jj;
  211. for (j = 0; j < numberOfContours; j++) {
  212. endPtsOfContours.push(code[i] << 8 | code[i + 1]);
  213. i += 2;
  214. }
  215. var instructionLength = code[i] << 8 | code[i + 1];
  216. i += 2 + instructionLength;
  217. var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
  218. var points = [];
  219. while (points.length < numberOfPoints) {
  220. flags = code[i++];
  221. var repeat = 1;
  222. if (flags & 0x08) {
  223. repeat += code[i++];
  224. }
  225. while (repeat-- > 0) {
  226. points.push({ flags: flags });
  227. }
  228. }
  229. for (j = 0; j < numberOfPoints; j++) {
  230. switch (points[j].flags & 0x12) {
  231. case 0x00:
  232. x += (code[i] << 24 | code[i + 1] << 16) >> 16;
  233. i += 2;
  234. break;
  235. case 0x02:
  236. x -= code[i++];
  237. break;
  238. case 0x12:
  239. x += code[i++];
  240. break;
  241. }
  242. points[j].x = x;
  243. }
  244. for (j = 0; j < numberOfPoints; j++) {
  245. switch (points[j].flags & 0x24) {
  246. case 0x00:
  247. y += (code[i] << 24 | code[i + 1] << 16) >> 16;
  248. i += 2;
  249. break;
  250. case 0x04:
  251. y -= code[i++];
  252. break;
  253. case 0x24:
  254. y += code[i++];
  255. break;
  256. }
  257. points[j].y = y;
  258. }
  259. var startPoint = 0;
  260. for (i = 0; i < numberOfContours; i++) {
  261. var endPoint = endPtsOfContours[i];
  262. var contour = points.slice(startPoint, endPoint + 1);
  263. if (contour[0].flags & 1) {
  264. contour.push(contour[0]);
  265. } else if (contour[contour.length - 1].flags & 1) {
  266. contour.unshift(contour[contour.length - 1]);
  267. } else {
  268. var p = {
  269. flags: 1,
  270. x: (contour[0].x + contour[contour.length - 1].x) / 2,
  271. y: (contour[0].y + contour[contour.length - 1].y) / 2
  272. };
  273. contour.unshift(p);
  274. contour.push(p);
  275. }
  276. moveTo(contour[0].x, contour[0].y);
  277. for (j = 1, jj = contour.length; j < jj; j++) {
  278. if (contour[j].flags & 1) {
  279. lineTo(contour[j].x, contour[j].y);
  280. } else if (contour[j + 1].flags & 1) {
  281. quadraticCurveTo(contour[j].x, contour[j].y, contour[j + 1].x, contour[j + 1].y);
  282. j++;
  283. } else {
  284. quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2);
  285. }
  286. }
  287. startPoint = endPoint + 1;
  288. }
  289. }
  290. }
  291. function compileCharString(code, cmds, font) {
  292. var stack = [];
  293. var x = 0,
  294. y = 0;
  295. var stems = 0;
  296. function moveTo(x, y) {
  297. cmds.push({
  298. cmd: 'moveTo',
  299. args: [x, y]
  300. });
  301. }
  302. function lineTo(x, y) {
  303. cmds.push({
  304. cmd: 'lineTo',
  305. args: [x, y]
  306. });
  307. }
  308. function bezierCurveTo(x1, y1, x2, y2, x, y) {
  309. cmds.push({
  310. cmd: 'bezierCurveTo',
  311. args: [x1, y1, x2, y2, x, y]
  312. });
  313. }
  314. function parse(code) {
  315. var i = 0;
  316. while (i < code.length) {
  317. var stackClean = false;
  318. var v = code[i++];
  319. var xa, xb, ya, yb, y1, y2, y3, n, subrCode;
  320. switch (v) {
  321. case 1:
  322. stems += stack.length >> 1;
  323. stackClean = true;
  324. break;
  325. case 3:
  326. stems += stack.length >> 1;
  327. stackClean = true;
  328. break;
  329. case 4:
  330. y += stack.pop();
  331. moveTo(x, y);
  332. stackClean = true;
  333. break;
  334. case 5:
  335. while (stack.length > 0) {
  336. x += stack.shift();
  337. y += stack.shift();
  338. lineTo(x, y);
  339. }
  340. break;
  341. case 6:
  342. while (stack.length > 0) {
  343. x += stack.shift();
  344. lineTo(x, y);
  345. if (stack.length === 0) {
  346. break;
  347. }
  348. y += stack.shift();
  349. lineTo(x, y);
  350. }
  351. break;
  352. case 7:
  353. while (stack.length > 0) {
  354. y += stack.shift();
  355. lineTo(x, y);
  356. if (stack.length === 0) {
  357. break;
  358. }
  359. x += stack.shift();
  360. lineTo(x, y);
  361. }
  362. break;
  363. case 8:
  364. while (stack.length > 0) {
  365. xa = x + stack.shift();
  366. ya = y + stack.shift();
  367. xb = xa + stack.shift();
  368. yb = ya + stack.shift();
  369. x = xb + stack.shift();
  370. y = yb + stack.shift();
  371. bezierCurveTo(xa, ya, xb, yb, x, y);
  372. }
  373. break;
  374. case 10:
  375. n = stack.pop() + font.subrsBias;
  376. subrCode = font.subrs[n];
  377. if (subrCode) {
  378. parse(subrCode);
  379. }
  380. break;
  381. case 11:
  382. return;
  383. case 12:
  384. v = code[i++];
  385. switch (v) {
  386. case 34:
  387. xa = x + stack.shift();
  388. xb = xa + stack.shift();
  389. y1 = y + stack.shift();
  390. x = xb + stack.shift();
  391. bezierCurveTo(xa, y, xb, y1, x, y1);
  392. xa = x + stack.shift();
  393. xb = xa + stack.shift();
  394. x = xb + stack.shift();
  395. bezierCurveTo(xa, y1, xb, y, x, y);
  396. break;
  397. case 35:
  398. xa = x + stack.shift();
  399. ya = y + stack.shift();
  400. xb = xa + stack.shift();
  401. yb = ya + stack.shift();
  402. x = xb + stack.shift();
  403. y = yb + stack.shift();
  404. bezierCurveTo(xa, ya, xb, yb, x, y);
  405. xa = x + stack.shift();
  406. ya = y + stack.shift();
  407. xb = xa + stack.shift();
  408. yb = ya + stack.shift();
  409. x = xb + stack.shift();
  410. y = yb + stack.shift();
  411. bezierCurveTo(xa, ya, xb, yb, x, y);
  412. stack.pop();
  413. break;
  414. case 36:
  415. xa = x + stack.shift();
  416. y1 = y + stack.shift();
  417. xb = xa + stack.shift();
  418. y2 = y1 + stack.shift();
  419. x = xb + stack.shift();
  420. bezierCurveTo(xa, y1, xb, y2, x, y2);
  421. xa = x + stack.shift();
  422. xb = xa + stack.shift();
  423. y3 = y2 + stack.shift();
  424. x = xb + stack.shift();
  425. bezierCurveTo(xa, y2, xb, y3, x, y);
  426. break;
  427. case 37:
  428. var x0 = x,
  429. y0 = y;
  430. xa = x + stack.shift();
  431. ya = y + stack.shift();
  432. xb = xa + stack.shift();
  433. yb = ya + stack.shift();
  434. x = xb + stack.shift();
  435. y = yb + stack.shift();
  436. bezierCurveTo(xa, ya, xb, yb, x, y);
  437. xa = x + stack.shift();
  438. ya = y + stack.shift();
  439. xb = xa + stack.shift();
  440. yb = ya + stack.shift();
  441. x = xb;
  442. y = yb;
  443. if (Math.abs(x - x0) > Math.abs(y - y0)) {
  444. x += stack.shift();
  445. } else {
  446. y += stack.shift();
  447. }
  448. bezierCurveTo(xa, ya, xb, yb, x, y);
  449. break;
  450. default:
  451. (0, _util.error)('unknown operator: 12 ' + v);
  452. }
  453. break;
  454. case 14:
  455. if (stack.length >= 4) {
  456. var achar = stack.pop();
  457. var bchar = stack.pop();
  458. y = stack.pop();
  459. x = stack.pop();
  460. cmds.push({ cmd: 'save' });
  461. cmds.push({
  462. cmd: 'translate',
  463. args: [x, y]
  464. });
  465. var cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[achar]]));
  466. compileCharString(font.glyphs[cmap.glyphId], cmds, font);
  467. cmds.push({ cmd: 'restore' });
  468. cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]]));
  469. compileCharString(font.glyphs[cmap.glyphId], cmds, font);
  470. }
  471. return;
  472. case 18:
  473. stems += stack.length >> 1;
  474. stackClean = true;
  475. break;
  476. case 19:
  477. stems += stack.length >> 1;
  478. i += stems + 7 >> 3;
  479. stackClean = true;
  480. break;
  481. case 20:
  482. stems += stack.length >> 1;
  483. i += stems + 7 >> 3;
  484. stackClean = true;
  485. break;
  486. case 21:
  487. y += stack.pop();
  488. x += stack.pop();
  489. moveTo(x, y);
  490. stackClean = true;
  491. break;
  492. case 22:
  493. x += stack.pop();
  494. moveTo(x, y);
  495. stackClean = true;
  496. break;
  497. case 23:
  498. stems += stack.length >> 1;
  499. stackClean = true;
  500. break;
  501. case 24:
  502. while (stack.length > 2) {
  503. xa = x + stack.shift();
  504. ya = y + stack.shift();
  505. xb = xa + stack.shift();
  506. yb = ya + stack.shift();
  507. x = xb + stack.shift();
  508. y = yb + stack.shift();
  509. bezierCurveTo(xa, ya, xb, yb, x, y);
  510. }
  511. x += stack.shift();
  512. y += stack.shift();
  513. lineTo(x, y);
  514. break;
  515. case 25:
  516. while (stack.length > 6) {
  517. x += stack.shift();
  518. y += stack.shift();
  519. lineTo(x, y);
  520. }
  521. xa = x + stack.shift();
  522. ya = y + stack.shift();
  523. xb = xa + stack.shift();
  524. yb = ya + stack.shift();
  525. x = xb + stack.shift();
  526. y = yb + stack.shift();
  527. bezierCurveTo(xa, ya, xb, yb, x, y);
  528. break;
  529. case 26:
  530. if (stack.length % 2) {
  531. x += stack.shift();
  532. }
  533. while (stack.length > 0) {
  534. xa = x;
  535. ya = y + stack.shift();
  536. xb = xa + stack.shift();
  537. yb = ya + stack.shift();
  538. x = xb;
  539. y = yb + stack.shift();
  540. bezierCurveTo(xa, ya, xb, yb, x, y);
  541. }
  542. break;
  543. case 27:
  544. if (stack.length % 2) {
  545. y += stack.shift();
  546. }
  547. while (stack.length > 0) {
  548. xa = x + stack.shift();
  549. ya = y;
  550. xb = xa + stack.shift();
  551. yb = ya + stack.shift();
  552. x = xb + stack.shift();
  553. y = yb;
  554. bezierCurveTo(xa, ya, xb, yb, x, y);
  555. }
  556. break;
  557. case 28:
  558. stack.push((code[i] << 24 | code[i + 1] << 16) >> 16);
  559. i += 2;
  560. break;
  561. case 29:
  562. n = stack.pop() + font.gsubrsBias;
  563. subrCode = font.gsubrs[n];
  564. if (subrCode) {
  565. parse(subrCode);
  566. }
  567. break;
  568. case 30:
  569. while (stack.length > 0) {
  570. xa = x;
  571. ya = y + stack.shift();
  572. xb = xa + stack.shift();
  573. yb = ya + stack.shift();
  574. x = xb + stack.shift();
  575. y = yb + (stack.length === 1 ? stack.shift() : 0);
  576. bezierCurveTo(xa, ya, xb, yb, x, y);
  577. if (stack.length === 0) {
  578. break;
  579. }
  580. xa = x + stack.shift();
  581. ya = y;
  582. xb = xa + stack.shift();
  583. yb = ya + stack.shift();
  584. y = yb + stack.shift();
  585. x = xb + (stack.length === 1 ? stack.shift() : 0);
  586. bezierCurveTo(xa, ya, xb, yb, x, y);
  587. }
  588. break;
  589. case 31:
  590. while (stack.length > 0) {
  591. xa = x + stack.shift();
  592. ya = y;
  593. xb = xa + stack.shift();
  594. yb = ya + stack.shift();
  595. y = yb + stack.shift();
  596. x = xb + (stack.length === 1 ? stack.shift() : 0);
  597. bezierCurveTo(xa, ya, xb, yb, x, y);
  598. if (stack.length === 0) {
  599. break;
  600. }
  601. xa = x;
  602. ya = y + stack.shift();
  603. xb = xa + stack.shift();
  604. yb = ya + stack.shift();
  605. x = xb + stack.shift();
  606. y = yb + (stack.length === 1 ? stack.shift() : 0);
  607. bezierCurveTo(xa, ya, xb, yb, x, y);
  608. }
  609. break;
  610. default:
  611. if (v < 32) {
  612. (0, _util.error)('unknown operator: ' + v);
  613. }
  614. if (v < 247) {
  615. stack.push(v - 139);
  616. } else if (v < 251) {
  617. stack.push((v - 247) * 256 + code[i++] + 108);
  618. } else if (v < 255) {
  619. stack.push(-(v - 251) * 256 - code[i++] - 108);
  620. } else {
  621. stack.push((code[i] << 24 | code[i + 1] << 16 | code[i + 2] << 8 | code[i + 3]) / 65536);
  622. i += 4;
  623. }
  624. break;
  625. }
  626. if (stackClean) {
  627. stack.length = 0;
  628. }
  629. }
  630. }
  631. parse(code);
  632. }
  633. var noop = '';
  634. function CompiledFont(fontMatrix) {
  635. this.compiledGlyphs = Object.create(null);
  636. this.compiledCharCodeToGlyphId = Object.create(null);
  637. this.fontMatrix = fontMatrix;
  638. }
  639. CompiledFont.prototype = {
  640. getPathJs: function getPathJs(unicode) {
  641. var cmap = lookupCmap(this.cmap, unicode);
  642. var fn = this.compiledGlyphs[cmap.glyphId];
  643. if (!fn) {
  644. fn = this.compileGlyph(this.glyphs[cmap.glyphId]);
  645. this.compiledGlyphs[cmap.glyphId] = fn;
  646. }
  647. if (this.compiledCharCodeToGlyphId[cmap.charCode] === undefined) {
  648. this.compiledCharCodeToGlyphId[cmap.charCode] = cmap.glyphId;
  649. }
  650. return fn;
  651. },
  652. compileGlyph: function compileGlyph(code) {
  653. if (!code || code.length === 0 || code[0] === 14) {
  654. return noop;
  655. }
  656. var cmds = [];
  657. cmds.push({ cmd: 'save' });
  658. cmds.push({
  659. cmd: 'transform',
  660. args: this.fontMatrix.slice()
  661. });
  662. cmds.push({
  663. cmd: 'scale',
  664. args: ['size', '-size']
  665. });
  666. this.compileGlyphImpl(code, cmds);
  667. cmds.push({ cmd: 'restore' });
  668. return cmds;
  669. },
  670. compileGlyphImpl: function compileGlyphImpl() {
  671. (0, _util.error)('Children classes should implement this.');
  672. },
  673. hasBuiltPath: function hasBuiltPath(unicode) {
  674. var cmap = lookupCmap(this.cmap, unicode);
  675. return this.compiledGlyphs[cmap.glyphId] !== undefined && this.compiledCharCodeToGlyphId[cmap.charCode] !== undefined;
  676. }
  677. };
  678. function TrueTypeCompiled(glyphs, cmap, fontMatrix) {
  679. fontMatrix = fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0];
  680. CompiledFont.call(this, fontMatrix);
  681. this.glyphs = glyphs;
  682. this.cmap = cmap;
  683. }
  684. _util.Util.inherit(TrueTypeCompiled, CompiledFont, {
  685. compileGlyphImpl: function compileGlyphImpl(code, cmds) {
  686. compileGlyf(code, cmds, this);
  687. }
  688. });
  689. function Type2Compiled(cffInfo, cmap, fontMatrix, glyphNameMap) {
  690. fontMatrix = fontMatrix || [0.001, 0, 0, 0.001, 0, 0];
  691. CompiledFont.call(this, fontMatrix);
  692. this.glyphs = cffInfo.glyphs;
  693. this.gsubrs = cffInfo.gsubrs || [];
  694. this.subrs = cffInfo.subrs || [];
  695. this.cmap = cmap;
  696. this.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)();
  697. this.gsubrsBias = this.gsubrs.length < 1240 ? 107 : this.gsubrs.length < 33900 ? 1131 : 32768;
  698. this.subrsBias = this.subrs.length < 1240 ? 107 : this.subrs.length < 33900 ? 1131 : 32768;
  699. }
  700. _util.Util.inherit(Type2Compiled, CompiledFont, {
  701. compileGlyphImpl: function compileGlyphImpl(code, cmds) {
  702. compileCharString(code, cmds, this);
  703. }
  704. });
  705. return {
  706. create: function FontRendererFactory_create(font, seacAnalysisEnabled) {
  707. var data = new Uint8Array(font.data);
  708. var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
  709. var numTables = getUshort(data, 4);
  710. for (var i = 0, p = 12; i < numTables; i++, p += 16) {
  711. var tag = (0, _util.bytesToString)(data.subarray(p, p + 4));
  712. var offset = getLong(data, p + 8);
  713. var length = getLong(data, p + 12);
  714. switch (tag) {
  715. case 'cmap':
  716. cmap = parseCmap(data, offset, offset + length);
  717. break;
  718. case 'glyf':
  719. glyf = data.subarray(offset, offset + length);
  720. break;
  721. case 'loca':
  722. loca = data.subarray(offset, offset + length);
  723. break;
  724. case 'head':
  725. unitsPerEm = getUshort(data, offset + 18);
  726. indexToLocFormat = getUshort(data, offset + 50);
  727. break;
  728. case 'CFF ':
  729. cff = parseCff(data, offset, offset + length, seacAnalysisEnabled);
  730. break;
  731. }
  732. }
  733. if (glyf) {
  734. var fontMatrix = !unitsPerEm ? font.fontMatrix : [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
  735. return new TrueTypeCompiled(parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
  736. }
  737. return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
  738. }
  739. };
  740. }();
  741. exports.FontRendererFactory = FontRendererFactory;