font_renderer.js 24 KB

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