cff_font.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* Copyright 2012 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. import { CFFCompiler, CFFParser } from "./cff_parser.js";
  16. import { SEAC_ANALYSIS_ENABLED, type1FontGlyphMapping } from "./fonts_utils.js";
  17. import { warn } from "../shared/util.js";
  18. class CFFFont {
  19. constructor(file, properties) {
  20. this.properties = properties;
  21. const parser = new CFFParser(file, properties, SEAC_ANALYSIS_ENABLED);
  22. this.cff = parser.parse();
  23. this.cff.duplicateFirstGlyph();
  24. const compiler = new CFFCompiler(this.cff);
  25. this.seacs = this.cff.seacs;
  26. try {
  27. this.data = compiler.compile();
  28. } catch (e) {
  29. warn("Failed to compile font " + properties.loadedName);
  30. // There may have just been an issue with the compiler, set the data
  31. // anyway and hope the font loaded.
  32. this.data = file;
  33. }
  34. this._createBuiltInEncoding();
  35. }
  36. get numGlyphs() {
  37. return this.cff.charStrings.count;
  38. }
  39. getCharset() {
  40. return this.cff.charset.charset;
  41. }
  42. getGlyphMapping() {
  43. const cff = this.cff;
  44. const properties = this.properties;
  45. const { cidToGidMap, cMap } = properties;
  46. const charsets = cff.charset.charset;
  47. let charCodeToGlyphId;
  48. let glyphId;
  49. if (properties.composite) {
  50. let invCidToGidMap;
  51. if (cidToGidMap && cidToGidMap.length > 0) {
  52. invCidToGidMap = Object.create(null);
  53. for (let i = 0, ii = cidToGidMap.length; i < ii; i++) {
  54. const gid = cidToGidMap[i];
  55. if (gid !== undefined) {
  56. invCidToGidMap[gid] = i;
  57. }
  58. }
  59. }
  60. charCodeToGlyphId = Object.create(null);
  61. let charCode;
  62. if (cff.isCIDFont) {
  63. // If the font is actually a CID font then we should use the charset
  64. // to map CIDs to GIDs.
  65. for (glyphId = 0; glyphId < charsets.length; glyphId++) {
  66. const cid = charsets[glyphId];
  67. charCode = cMap.charCodeOf(cid);
  68. if (invCidToGidMap && invCidToGidMap[charCode] !== undefined) {
  69. // According to the PDF specification, see Table 117, it's not clear
  70. // that a /CIDToGIDMap should be used with any non-TrueType fonts,
  71. // however it's necessary to do so in order to fix issue 15559.
  72. //
  73. // It seems, in the CFF-case, that the /CIDToGIDMap needs to be used
  74. // "inverted" compared to the TrueType-case. Here it thus seem to be
  75. // a charCode mapping, rather than the normal CID to GID mapping.
  76. charCode = invCidToGidMap[charCode];
  77. }
  78. charCodeToGlyphId[charCode] = glyphId;
  79. }
  80. } else {
  81. // If it is NOT actually a CID font then CIDs should be mapped
  82. // directly to GIDs.
  83. for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
  84. charCode = cMap.charCodeOf(glyphId);
  85. charCodeToGlyphId[charCode] = glyphId;
  86. }
  87. }
  88. return charCodeToGlyphId;
  89. }
  90. let encoding = cff.encoding ? cff.encoding.encoding : null;
  91. if (properties.isInternalFont) {
  92. encoding = properties.defaultEncoding;
  93. }
  94. charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
  95. return charCodeToGlyphId;
  96. }
  97. hasGlyphId(id) {
  98. return this.cff.hasGlyphId(id);
  99. }
  100. /**
  101. * @private
  102. */
  103. _createBuiltInEncoding() {
  104. const { charset, encoding } = this.cff;
  105. if (!charset || !encoding) {
  106. return;
  107. }
  108. const charsets = charset.charset,
  109. encodings = encoding.encoding;
  110. const map = [];
  111. for (const charCode in encodings) {
  112. const glyphId = encodings[charCode];
  113. if (glyphId >= 0) {
  114. const glyphName = charsets[glyphId];
  115. if (glyphName) {
  116. map[charCode] = glyphName;
  117. }
  118. }
  119. }
  120. if (map.length > 0) {
  121. this.properties.builtInEncoding = map;
  122. }
  123. }
  124. }
  125. export { CFFFont };