You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2066 lines
65 KiB

1 month ago
  1. % Copyright (C) 2001-2023 Artifex Software, Inc.
  2. % All Rights Reserved.
  3. %
  4. % This software is provided AS-IS with no warranty, either express or
  5. % implied.
  6. %
  7. % This software is distributed under license and may not be copied,
  8. % modified or distributed except as expressly authorized under the terms
  9. % of the license contained in the file LICENSE in this distribution.
  10. %
  11. % Refer to licensing information at http://www.artifex.com or contact
  12. % Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  13. % CA 94129, USA, for further information.
  14. %
  15. % Support code for direct use of TrueType fonts.
  16. % (Not needed for Type 42 fonts.)
  17. % Note that if you want to use this file without including the ttfont.dev
  18. % option when you built Ghostscript, you will need to load the following
  19. % files before this one:
  20. % lib/gs_mgl_e.ps
  21. % lib/gs_mro_e.ps
  22. % lib/gs_wan_e.ps
  23. % Thanks to B. Jackowski and GUST (the Polish TeX Users' Group) for
  24. % the glyf-splitting code.
  25. % ---------------- Font loading machinery ---------------- %
  26. % Augment the FONTPATH machinery so it recognizes TrueType fonts.
  27. /.scanfontheaders where {
  28. /.scanfontheaders [
  29. /.scanfontheaders .systemvar aload pop (\000\001\000\000*) (true*) (wOFF*)
  30. ] put
  31. } if
  32. % ---------------- Automatic Type 42 generation ---------------- %
  33. % Load a TrueType font from a file as a Type 42 PostScript font.
  34. % The thing that makes this really messy is the handling of encodings.
  35. % There are 2 interacting tables that affect the encoding:
  36. % 'cmap' provides multiple maps from character codes to glyph indices
  37. % 'post' maps glyph indices to glyph names (if present)
  38. % What we need to get out of this is:
  39. % Encoding mapping character codes to glyph names
  40. % (the composition of cmap and post)
  41. % CharStrings mapping glyph names to glyph indices
  42. % (the inverse of post)
  43. % If the post table is missing, we have to take a guess based on the cmap
  44. % table.
  45. /.loadttfontdict 50 dict dup begin
  46. /orgXUID AladdinEnterprisesXUID def
  47. /maxstring 32764 def % half the maximum length of a PostScript string,
  48. % must be a multiple of 4 (for hmtx / loca / vmtx)
  49. /.invert_encoding % <array> invert_encoding <dict>
  50. { dup 256 dict exch
  51. 0 exch 1 exch length 1 sub { % [] <> i
  52. dup 3 index exch get % [] <> i v
  53. dup /.notdef ne {
  54. exch 2 index 2 index .knownget {
  55. dup type /arraytype eq {
  56. [ exch aload pop counttomark 2 add -1 roll ]
  57. } {
  58. exch 2 array astore
  59. } ifelse
  60. } if 2 index 3 1 roll put
  61. } {
  62. pop pop
  63. } ifelse
  64. } for
  65. exch pop
  66. } .forcebind def
  67. % Make /MacRomanEncodingForTrueType including additional
  68. % characters in Mac OS Roman encoding, which is missing
  69. % in /MacRomanEncoding. See PDF spec 1.7, p. 431 or
  70. % "Inside Macintosh: Text" 1-55, Figure 1-36.
  71. % This is useful to exploit the glyphs via Apple Roman
  72. % TrueType cmap subtable, but not appropriate for information
  73. % interchange.
  74. /MacRomanEncodingForTrueType
  75. /MacRomanEncoding .findencoding
  76. dup length array copy
  77. <<
  78. /notequal 173
  79. /infinity 176
  80. /lessequal 178
  81. /greaterequal 179
  82. /partialdiff 182
  83. /summation 183
  84. /product 184
  85. /pi 185
  86. /integral 186
  87. /Omega 189
  88. /radical 195
  89. /approxequal 197
  90. /Delta 198
  91. /lozenge 215
  92. /Euro 219
  93. /apple 240
  94. >> {
  95. TTFDEBUG { (Extend MacRomanEncodingForTrueType for TrueType: ) =only } if
  96. % check /.notdef to avoid overwriting
  97. 2 index 1 index get dup /.notdef eq {
  98. TTFDEBUG { (insert /) =only 2 index =only ( @ ) =only 1 index //== exec } if
  99. pop
  100. exch 2 index 3 1 roll put
  101. } {
  102. TTFDEBUG { (cannot insert /) =only 2 index =only ( @ ) =only 1 index =only ( used for ) =only dup //== exec } if
  103. pop
  104. pop pop
  105. } ifelse
  106. } forall
  107. aload pop
  108. 256 packedarray
  109. 5 1 index .registerencoding
  110. .defineencoding
  111. % Define the Macintosh standard mapping from characters to glyph indices.
  112. /MacRomanEncoding dup .findencoding def
  113. /MacGlyphEncoding dup .findencoding def
  114. /MacRomanEncodingForTrueType dup .findencoding def
  115. % Invert the MacRomanEncoding.
  116. /.romanmacdict MacRomanEncodingForTrueType .invert_encoding def
  117. /.latin1isodict ISOLatin1Encoding .invert_encoding def
  118. % Define remapping for misnamed glyphs in TrueType 'post' tables.
  119. % There are probably a lot more than this!
  120. /postremap mark
  121. /Eoverdot /Edotaccent
  122. /eoverdot /edotaccent
  123. .dicttomark readonly def
  124. % Array used for fast pre-filling of cmap array
  125. /.array1024z [ 1024 { 0 } repeat ] def
  126. % ---- Utilities ---- %
  127. % Define a serial number for creating unique XUIDs for TrueType fonts.
  128. % We used to use the checkSumAdjustment value from the font, but this is
  129. % not reliable, since some fonts don't set it correctly.
  130. % Note that we must do this in a string to make it immune to save/restore.
  131. % handle 64 bit integer objects
  132. /xuidstring 16#ffffffff 0 gt
  133. {
  134. <8000000000000000>
  135. }
  136. {
  137. <80000000>
  138. } ifelse def
  139. /curxuid { % - curxuid <int>
  140. //.getCPSImode
  141. //false //.setCPSImode
  142. 0 xuidstring { exch 8 bitshift exch add } forall
  143. % for tbe benefit of pdfwrite/ps2write we want the resulting XUID contents
  144. % to fit into a 32 bit value
  145. 16#ffffffff 0 gt
  146. {
  147. 16#ffffffff idiv
  148. } if
  149. exch //.setCPSImode
  150. } .forcebind def
  151. /nextxuid { % - nextxuid -
  152. 3 -1 0 {
  153. xuidstring 1 index 2 copy get dup 255 ne {
  154. 1 add put pop exit
  155. } if pop 0 put pop
  156. } for
  157. } .internalbind def
  158. % <string> <index> getu16 <integer>
  159. /getu16 {
  160. 2 copy get 8 bitshift 3 1 roll 1 add get add
  161. } .forcebind def
  162. % <string> <index> gets16 <integer>
  163. /gets16 {
  164. getu16 16#8000 xor 16#8000 sub
  165. } .forcebind def
  166. % <string> <index> getu32 <integer>
  167. /getu32 {
  168. 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
  169. } .forcebind def
  170. % <string> <index> gets32 <integer>
  171. /gets32 {
  172. 2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
  173. } .bind def
  174. % <string|array> <index> getu16 <integer>
  175. /getu16a {
  176. 2 getinterval_from_stringarray 0 getu16
  177. } .forcebind def
  178. % <string|array> <index> gets16 <integer>
  179. /gets16a {
  180. 2 getinterval_from_stringarray 0 gets16
  181. } .forcebind def
  182. % <string|array> <index> getu32a <integer>
  183. /getu32a {
  184. 4 getinterval_from_stringarray 0 getu32
  185. } .forcebind def
  186. % <string|array> <index> gets32a <integer>
  187. /gets32a {
  188. 4 getinterval_from_stringarray 0 gets32
  189. } .bind def
  190. 16#ffffffff 0 gt { % 64-bit sign extension
  191. { /gets32 /gets32a} {
  192. mark 1 index load aload pop { 16#80000000 xor 16#80000000 sub } aload pop
  193. //.packtomark exec cvx def
  194. } .bind forall
  195. } if
  196. % <string> <index> <integer> putu16 -
  197. /putu16 {
  198. 3 copy -8 bitshift put
  199. exch 1 add exch 16#ff and put
  200. } .forcebind def
  201. % <string> <index> <integer> putu32 -
  202. /putu32 {
  203. 3 copy -16 bitshift putu16
  204. exch 2 add exch 16#ffff and putu16
  205. } .forcebind def
  206. % <nametable> <nameid> findname <string> true
  207. % <nametable> <nameid> findname false
  208. /findname {
  209. TTFDEBUG { (findname: ) print dup =only } if
  210. [ //false 4 2 roll
  211. {
  212. 0 1 3 index 2 getu16 1 sub {
  213. % Stack: false table id index
  214. 12 mul 6 add 2 index exch 12
  215. % Check the table is actually long enough to contain the requested index
  216. 1 index add 2 index length gt
  217. {
  218. /pdfformaterror where
  219. {
  220. ( **** TrueType font has malformed name table.\n) exch /pdfformaterror get exec
  221. PDFSTOPONERROR {
  222. /.loadpdfttfont cvx /invalidfont signalerror
  223. } if
  224. } if
  225. pop pop
  226. exit
  227. } if
  228. 12 getinterval
  229. dup 6 getu16 2 index eq 1 index 8 getu16 0 ne and {
  230. % We found the name we want.
  231. exch pop
  232. % Stack: false table record
  233. dup 10 getu16 2 index 4 getu16 add
  234. 1 index 8 getu16 4 -1 roll 3 1 roll
  235. 3 copy add 1 index length
  236. le {
  237. pop
  238. getinterval exch
  239. % Stack: false string record
  240. % Check for 8- vs. 16-bit characters.
  241. is2byte { //true } { dup is2byte2 } ifelse { string2to1 } if //true //null 4 -1 roll exit
  242. } {
  243. pop pop pop pop
  244. //false
  245. exit
  246. } ifelse
  247. } if pop
  248. } for
  249. } stopped {
  250. cleartomark //false
  251. } {
  252. pop pop
  253. counttomark 1 add -1 roll pop
  254. } ifelse
  255. TTFDEBUG {
  256. dup { ( = ) print 1 index //== exec } { ( not found) = } ifelse
  257. } if
  258. } .forcebind def
  259. % <namerecord> is2byte <bool>
  260. /is2byte {
  261. dup 0 getu16
  262. {
  263. { pop //true } % Apple Unicode
  264. { pop //false } % Macintosh Script manager
  265. { 1 getu16 1 eq } % ISO
  266. { 1 getu16 1 eq } % Microsoft
  267. { pop //false } % default - *MUST* be last
  268. }
  269. % check for a valid Platform ID, if we don't get one, assume single byte encoding
  270. dup length 1 sub
  271. 2 index lt {exch pop dup length 1 sub}{exch} ifelse
  272. get exec
  273. } .forcebind def
  274. % <string> is2byte2 <bool>
  275. /is2byte2 {
  276. dup length
  277. dup 2 mod 0 ne {
  278. pop pop //false
  279. } { % s l
  280. //true exch % s b l
  281. 1 sub 0 exch 2 exch {
  282. 2 index exch get 0 ne {
  283. pop //false exit
  284. } if
  285. } for
  286. exch pop
  287. } ifelse
  288. } .forcebind def
  289. % <string2> string2to1 <string>
  290. /string2to1 {
  291. dup length 2 idiv string dup
  292. 0 1 3 index length 1 sub {
  293. 3 index 1 index 2 mul 1 add get put dup
  294. } for pop exch pop
  295. } .forcebind def
  296. % Each procedure in this dictionary is called as follows:
  297. % <encodingtable> proc <glyph dictionary>
  298. /cmapformats mark
  299. 0 { % Apple standard 1-to-1 mapping.
  300. 6 256 getinterval_from_stringarray
  301. mark 0 3 -1 roll
  302. { 1 index 1 add } forall pop
  303. .dicttomark
  304. } .forcebind
  305. 2 { % Apple 16bit CJK (ShiftJIS etc)
  306. % /sHK_sz subHeaderKey_size % 1 * uint16
  307. % /sH_sz subHeader_size % 4 * uint16
  308. % /sH_len subHeader_length
  309. % /cmapf2_tblen total table length
  310. % /cmapf2_lang language code (not used)
  311. % /sHKs subHeaderKeys
  312. /sHK_sz 2 def
  313. /sH_sz 8 def
  314. dup 2 getu16a /cmapf2_tblen exch def
  315. dup 4 getu16a /cmapf2_lang exch def
  316. dup 6 256 sHK_sz mul getinterval_from_stringarray /sHKs exch def
  317. 0 % initialization value for /sH_len
  318. 0 1 255 {
  319. sHKs exch
  320. 2 mul getu16a
  321. 1 index % get current max
  322. 1 index % get current subHeaderKey
  323. lt {exch} if pop
  324. } for
  325. /sH_len exch def
  326. dup 6 256 sHK_sz mul add
  327. cmapf2_tblen 1 index sub getinterval_from_stringarray
  328. /sH_gIA exch def
  329. /cmapf2_glyph_array 0 dict def
  330. /.cmapf2_putGID {
  331. /cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def
  332. firstCode cmapf2_ch_lo le
  333. cmapf2_ch_lo firstCode entryCount add lt
  334. and { % true: j is inside
  335. sH_offset idRangeOffset add % offset to gI
  336. cmapf2_ch_lo firstCode sub 2 mul % rel. pos. in range
  337. add 6 add % offset in sH_gIA
  338. sH_gIA exch getu16a
  339. dup 0 gt { %
  340. idDelta add
  341. cmapf2_glyph_array exch cmapf2_ch exch put
  342. } {
  343. pop
  344. % cmapf2_glyph_array cmapf2_ch 0 put
  345. } ifelse
  346. } { % false: j is outside
  347. % cmapf2_glyph_array cmapf2_ch 0 put
  348. } ifelse
  349. } def
  350. 16#00 1 16#ff { % hi_byte scan
  351. /cmapf2_ch_hi exch def
  352. sHKs cmapf2_ch_hi sHK_sz mul getu16a
  353. /sH_offset exch def
  354. sH_gIA sH_offset sH_sz getinterval
  355. dup 0 getu16a /firstCode exch def
  356. dup 2 getu16a /entryCount exch def
  357. dup 4 gets16a /idDelta exch def
  358. dup 6 getu16a /idRangeOffset exch def
  359. pop
  360. sH_offset 0 eq {
  361. /cmapf2_ch_lo cmapf2_ch_hi def
  362. /cmapf2_ch_hi 0 def
  363. .cmapf2_putGID
  364. } {
  365. 16#00 1 16#ff { % lo_byte scan
  366. /cmapf2_ch_lo exch def
  367. .cmapf2_putGID
  368. } for
  369. } ifelse
  370. } for
  371. pop
  372. cmapf2_glyph_array
  373. } .forcebind
  374. 4 { % Microsoft/Adobe segmented mapping.
  375. /etab exch def
  376. /nseg2 etab 6 getu16a def
  377. 14 /endc etab 2 index nseg2 getinterval_from_stringarray def
  378. % The Apple TrueType documentation omits the 2-byte
  379. % 'reserved pad' that follows the endCount vector!
  380. 2 add
  381. nseg2 add /startc etab 2 index nseg2 getinterval_from_stringarray def
  382. nseg2 add /iddelta etab 2 index nseg2 getinterval_from_stringarray def
  383. nseg2 add /idroff etab 2 index nseg2 getinterval_from_stringarray def
  384. % The following hack allows us to properly handle
  385. % idiosyncratic fonts that start at 0xf000:
  386. pop
  387. /firstcode startc 0 getu16a 16#ff00 and dup 16#f000 ne { pop 0 } if def
  388. /putglyph {
  389. glyphs code known
  390. {
  391. glyphs /.cmap_warning_issued known not {
  392. (**** Warning: Invalid TTF cmap mapping (overlapping/repeated map)\n) print flush
  393. glyphs /.cmap_warning_issued //true put
  394. } if
  395. pop
  396. }
  397. {glyphs code 3 -1 roll put}ifelse
  398. /code code 1 add def
  399. } bind def
  400. /glyphs 0 dict def
  401. % neg2 is number of segments x 2. A format 4 cmap, with usable
  402. % mappings cannot (according to the spec) have only 1 segment,
  403. % since format 4 requires a closing segment with start and end
  404. % codes being 0xffff. Unfortunately, we have found badly subsetted
  405. % TTF fonts which have one segment with valid mappings, and no
  406. % closing segment.
  407. % In such a case, force the loop to work as though as we have two
  408. % segments - this works as we don't rely on the terminating segment
  409. % but use the loop counter to spot completion - effrectively, we
  410. % ignore the closing segment when it's present, anyway.
  411. %
  412. % This loop and/or putglyph do not account for out of spec fonts
  413. % that have repeated or overlapping ranges in the segments. As we
  414. % write the code/gid to a PS dictionary, later encounters with a
  415. % given code will overwrite the earlier one(s). As this is outside
  416. % of the spec, it's not clear how other consumers handle this
  417. % condition, so we'll await a suitable example before making changes.
  418. % Two choices are: drop later repeated/overlapping segments entirely,
  419. % or only use codes from later, overlapping segments not already set
  420. % by the earlier segment. (Inspired by Bug 700968).
  421. % Revision: bug 703589 has an (invalid) cmap table with overlapping
  422. % (actually repeating) ranges, and requires the *first* range definition
  423. % to be used in order to render correctly. So /putglyph now refuses to
  424. % overwrite existing keys in the "glyphs" dictionary
  425. 0 2 nseg2 dup 4 lt {pop 4}if 3 sub {
  426. /i2 exch def
  427. /scode startc i2 getu16a def
  428. /ecode endc i2 getu16a def
  429. % Bug 693538: see above
  430. scode 0 eq ecode 0 eq and not {
  431. scode ecode 1 add gt { /ecode scode 1 add def } if % Bug 691326. See above.
  432. /code scode def
  433. /delta iddelta i2 gets16a def
  434. TTFDEBUG {
  435. (scode=) print scode =only
  436. ( ecode=) print ecode =only
  437. ( delta=) print delta =only
  438. ( droff=) print idroff i2 getu16 =
  439. } if
  440. idroff i2 getu16a dup 0 eq {
  441. pop scode delta add 65535 and 1 ecode delta add 65535 and
  442. { putglyph } for
  443. } { % The +2 is for the 'reserved pad'.
  444. /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
  445. 0 1 ecode scode sub {
  446. 2 mul gloff add etab exch getu16a
  447. dup 0 ne { delta add 65535 and } if putglyph
  448. } for
  449. } ifelse
  450. } if
  451. } for
  452. % If we've encoutered an invalid table, remove the key before returning
  453. glyphs /.cmap_warning_issued undef
  454. glyphs /glyphs //null def % for GC
  455. } .forcebind
  456. 6 { % Single interval lookup.
  457. dup 6 getu16a /firstcode exch def
  458. dup 8 getu16a /ng exch def
  459. ng dict
  460. dup
  461. % Stack: tab dict dict
  462. % Fill elements firstcode .. firstcode+nvalue-1 with glyph values
  463. 0 1 ng 1 sub {
  464. dup firstcode add exch
  465. 2 mul 10 add 4 index exch getu16a 3 copy put pop pop
  466. } for pop exch pop
  467. } .forcebind
  468. 12 { % Microsoft/Adobe segmented mapping.
  469. /etab exch def
  470. /glyphs 0 dict def
  471. 0 1
  472. etab 12 getu32a % nGroups
  473. 1 sub {
  474. /ind exch def
  475. /gid etab 12 ind mul 8 add 16 add getu32a def % startGlyphID
  476. etab 12 ind mul 16 add getu32a % startCharCode
  477. 1
  478. etab 12 ind mul 4 add 16 add getu32a % endCharCode
  479. {
  480. gid glyphs 3 1 roll put
  481. /gid gid 1 add def
  482. } for
  483. } for
  484. glyphs /glyphs //null def % for GC
  485. } .forcebind
  486. .dicttomark readonly def % cmapformats
  487. % <cmaptab> cmapdict <glyph dictionary>
  488. /cmapdict {
  489. dup 0 getu16a cmapformats exch .knownget {
  490. TTFDEBUG {
  491. (cmap: format ) print 1 index 0 getu16a = flush
  492. } if exec
  493. } {
  494. (Can't handle format ) print 0 getu16a = flush
  495. mark 0 1 255 { dup } for .dicttomark
  496. } ifelse
  497. TTFDEBUG {
  498. (cmap: length=) print dup length = dup ===
  499. } if
  500. } .forcebind def
  501. /get_from_stringarray % <array|string> <offset> get_from_stringarray <int>
  502. { 1 index type /stringtype eq {
  503. get
  504. } {
  505. exch { % o ()
  506. 2 copy length ge {
  507. length sub
  508. } {
  509. exch get exit
  510. } ifelse
  511. } forall
  512. } ifelse
  513. } .forcebind def
  514. /getinterval_from_stringarray % <array|string> <offset> <length> getinterval_from_stringarray <string>
  515. { % May allocate a string in VM.
  516. 2 index type /stringtype eq {
  517. getinterval
  518. } {
  519. dup 65535 le {
  520. string exch 0 % [] s o p
  521. 4 3 roll { % s o p Si
  522. dup length % s o p Si lSi
  523. dup 4 index lt {
  524. 3 index exch sub % s o p Si o'
  525. exch pop 3 1 roll exch pop % s o' p
  526. } { % s o p Si lSi
  527. dup 3 1 roll % s o p lSi Si lSi
  528. 4 index sub % s o p lSi Si lSi-o
  529. 5 index length 4 index sub % s o p lSi Si lSi-o ls-p
  530. 2 copy gt { exch } if pop % s o p lSi Si minl
  531. dup 3 1 roll % s o p lSi minl Si minl
  532. 5 index exch getinterval % s o p lSi minl from
  533. 5 index 4 index 3 index % s o p lSi minl from s p minl
  534. getinterval % s o p lSi minl from to
  535. copy pop % s o p lSi minl
  536. exch pop add exch pop 0 exch % s 0 p'
  537. dup 3 index length ge { exit } if
  538. } ifelse
  539. } forall
  540. pop pop % s
  541. } {
  542. [ 4 1 roll
  543. {
  544. dup 0 eq {
  545. pop pop pop exit
  546. } if
  547. 3 copy
  548. dup 65535 ge {
  549. pop 65535
  550. } if
  551. getinterval_from_stringarray 4 1 roll
  552. 3 index length sub
  553. exch
  554. 3 index length add
  555. exch
  556. } loop
  557. ]
  558. } ifelse
  559. } ifelse
  560. } .forcebind def
  561. /string_array_size % <array|string> string_array_size <int>
  562. { dup type /stringtype eq {
  563. length
  564. } {
  565. 0 exch { length add } forall
  566. } ifelse
  567. } .forcebind def
  568. % Each procedure in this dictionary is called as follows:
  569. % posttable <<proc>> glyphencoding
  570. /postformats mark
  571. 16#00010000 { % 258 standard Macintosh glyphs.
  572. pop MacGlyphEncoding
  573. }
  574. 16#00020000 { % Detailed map, required by Microsoft fonts.
  575. dup dup type /arraytype eq { 0 get } if length 36 lt {
  576. TTFDEBUG { (post format 2.0 invalid.) = flush } if
  577. pop [ ]
  578. } {
  579. /postglyphs exch def
  580. /post_first postglyphs dup type /arraytype eq { 0 get } if def
  581. post_first 32 getu16 /numglyphs exch def
  582. % Build names array in the order they occur in the 'post' table
  583. /postpos numglyphs 2 mul 34 add def
  584. /total_length postglyphs //string_array_size exec def
  585. % the number of names in a post table is not declared up front
  586. % and there are fonts with more names than glyph indices <sigh>
  587. % so we have to pre-process and find the highest index used.
  588. % We start with a base value of numglyphs as it's most common,
  589. % and we can safely have a array that's too large.
  590. % Rather than parse out the indices twice, we store them in an
  591. % array on the stack, which we then reuse, overwriting entries
  592. % as we go later on.
  593. numglyphs array numglyphs postglyphs
  594. 0 1 numglyphs 1 sub {
  595. dup 2 mul 34 add 2 index exch 2 //getinterval_from_stringarray exec
  596. dup 0 get 8 bitshift exch 1 get add
  597. dup 5 index exch
  598. 4 -1 roll exch put
  599. 258 sub dup 3 index gt
  600. % if we find a reference to an index higher than the value
  601. % already on the stack, replace the value on the stack
  602. { 3 -1 roll pop 2 1 roll} {pop} ifelse
  603. } for
  604. pop
  605. 1 add array 0 1 2 index length 1 sub {
  606. postpos total_length ge {
  607. % Fill the rest with .notdef
  608. 1 2 index length 1 sub { 1 index exch /.notdef put } for
  609. exit
  610. } if
  611. % No name available, /postnames will be defined as an empty
  612. % array and the glyph won't get a name attached.
  613. postglyphs postpos //get_from_stringarray exec
  614. postglyphs postpos 1 add 2 index
  615. 2 copy add total_length gt {
  616. TTFDEBUG { (post table ends in the middle of the entry.) print flush } if
  617. pop pop pop pop
  618. % Fill the rest with .notdef
  619. 1 2 index length 1 sub { 1 index exch /.notdef put } for
  620. exit
  621. } if
  622. //getinterval_from_stringarray exec cvn
  623. exch postpos add 1 add /postpos exch def
  624. 2 index 3 1 roll
  625. put
  626. } for
  627. /postnames exch def
  628. % Some TrueType fonts converted by "Windows Type 1 Installer" have
  629. % problematic post table including MacGlyphEncoding entries which
  630. % should be omitted. Such extra entries in the beginning of glyphName
  631. % array make /Encoding broken. If we find populary predefined
  632. % ISOLatin1Encoding glyph name in the post table, empty encoding is
  633. % returned. Some TrueType fonts for Microsoft Windows redefines
  634. % MacGlyphEncoding glyph name out of predefined range). To permit
  635. % such fonts, ISOLatin1Encoding is used to find broken post. Bug 689495.
  636. /.broken_post //false def
  637. tabdict /name .knownget {
  638. (Windows Type 1 Installer V1.0) search {
  639. pop pop pop
  640. .latin1isodict postnames {
  641. dup /.notdef ne {
  642. 2 copy known {
  643. TTFDEBUG { (ignore post table that redefines ISOLatin1Encoding glyph name ) print dup //== exec flush } if
  644. /.broken_post //true def
  645. pop exit
  646. } if
  647. } if
  648. pop
  649. } forall
  650. pop
  651. } {
  652. pop
  653. } ifelse
  654. } if
  655. % Loop through the array of name indices we created above.
  656. % This loop replaces name index in the array with the name
  657. % it references.
  658. 0 1 2 index length 1 sub {
  659. dup 2 index exch get dup 258 lt {
  660. MacGlyphEncoding exch get
  661. } {
  662. 258 sub postnames exch get
  663. % At least some of Microsoft's TrueType fonts use incorrect
  664. % (Adobe-incompatible) names for some glyphs.
  665. % Correct for this here.
  666. postremap 1 index .knownget { exch pop } if
  667. } ifelse
  668. 2 index 3 1 roll
  669. put
  670. } for
  671. .broken_post {
  672. pop
  673. [ postnames aload length 1 roll ]
  674. } if
  675. }
  676. ifelse
  677. } .forcebind
  678. 16#00030000 { % No map.
  679. pop [ ]
  680. } .forcebind
  681. .dicttomark readonly def % postformats
  682. /call.readtable
  683. { .readtable
  684. } .forcebind def
  685. /call.readbigtable
  686. { .readbigtable
  687. } .forcebind def
  688. % Each procedure in this dictionary is called as follows:
  689. % <file> <length> -proc- <string|array_of_strings>
  690. % Note that each table must have an even length, because of a strange
  691. % Adobe requirement that each sfnts entry have even length.
  692. /readtables mark
  693. % Ordinary tables
  694. (head) //call.readtable
  695. (hhea) 1 index
  696. (maxp) 1 index
  697. (name) 1 index
  698. (OS/2) 1 index
  699. (post) //call.readbigtable
  700. (vhea) //call.readtable
  701. % Big tables
  702. (cmap) //call.readbigtable
  703. (GSUB) //call.readbigtable
  704. (glyf) //call.readbigtable
  705. (loca) 1 index
  706. (hmtx) 1 index
  707. (vmtx) 1 index
  708. (cvt ) //call.readtable
  709. (fpgm) 1 index
  710. (prep) 1 index
  711. .dicttomark
  712. % Normally there would be a 'readonly' here, but the ttf2pf utility wants
  713. % to include the 'kern' table as well, so we leave the readtables dictionary
  714. % writable.
  715. def % readtables
  716. /readtables_stripped readtables dup length dict copy
  717. dup (loca) { .skiptable } put
  718. dup (glyf) { .skiptable } put
  719. def
  720. % Read a table as a single string.
  721. % <file> <length> .skiptable <string>
  722. /.skiptable {
  723. pop pop ()
  724. } .forcebind def
  725. % Read a table as a single string.
  726. % <file> <length> .readtable <string>
  727. /.readtable {
  728. dup dup 1 and add string
  729. % Stack: f len str
  730. dup 0 4 -1 roll getinterval
  731. % Stack: f str str1
  732. % Because of the absurd PostScript specification that gives an
  733. % error for reading into an empty string, we have to check for
  734. % this explicitly here.
  735. 3 -1 roll exch
  736. dup () ne { readstring } if pop pop
  737. } .forcebind def
  738. % Read a big table (one that may exceed 64K).
  739. % <file> <length> .readbigtable <string[s]>
  740. /.readbigtable {
  741. dup 65400 lt {
  742. .readtable
  743. } {
  744. currentuserparams /VMReclaim get -2 vmreclaim
  745. [ 4 2 roll {
  746. % Stack: mark ... f left
  747. dup maxstring le { exit } if
  748. 1 index maxstring string readstring pop 3 1 roll maxstring sub
  749. } loop .readtable ]
  750. exch vmreclaim
  751. } ifelse
  752. } .forcebind def
  753. end readonly def % .loadttfontdict
  754. % <tab> .printtab -
  755. /.printtab {
  756. dup 0 4 getinterval print ( ) print
  757. dup 8 getu32 =only ( ) print
  758. 12 getu32 =
  759. } .internalbind def
  760. % <file> <bool> <SubfontID> .loadttfonttables -
  761. % Pushes .loadttfontdict & scratch dict on d-stack.
  762. % Defines f, offsets, tables, tabdict, tabs, tthdrlen.
  763. % Skips loca and glyf if <bool> is true.
  764. /.loadttfonttables {
  765. //.loadttfontdict begin
  766. 40 dict begin
  767. /SubfontID exch def
  768. /load_stripped exch def
  769. /f exch def
  770. /offsets f 12 string readstring pop def
  771. /tthdrlen offsets length def
  772. load_stripped { readtables_stripped } { readtables } ifelse /readtables_ exch def
  773. offsets 0 4 getinterval (ttcf) eq {
  774. offsets 8 getu32 /num_fonts exch def
  775. SubfontID num_fonts ge {
  776. QUIET not { (True Type collection contains insufficient fonts.) = } if
  777. /.loadttfonttables cvx /invalidfont signalerror
  778. } if
  779. f SubfontID 4 mul dup 0 ne {
  780. () /SubFileDecode filter flushfile
  781. } {
  782. pop pop
  783. } ifelse
  784. f 4 string readstring pop
  785. 0 getu32 /ttc_offset exch def
  786. f ttc_offset SubfontID 4 mul sub 16 sub
  787. dup 0 ne {
  788. () /SubFileDecode filter flushfile
  789. } {
  790. pop pop
  791. } ifelse
  792. /offsets f 12 string readstring pop def
  793. } {
  794. SubfontID 0 gt {
  795. QUIET not { (SubfontID > 0 with a True Type file which is not a collection.) = } if
  796. /.loadttfonttables cvx /invalidfont signalerror
  797. } if
  798. /ttc_offset 0 def
  799. } ifelse
  800. % Peek because table counter may be incorrect.
  801. /tables f offsets 4 getu16 16 mul string .peekstring pop def
  802. /tabdict tables length 16 idiv dict def
  803. % tabs = tables we want to keep, sorted by file position.
  804. /tabs [ 0 16 tables length 1 sub {
  805. tables exch 16 getinterval
  806. TTFDEBUG { dup //.printtab exec } if
  807. dup 0 4 getinterval readtables_ 1 index known {
  808. % put all 0 length tables at 0 to avoid overlap
  809. 1 index 12 getu32 0 eq { 1 index 8 0 putu32 } if
  810. tabdict exch 2 index put
  811. } {
  812. pop pop
  813. } ifelse
  814. } for ] {
  815. exch 8 getu32 exch 8 getu32 lt
  816. } .sort def
  817. % In certain malformed TrueType fonts, tables overlap.
  818. % Truncate tables if necessary.
  819. 0 1 tabs length 2 sub {
  820. dup tabs exch get exch 1 add tabs exch get
  821. 1 index 8 getu32 2 index 12 getu32 add
  822. 1 index 8 getu32 gt {
  823. (**** Warning: ) print 1 index 0 4 getinterval print
  824. ( overlaps ) print dup 0 4 getinterval print
  825. (, truncating.) = flush
  826. dup 8 getu32 2 index 8 getu32 sub
  827. 2 index 12 3 -1 roll putu32
  828. } if pop pop
  829. } for
  830. } .forcebind def
  831. % <file> <bool> <SubfontID> .loadwofftables -
  832. % Pushes .loadttfontdict & scratch dict on d-stack.
  833. % Defines f, offsets, tables, tabdict, tabs, tthdrlen.
  834. % Skips loca and glyf if <bool> is true.
  835. /.loadwofftables {
  836. //.loadttfontdict begin
  837. 40 dict begin
  838. /SubfontID exch def
  839. /load_stripped exch def
  840. /f exch def
  841. % loading WOFFs "stripped" only works for .findfontvalue - we cannot
  842. % (currently) use a stripped wOFF font
  843. load_stripped { readtables_stripped } { readtables } ifelse /readtables_ exch def
  844. /offsets 12 string def
  845. /woffhdr f 44 string readstring pop def
  846. /tthdrlen woffhdr length def
  847. /ttc_offset 0 def
  848. woffhdr 0 4 getinterval (wOFF) eq not
  849. % allow loading wOFFOTTO fonts "stripped" for .findfontvalue
  850. woffhdr 4 4 getinterval (OTTO) eq load_stripped not and or
  851. {/.loadwofftables cvx /invalidfont signalerror}
  852. {
  853. offsets 0 woffhdr 4 4 getinterval putinterval
  854. /tables f woffhdr 12 getu16 20 mul string .peekstring pop def
  855. offsets 4 tables length 20 idiv putu16
  856. /tabdict tables length 20 idiv dict def
  857. /tabs [ 0 20 tables length 1 sub
  858. {
  859. tables exch 20 getinterval
  860. TTFDEBUG { dup //.printtab exec } if
  861. dup 0 4 getinterval readtables_ 1 index known
  862. {
  863. % put all 0 length tables at 0 to avoid overlap
  864. 1 index 12 getu32 0 eq { 1 index 8 0 putu32 } if
  865. tabdict exch 2 index put
  866. }
  867. {pop pop}
  868. ifelse
  869. }for
  870. ]
  871. { exch 4 getu32 exch 4 getu32 lt } .sort
  872. def
  873. } ifelse
  874. } .forcebind def
  875. /.file_table_pos_names
  876. mark
  877. /glyf 0
  878. /loca 0
  879. .dicttomark readonly def
  880. % - .readttdata -
  881. % Read data. Updates offsets, tabs; stores data in tabdict.
  882. /.readttdata {
  883. /file_table_pos 10 dict def
  884. /fpos tthdrlen ttc_offset add def
  885. /sfpos offsets length tabs length 16 mul add def
  886. offsets 4 tabs length putu16
  887. 0 1 tabs length 1 sub {
  888. dup tabs exch get
  889. dup 0 4 getinterval /tname exch def
  890. dup length 20 eq
  891. {
  892. dup 4 getu32 /tpos exch def
  893. dup 8 getu32 /tclen exch def
  894. dup 12 getu32 /tlen exch def
  895. }
  896. {
  897. dup 8 getu32 /tpos exch def
  898. dup 12 getu32 /tlen exch def
  899. /tclen tlen def
  900. } ifelse
  901. load_stripped //.file_table_pos_names tname known and {
  902. pop
  903. file_table_pos tname [tpos tlen tclen] put
  904. tabdict tname () put
  905. pop
  906. } {
  907. dup length 20 eq
  908. {
  909. 0 16 getinterval dup 8 sfpos putu32
  910. tabs 3 -2 roll put
  911. }
  912. {8 sfpos putu32 pop}
  913. ifelse
  914. % Skip data between the end of the previous table and
  915. % the beginning of this one, if any.
  916. tpos fpos gt {
  917. load_stripped {
  918. % 'setfileposition' is faster for skipping a big data.
  919. f tpos setfileposition
  920. } {
  921. f tpos fpos sub () /SubFileDecode filter dup flushfile closefile
  922. /fpos tpos def
  923. } ifelse
  924. } if
  925. /ff
  926. tlen tclen eq not
  927. {f tclen () /SubFileDecode filter /FlateDecode filter}
  928. {f tlen () /SubFileDecode filter}
  929. ifelse
  930. def
  931. ff tlen readtables_ tname get exec
  932. ff closefile
  933. tabdict tname 3 -1 roll put
  934. % Round up the table length to an even value.
  935. /sfpos sfpos tlen dup 1 and add add def
  936. } ifelse
  937. /fpos fpos tclen add def
  938. } for
  939. } .forcebind def
  940. % Find the string in a list of strings that includes a given index.
  941. % <strings> <index> .findseg <string> <index'>
  942. /.findseg {
  943. exch {
  944. dup length 2 index gt { exch exit } if
  945. length sub
  946. } forall
  947. } .forcebind def
  948. % - .makesfnts -
  949. % Defines checksum, getloca, head, locatable, numloca, post, sfnts, upem
  950. % Note that the 'loca' table may be out of order.
  951. /.makesfnts {
  952. //.readttdata exec
  953. /head tabdict /head get def
  954. /post tabdict /post .knownget {
  955. dup 0 get /post_first_part exch def
  956. } {
  957. //null
  958. } ifelse def
  959. load_stripped not {
  960. /locatable tabdict /loca get def
  961. /numloca
  962. locatable dup type /stringtype eq
  963. { length }
  964. { 0 exch { length add } forall }
  965. ifelse % no def yet
  966. locatable type /stringtype eq {
  967. /.indexloca {} def
  968. } {
  969. /.indexloca //.findseg def
  970. } ifelse
  971. head 50 getu16 0 ne {
  972. /getloca {
  973. 2 bitshift locatable exch .indexloca getu32
  974. } def
  975. 4 idiv 1 sub
  976. } {
  977. /getloca {
  978. dup add locatable exch .indexloca getu16 dup add
  979. } def
  980. 2 idiv 1 sub
  981. } ifelse def % numloca
  982. } {
  983. % We did not load loca, take the number of glyphs from maxp.
  984. /numloca tabdict /maxp get 4 getu16 def
  985. } ifelse
  986. /sfnts [
  987. offsets tabs { concatstrings } forall
  988. tabs {
  989. 0 4 getinterval tabdict exch get
  990. dup type /stringtype ne { aload pop } if
  991. } forall
  992. ] def
  993. } .forcebind odef
  994. /first_post_string % - first_post_string <string>
  995. {
  996. post dup type /arraytype eq { 0 get } if
  997. } .internalbind def
  998. % - .getpost -
  999. % Uses post, defines glyphencoding
  1000. /.getpost {
  1001. /glyphencoding post //null eq {
  1002. TTFDEBUG { (post missing) = flush } if [ ]
  1003. } {
  1004. postformats first_post_string 0 getu32 .knownget {
  1005. TTFDEBUG {
  1006. (post: format ) print
  1007. first_post_string
  1008. dup 0 getu16 =only (,) print 2 getu16 = flush
  1009. } if
  1010. post exch exec
  1011. } {
  1012. TTFDEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
  1013. } ifelse
  1014. } ifelse
  1015. TTFDEBUG { (post=) print dup //== exec } if
  1016. def
  1017. } .forcebind def
  1018. % - .ttkeys <key> <value> ...
  1019. /.ttkeys {
  1020. count /ttkeycount exch def
  1021. /upem head 18 getu16 def
  1022. /FontMatrix matrix
  1023. /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
  1024. nextxuid
  1025. tabdict /name .knownget {
  1026. % Find the names from the 'name' table.
  1027. /names exch def
  1028. /FontName names 6 findname not { names 4 findname not { curxuid 16#ffffffff and 16 32 string cvrs } if } if
  1029. /fontname 1 index def
  1030. /FontInfo mark
  1031. names 0 findname { /Notice exch } if
  1032. names 1 findname { /FamilyName exch } if
  1033. names 4 findname { /FullName exch } if
  1034. names 5 findname { /Version exch } if
  1035. } {
  1036. % No name table, fabricate a FontName.
  1037. /FontName curxuid 16#ffffffff and 16 32 string cvrs
  1038. /fontname 1 index def
  1039. /FontInfo mark
  1040. } ifelse
  1041. % Stack: ... /FontInfo mark key1 value1 ...
  1042. post //null ne {
  1043. /ItalicAngle first_post_string 4 gets32 65536.0 div
  1044. /isFixedPitch first_post_string 12 getu32 0 ne
  1045. /UnderlinePosition first_post_string 8 gets16 upem div
  1046. /UnderlineThickness first_post_string 10 gets16 upem div
  1047. } if
  1048. counttomark 0 ne { .dicttomark } { pop pop } ifelse
  1049. /XUID [orgXUID 42 curxuid]
  1050. TTFDEBUG {
  1051. tabs { //.printtab exec } forall
  1052. [ sfnts { length } forall ] //== exec
  1053. count ttkeycount sub array astore dup { //== exec } forall aload pop
  1054. } if
  1055. /sfnts sfnts
  1056. } .forcebind def
  1057. % ---------------- Standard TrueType font loading ---------------- %
  1058. % - .pickcmap_with_no_xlatmap -
  1059. % Defines cmapsub, cmaptab
  1060. /.pickcmap_with_no_xlatmap {
  1061. tabdict /cmap get
  1062. % The Apple cmap format is no help in determining the encoding.
  1063. % Look for a Microsoft table. If we can't find one,
  1064. % just use the first table, whatever it is.
  1065. dup 4 8 getinterval_from_stringarray exch % () [] % the default
  1066. 0 1 2 index 2 getu16a 1 sub { % () [] i
  1067. 8 mul 4 add 1 index exch 8 getinterval_from_stringarray % () [] ()
  1068. TTFDEBUG {
  1069. (cmap: platform ) print dup 0 getu16 =only
  1070. ( encoding ) print dup 2 getu16 = flush
  1071. } if
  1072. dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
  1073. } for
  1074. % Stack: subentry table
  1075. /cmapsub 2 index def % () []
  1076. exch 4 getu32 1 index string_array_size 1 index sub getinterval_from_stringarray
  1077. /cmaptab exch def
  1078. } .forcebind def
  1079. % - .pickcmap_with_xlatmap -
  1080. % Defines cmapsub, cmaptab
  1081. /.pickcmap_with_xlatmap {
  1082. .xlatmap_dict /TrueType known not {
  1083. (Emulating a CID font with a True Type file, ) print
  1084. (the file gs/lib/xlatmap must contain /TrueType key.) =
  1085. /.pickcmap_with_xlatmap cvx /configurationerror signalerror
  1086. } if
  1087. //false
  1088. .xlatmap_dict /TrueType get
  1089. dup length 2 sub 0 exch 2 exch { % bool [] i
  1090. 2 copy get % bool [] i ()
  1091. (.) search { % bool [] i post match pre
  1092. cvi exch pop exch cvi % bool [] i PlatID SpecID
  1093. } {
  1094. (gs/lib/xlatmap containg a record with an invalid (PlatformID.SpecificID)) =
  1095. /.pickcmap_with_xlatmap cvx /configurationerror signalerror
  1096. } ifelse
  1097. TTFDEBUG {
  1098. (Seeking a cmap for platform=) print 1 index =only ( encoding=) print dup =
  1099. } if
  1100. tabdict /cmap get % bool [] i PlatID SpecID (cmap)
  1101. dup /cmaptab exch def % temporary
  1102. 0 1 2 index 2 getu16a 1 sub { % bool [] i PlatID SpecID (cmap) j
  1103. 8 mul 4 add 1 index exch 8
  1104. getinterval_from_stringarray % bool [] i PlatID SpecID (cmap) (cmapsub)
  1105. TTFDEBUG {
  1106. (cmap: platform ) print dup 0 getu16 =only
  1107. ( encoding ) print dup 2 getu16 = flush
  1108. } if
  1109. dup 0 getu16 4 index eq {
  1110. dup 2 getu16 3 index eq { % bool [] i PlatID SpecID (cmap) (cmapsub)
  1111. TTFDEBUG {
  1112. (Choosen a cmap for platform=) print 3 index =only
  1113. ( encoding=) print 2 index =
  1114. } if
  1115. /cmapsub 1 index def
  1116. dup 4 getu32 % bool [] i PlatID SpecID (cmap) (cmapsub) p
  1117. cmaptab 1 index getu16a % get cmap format
  1118. 8 lt { % length for traditional 16bit format 0, 2, 4, 6
  1119. cmaptab 1 index 2 add getu16a
  1120. } { % length for advanced 32bit format 8, 10, 12
  1121. cmaptab 1 index 4 add getu32a
  1122. } ifelse % bool [] i PlatID SpecID (cmap) (cmapsub) p l
  1123. cmaptab 3 1 roll getinterval_from_stringarray
  1124. /cmaptab exch def % bool [] i PlatID SpecID (cmap) (cmapsub)
  1125. 5 index 5 index 1 add get % bool [] i PlatID SpecID (cmap) (cmapsub) /Decoding
  1126. /Decoding exch def % bool [] i PlatID SpecID (cmap) (cmapsub)
  1127. 7 -1 roll pop //true 7 1 roll % true [] i PlatID SpecID (cmap) (cmapsub)
  1128. } if
  1129. } if
  1130. pop % true [] i PlatID SpecID (cmap)
  1131. 5 index { exit } if
  1132. } for % bool [] i PlatID SpecID (cmap)
  1133. pop pop pop pop % bool []
  1134. 1 index { exit } if
  1135. } for % bool []
  1136. pop % bool
  1137. not {
  1138. QUIET not { (True Type font doesn't contain a charset listed in gs/lib/xlatmap.) = } if
  1139. /.pickcmap_with_xlatmap cvx /invalidfont signalerror
  1140. } if %
  1141. } .forcebind def
  1142. % - .pickcmap -
  1143. % Defines cmapsub, cmaptab
  1144. /.pickcmap {
  1145. % Currently we use xlatmap only for emulation CIDFontType 2 with
  1146. % a disk True Type font files, and use load_stripped
  1147. % to check this regime. We would like to do so
  1148. % while emulating a Type 42, but first the old code
  1149. % about handling them to be changed
  1150. % with adding a handling of a Decoding.
  1151. % fixme : A correct way to fix this is to implenent
  1152. % the Type 42 emulation with gs_fntem.ps .
  1153. % Also note that PDF embedded fonts probably don't need a xlatmap -
  1154. % see PDF spec, "Encodings for True Type fonts".
  1155. load_stripped {
  1156. //.pickcmap_with_xlatmap exec
  1157. } {
  1158. //.pickcmap_with_no_xlatmap exec
  1159. } ifelse
  1160. } .forcebind odef
  1161. currentdict /.pickcmap_with_xlatmap .undef
  1162. currentdict /.pickcmap_with_no_xlatmap .undef
  1163. % <glyph> .nname <_name>
  1164. /.nname {
  1165. =string cvs (_) exch concatstrings cvn
  1166. } .internalbind def
  1167. % - .charkeys /CharStrings <charstrings> /Encoding <encoding>
  1168. % Resets glyphencoding
  1169. /.charkeys {
  1170. TTFDEBUG {
  1171. (glyphencoding: length=) print glyphencoding dup length = === flush
  1172. } if
  1173. % Hack: if there is no usable post table but the cmap uses
  1174. % the Microsoft Unicode encoding, use ISOLatin1Encoding.
  1175. % if 'post' presents, .charkeys computes (with dropping minor details) :
  1176. % CharStrings = glyphencoding^-1
  1177. % Encoding = cmap*glyphencoding
  1178. % because 'post' maps glyph indices to glyph names.
  1179. % Otherwise .charkeys must compute (with dropping same details) :
  1180. % CharStrings = glyphencoding^-1 * cmap
  1181. % Encoding = glyphencoding
  1182. % because glyphencoding is stubbed with an encoding,
  1183. % which maps char codes to glyph names.
  1184. glyphencoding length 0 eq {
  1185. /have_post //false def
  1186. cmapsub 0 4 getinterval <00030001> eq {
  1187. TTFDEBUG { (No post but have cmap 3.1, so use ISOLatin1Encoding) = } if
  1188. /glyphencoding ISOLatin1Encoding dup length array copy def
  1189. } {
  1190. TTFDEBUG { (No encoding info, use .GS_extended_SymbolEncoding) = } if
  1191. /glyphencoding /.GS_extended_SymbolEncoding findencoding dup length array copy def
  1192. } ifelse
  1193. } {
  1194. /have_post //true def
  1195. } ifelse
  1196. % If necessary, fabricate additional glyphencoding entries
  1197. % to cover all of loca
  1198. glyphencoding length numloca lt {
  1199. /glyphencoding numloca array
  1200. glyphencoding length dup 1 sub 0 1 3 2 roll {
  1201. dup glyphencoding exch get
  1202. 3 index 3 1 roll put
  1203. } for
  1204. % /glyphencoding <newarray> <glyphencoding length>
  1205. 1 numloca 1 sub {
  1206. 1 index exch dup //.nname exec put
  1207. } for
  1208. def
  1209. } if
  1210. /cmapa cmaptab cmapdict def
  1211. % Some badly designed Chinese fonts have a post table
  1212. % in which all glyphs other than 0 are named .null.
  1213. % Use CharStrings to keep track of the reverse map from
  1214. % names to glyphs, and don't let any name be used for
  1215. % more than one glyph.
  1216. /CharStrings glyphencoding dup length 1 add dict % +1 for .notdef
  1217. 0 1 3 index length 1 sub {
  1218. % Stack: glyphencoding dict index
  1219. dup 3 index 1 index get
  1220. have_post not {
  1221. exch
  1222. cmapa exch .knownget not {
  1223. 0 % a stub for a while. Must skip the entry.
  1224. } if
  1225. exch
  1226. } if
  1227. 3 index 1 index known
  1228. { % The same name maps to more than one glyph. Change the name.
  1229. % No special treatment for /.notdef glyph. Bug 689408.
  1230. pop //.nname exec 3 index 2 index 2 index put
  1231. 2 index exch 3 -1 roll put
  1232. } {
  1233. 3 index exch 3 -1 roll put % unique name
  1234. pop
  1235. } ifelse
  1236. } for exch pop
  1237. % If there is no .notdef entry, map it to glyph 0.
  1238. dup /.notdef known not { dup /.notdef 0 put } if
  1239. TTFDEBUG {
  1240. (CharStrings:)= dup { exch =string cvs print ( ) print //== exec } forall
  1241. } if
  1242. % Provide all known aliases for each glyph
  1243. cmapsub 0 4 getinterval <00030001> eq % is the cmap table a unicode one?
  1244. cmapa //ReverseAdobeGlyphList //AdobeGlyphList
  1245. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer)
  1246. exch
  1247. dup 6 index exch .knownget
  1248. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) codep(integer) gname(name) gindex(integer)
  1249. 3 index 3 index .knownget
  1250. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) codep(integer) gname(name) gindex(integer) gnames(array)
  1251. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) codep(integer) gname(name) gindex(integer) gname(name)
  1252. TTFDEBUG { (\n1 setting alias: ) print dup ==only
  1253. ( to be the same as ) print 2 index //== exec } if
  1254. 7 index 2 index 3 -1 roll exch put
  1255. } forall
  1256. pop pop pop
  1257. }
  1258. {
  1259. pop pop
  1260. } ifelse
  1261. }
  1262. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer)
  1263. exch
  1264. % Only do this for Unicode cmap table
  1265. 4 index
  1266. {
  1267. dup 4 index exch .knownget
  1268. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer) gindex(integer)
  1269. exch pop
  1270. TTFDEBUG { (\n2 setting alias: ) print 1 index ==only
  1271. ( to use glyph index: ) print dup //== exec } if
  1272. 5 index 3 1 roll put
  1273. //false
  1274. }
  1275. {
  1276. //true
  1277. }ifelse
  1278. }
  1279. {
  1280. //true
  1281. } ifelse
  1282. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer)
  1283. 16 4 string cvrs dup length neg 7 add (uni0000) dup
  1284. 4 -2 roll exch putinterval cvn 3 index 1 index .knownget
  1285. { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer) gindex(integer)
  1286. TTFDEBUG { (\3 nsetting alias: ) print 1 index ==only
  1287. ( to be index: ) print dup //== exec } if
  1288. exch pop 5 index 3 1 roll put
  1289. }
  1290. {
  1291. pop pop
  1292. } ifelse
  1293. } if
  1294. } ifelse
  1295. } forall
  1296. pop pop pop
  1297. readonly
  1298. /Encoding [
  1299. have_post {
  1300. 0 1 255 {
  1301. cmapa exch .knownget not { 0 } if
  1302. glyphencoding dup length
  1303. 2 index le {
  1304. pop pop /.notdef
  1305. } {
  1306. exch get
  1307. } ifelse
  1308. } for
  1309. } {
  1310. glyphencoding dup length 256 gt { 0 256 getinterval } if
  1311. aload pop
  1312. counttomark 256 exch sub { /.notdef } repeat
  1313. } ifelse
  1314. ]
  1315. TTFDEBUG { (Encoding: ) print dup === flush } if
  1316. } .forcebind odef
  1317. % ---------------- CIDFontType 2 font loading ---------------- %
  1318. % Fill a string with sequential CIDs starting from the initial value.
  1319. % <string> <value> .fill_identity_cmap <string>
  1320. /.fill_identity_cmap { % () v
  1321. 1 index length 2 sub % () v n-2
  1322. 0 2 3 2 roll { % () v 0 2 n-1
  1323. 3 copy exch % () v i () i v
  1324. -8 bitshift % () v i () i v>>8
  1325. put % () v i
  1326. 3 copy 1 add % () v i () v i+1
  1327. exch 255 and % () v i () i+1 v&255
  1328. put % () v i
  1329. pop 1 add % () v+1
  1330. } for
  1331. pop
  1332. } .forcebind def
  1333. % <CIDSystemInfo dict> <dict> .definettcidfont <font>
  1334. /.definettcidfont {
  1335. dup begin
  1336. /CIDFontName fontname def
  1337. /CIDFontType 2 def
  1338. /CIDSystemInfo 4 -1 roll def
  1339. /CharStrings mark /.notdef 0 .dicttomark def
  1340. % The cmap isn't of any use even if it is present.
  1341. % Just construct an identity CIDMap covering all the glyphs.
  1342. /CIDCount numloca % Wrong if a CIDFontType2 embedded into PDF with a non-Identity CIDToGIDMap.
  1343. def % processCIDToGIDMap may replace.
  1344. /CIDMap numloca maxstring le {
  1345. % Use a single string.
  1346. numloca 2 mul string 0 //.fill_identity_cmap exec
  1347. } {
  1348. % We must use 2 strings.
  1349. maxstring 2 mul string 0 //.fill_identity_cmap exec
  1350. numloca maxstring sub 2 mul string maxstring //.fill_identity_cmap exec
  1351. 2 array astore
  1352. } ifelse
  1353. def
  1354. /GDBytes 2 def
  1355. end
  1356. end end dup /CIDFontName get exch /CIDFont defineresource
  1357. } .forcebind def
  1358. % <CIDSystemInfo dict> <file> <Substite name> .loadttcidfont <cidtype2font>
  1359. /.loadttcidfont {
  1360. exch
  1361. //false 0 .loadttfonttables
  1362. .makesfnts
  1363. % CIDFontType2 fonts don't have a cmap: they are indexed by CID.
  1364. mark
  1365. //.ttkeys exec
  1366. .dicttomark dup % convert keys to dict and copy dict
  1367. 3 -1 roll % Bring PDF substitute name to top of stack
  1368. dup
  1369. /fontname exch def
  1370. /FontName exch put % replace any definition of /FontName
  1371. //.definettcidfont exec
  1372. } .forcebind odef
  1373. % <file> <SubfontID> .load_tt_font_stripped <font_data>
  1374. % The font_data includes sfnts, NumGlyphs, TT_cmap, file_table_pos, Decoding.
  1375. % CIDMap to be created later from TT_cmap.
  1376. /.load_tt_font_stripped {
  1377. //true exch .loadttfonttables
  1378. .makesfnts
  1379. .pickcmap
  1380. mark
  1381. //.ttkeys exec
  1382. /NumGlyphs numloca
  1383. /TT_cmap cmaptab cmapdict
  1384. /file_table_pos file_table_pos
  1385. /Decoding Decoding
  1386. .dicttomark
  1387. end end
  1388. } .forcebind def
  1389. /.load_woff_for_cid {
  1390. //false exch //.loadwofftables exec
  1391. .makesfnts
  1392. % we have to set load_stripped here so
  1393. % .pickcmap will follow the right logic
  1394. % for emulating a CIDFont
  1395. /load_stripped //true def
  1396. .pickcmap
  1397. /load_stripped //false def
  1398. mark
  1399. //.ttkeys exec
  1400. /NumGlyphs numloca
  1401. /TT_cmap cmaptab cmapdict
  1402. % /file_table_pos file_table_pos
  1403. /Decoding Decoding
  1404. .dicttomark
  1405. end end
  1406. } .forcebind def
  1407. % ---------------- PDF TrueType font loading ---------------- %
  1408. % Strictly speaking, this code should be loaded only if we have a PDF
  1409. % interpreter, but it's so closely tied to the rest of the code in this
  1410. % file that we always include it.
  1411. % <plat+enc> .findcmap <subtable> true
  1412. % <plat+enc> .findcmap false
  1413. /.findcmap {
  1414. //false exch tabdict /cmap get
  1415. % Some fonts have multiple cmaps with the same platform and
  1416. % encoding. Use the first one we find.
  1417. 0 1 2 index 2 getu16a 1 sub {
  1418. % Stack: false plat+enc cmap index
  1419. 8 mul 4 add 1 index exch 8 getinterval_from_stringarray
  1420. dup 0 4 getinterval 3 index eq {
  1421. 4 getu32 1 index exch 1 index string_array_size 1 index sub getinterval_from_stringarray
  1422. 4 -1 roll not 4 2 roll exit
  1423. } if pop
  1424. } for
  1425. % Stack: false plat+enc cmap || subtable true plat+enc cmap
  1426. pop pop
  1427. } .forcebind def
  1428. % Build .symbol_list for .pdfcharkeys .
  1429. % It is a dictionary containing all SymbolEncoding glyph names
  1430. % and random names for filling gaps in the character code range.
  1431. /.symbol_list 256 dict def
  1432. {
  1433. =string 0 (x) 0 get put
  1434. /SymbolEncoding .findencoding
  1435. 0 1 255 {
  1436. dup 2 index exch get
  1437. dup /.notdef eq {
  1438. pop dup
  1439. =string 1 3 getinterval cvs length 1 add
  1440. =string exch 0 exch getinterval cvn
  1441. } if
  1442. exch //.symbol_list 3 1 roll put
  1443. } for
  1444. pop
  1445. } .forcebind exec
  1446. % Create .GS_extended_SymbolEncoding as inverse of .symbol_list .
  1447. {
  1448. /.GS_extended_SymbolEncoding 256 array
  1449. //.symbol_list {
  1450. exch 2 index 3 1 roll put
  1451. } forall
  1452. .defineencoding
  1453. } .forcebind exec
  1454. /.hexdigits (0123456789ABCDEF) def
  1455. /.is_hex_digit { % <int> .is_hex_digit <bool>
  1456. dup 48 ge exch
  1457. dup 57 le exch
  1458. dup 65 ge exch
  1459. 70 le and
  1460. 3 1 roll
  1461. and or
  1462. } .forcebind def
  1463. /.popfex { pop //false exit } .internalbind def
  1464. /.pop3ex { pop pop pop exit } .internalbind def
  1465. /.addglyph { % <dict> <name> <glyph#> .addglyph -
  1466. 1 index .namestring % d n g s
  1467. dup length 7 eq {
  1468. % Bug688467.ps doesn't work if the uniXXXX mapping is allowed with any cmap.
  1469. % Allow it with cmap 3.1 only.
  1470. currentdict /.allow_uniXXXX_glyph_names .knownget not { //false } if
  1471. } { //false
  1472. } ifelse % d n g s b
  1473. {
  1474. % An undocumented Adobe feature (not sure) :
  1475. % if the name is uniXXXX, obtain Unicode code from it.
  1476. % See bug 688946.
  1477. TTFDEBUG { (Try uniXXXX:) print dup print } if
  1478. { dup 0 get 117 ne //.popfex if % u
  1479. dup 1 get 110 ne //.popfex if % n
  1480. dup 2 get 105 ne //.popfex if % i
  1481. dup 3 get //.is_hex_digit exec not //.popfex if
  1482. dup 4 get //.is_hex_digit exec not //.popfex if
  1483. dup 5 get //.is_hex_digit exec not //.popfex if
  1484. dup 6 get //.is_hex_digit exec not //.popfex if
  1485. dup 3 1 getinterval .hexdigits exch search pop length exch pop exch pop 12 bitshift exch
  1486. dup 4 1 getinterval .hexdigits exch search pop length exch pop exch pop 8 bitshift exch
  1487. dup 5 1 getinterval .hexdigits exch search pop length exch pop exch pop 4 bitshift exch
  1488. dup 6 1 getinterval .hexdigits exch search pop length exch pop exch pop exch pop
  1489. add add add
  1490. cmapencoding exch .knownget not { 0 } if
  1491. dup 0 eq //.popfex if
  1492. TTFDEBUG { ( index=) print dup =string cvs print } if
  1493. exch pop
  1494. put //true exit
  1495. } loop
  1496. TTFDEBUG { ()= } if
  1497. } {
  1498. pop //false
  1499. } ifelse
  1500. not { % d n g
  1501. {
  1502. cmapencoding exch .knownget not { 0 } if
  1503. dup 0 eq //.pop3ex if
  1504. 3 copy pop known //.pop3ex if
  1505. put exit
  1506. } loop
  1507. } if
  1508. } .forcebind def
  1509. % <chartoglyphmap> <subcmap> <AGL> .pdfmapchars /CharStrings <charstrings>
  1510. /.pdfmapchars {
  1511. exch cmapdict /cmapencoding exch def % c2g
  1512. /CharStrings 0 dict % c2g /CS <<>>
  1513. % Add glyphs of <AGL>*<subcmap> :
  1514. 3 2 roll { % /CS <<>> v
  1515. dup type /arraytype eq { % /CS <<>> /name []
  1516. { 3 copy //.addglyph exec
  1517. pop
  1518. } forall
  1519. } {
  1520. 3 copy //.addglyph exec pop
  1521. } ifelse
  1522. pop
  1523. } forall
  1524. % Add glyphs of 'post' with lower priority :
  1525. 0 1 glyphencoding length 1 sub {
  1526. dup glyphencoding exch get exch
  1527. dup 0 ne {
  1528. 3 copy pop known not {
  1529. 3 copy put
  1530. } if
  1531. } if
  1532. pop pop
  1533. } for
  1534. % Finally, add glyphs from the prebuilt_encoding with lowest priority
  1535. % this is a catch-all for poorly matched font/PDF combos
  1536. 3 2 roll { % /CS <<>> v
  1537. dup type /arraytype eq { % /CS <<>> /name []
  1538. { 3 copy //.addglyph exec
  1539. pop
  1540. } forall
  1541. } {
  1542. 3 copy //.addglyph exec pop
  1543. } ifelse
  1544. pop
  1545. } forall
  1546. dup /.notdef 0 put
  1547. } .forcebind def
  1548. % <subtable> .pdfmapsymbolic /Encoding [] /CharStrings <<>>
  1549. /.pdfmapsymbolic {
  1550. //true /.render_notdef gput
  1551. cmapdict
  1552. dup length 1 add dict begin
  1553. [ 64 { /.notdef /.notdef /.notdef /.notdef } repeat ]
  1554. exch { % [] char glyph
  1555. exch
  1556. dup 255 gt {
  1557. 255 and
  1558. 2 index 1 index get /.notdef ne {
  1559. pop pop
  1560. //false
  1561. } {
  1562. //true
  1563. } ifelse
  1564. } {
  1565. //true
  1566. } ifelse {
  1567. dup (01234567) cvs cvn % glyph char /char
  1568. 3 1 roll % /char glyph char
  1569. 3 index exch % /char glyph [] char
  1570. 3 index put % /char glyph
  1571. def % -
  1572. } if
  1573. } forall
  1574. /.notdef 0 def
  1575. /Encoding exch
  1576. /CharStrings currentdict end
  1577. } .forcebind def
  1578. % If we're using a 1,0 cmap table, we need to store the table for the heuristic
  1579. % to know whether to image or elide GID 0. See zfapi.c ps_get_glyphname_or_cid().
  1580. % For other cmap types, we don't. Since this just pushes key/value pairs onto the
  1581. % stack for a later dicttomark op, it doesn't matter that different branches can push
  1582. % different numbers of objects.
  1583. %
  1584. % - .pdfcharkeys [/TT_cmap cmapdict] /CharStrings <charstrings> /Encoding <encoding>
  1585. /.pdfcharkeys {
  1586. % The following algorithms are per the PDF 1.7 Reference.
  1587. TTFDEBUG { (.pdfcharkeys beg) = } if
  1588. % if the flags say symbolic, *and* the font contains a symbol or UCS-2
  1589. % cmap table, ignore Encoding if there is one, treat as symbolic.
  1590. % If the flags say symbolic, and the font doesn't have a symbol cmap
  1591. % and we have an Encoding, treat it as non-symbolic
  1592. % if we don't have an Encoding, try the MacRoman cmap table.
  1593. % Finally, if none of that works, remove the Encoding, and treat it
  1594. % as non-symbolic.
  1595. is_symbolic {
  1596. <00030000> //.findcmap exec
  1597. { //true }
  1598. {
  1599. prebuilt_encoding //null eq {
  1600. <00030001> //.findcmap exec
  1601. {//true}
  1602. {<00010000> //.findcmap exec}
  1603. ifelse
  1604. }
  1605. {//false}
  1606. ifelse
  1607. } ifelse
  1608. {
  1609. //.pdfmapsymbolic exec
  1610. /prebuilt_encoding //null def
  1611. //false
  1612. } {
  1613. /prebuilt_encoding //null def
  1614. //true
  1615. } ifelse
  1616. } {
  1617. //true
  1618. }
  1619. ifelse
  1620. {
  1621. <00030001> //.findcmap exec {
  1622. prebuilt_encoding //null ne {
  1623. TTFDEBUG { (Using cmap 3.1 with prebuilt_encoding for non-symbolic.) = } if
  1624. //true /.render_notdef gput
  1625. % The character code in /prebuilt_encoding[] is not guaranteed to be
  1626. % compatible with the Microsoft UCS2 TrueType cmap subtable.
  1627. % If the glyphname is known by AdobeGlyphList, the charcode for the glyph
  1628. % is replaced by UCS2 charcode from AdobeGlyphList. Otherwise it is left
  1629. % as in /prebuilt_encoding[]. /.pdfmapchars should dredge them.
  1630. /.allow_uniXXXX_glyph_names //true def
  1631. AdobeGlyphList prebuilt_encoding .invert_encoding dup { % <<AGL>> <<pbe>> <glyphname> <pbecode>
  1632. pop % <<AGL>> <<pbe>> <glyphname>
  1633. TTFDEBUG { (check glypname /) print dup =only flush } if
  1634. 2 index 1 index .knownget { % <<AGL>> <<pbe>> <glyphname> <AGLcode>
  1635. 2 index 3 1 roll % <<AGL>> <<pbe>> <<pbe>> <glyphname> <AGLcode>
  1636. TTFDEBUG { ( redefine codepoint by AdobeGlyphList, ) print dup //== exec flush } if
  1637. put % <<AGL>> <<pbe>>
  1638. } { % <<AGL>> <<pbe>> <glyphname>
  1639. TTFDEBUG { ( unknown glyphname, leave as it is ) = flush } if
  1640. pop % <<AGL>> <<pbe>>
  1641. } ifelse
  1642. } forall
  1643. exch pop % <<pbe>>
  1644. TTFDEBUG { dup (<<\n) print { exch ( ) print =only (\t) print //== exec } forall (>>\n) print flush } if
  1645. exch AdobeGlyphList
  1646. //.pdfmapchars exec
  1647. /Encoding prebuilt_encoding
  1648. } {
  1649. % Likely this branch is now obsolete.
  1650. TTFDEBUG { (Using cmap 3.1 for non-symbolic.) = } if
  1651. 0 dict exch
  1652. AdobeGlyphList //.pdfmapchars exec
  1653. /Encoding /WinAnsiEncoding .findencoding
  1654. % WinAnsiEncoding is just a stub here.
  1655. % It will be replaced with one from font resource,
  1656. % because PDF spec requires it.
  1657. } ifelse
  1658. } {
  1659. <00010000> //.findcmap exec {
  1660. /TT_cmap 1 index cmapdict 3 -1 roll
  1661. TTFDEBUG { (Using cmap 1.0 for non-symbolic.) = } if
  1662. prebuilt_encoding //null ne {
  1663. prebuilt_encoding .invert_encoding exch .romanmacdict //.pdfmapchars exec
  1664. prebuilt_encoding
  1665. } {
  1666. 0 dict exch .romanmacdict //.pdfmapchars exec
  1667. /MacRomanEncodingForTrueType .findencoding
  1668. } ifelse
  1669. /Encoding exch
  1670. } {
  1671. % Apply the default algorithm for using the 'post'.
  1672. .charkeys
  1673. % But use PDF encoding when available.
  1674. prebuilt_encoding //null ne {
  1675. pop prebuilt_encoding
  1676. } if
  1677. } ifelse
  1678. } ifelse
  1679. } if
  1680. TTFDEBUG { (.pdfcharkeys end) = } if
  1681. } .forcebind def
  1682. % <file> <is_symbolic> <Encoding|null> <FontName> .loadpdfttfont <type42font>
  1683. /.loadpdfttfont {
  1684. TTFDEBUG { (.loadpdfttfont FontName=) print dup == } if
  1685. /font_name gput
  1686. TTFDEBUG { (.loadpdfttfont Encoding=) print dup //== exec } if
  1687. /prebuilt_encoding gput % for .pdfcharkeys
  1688. /is_symbolic gput
  1689. % init key for whether to display the TTF notdef
  1690. //false /.render_notdef gput
  1691. //false 0 .loadttfonttables
  1692. .makesfnts
  1693. tabdict /cmap known not {
  1694. ( **** Warning: Embedded TT font lacks required cmap table. Using identity cmap.\n)
  1695. pdfformaterror
  1696. % Unknown (i.e. not 0 ) language ID brings in post table.
  1697. % Fields: cmap_version, number_of_subtables,
  1698. % plarform_id, encoding_id, offset,
  1699. % format, subtable_length, language,
  1700. % 256 bytes of identity mapping.
  1701. tabdict /cmap
  1702. < 0000 0001
  1703. 0001 D00D 0000000c
  1704. 0000 0106 0000
  1705. 00 01 02 03 04 05 06 07 08 09 0a 0d 0c 0d 0e 0f
  1706. 10 11 12 13 14 15 16 17 18 19 1a 1d 1c 1d 1e 1f
  1707. 20 21 22 23 24 25 26 27 28 29 2a 2d 2c 2d 2e 2f
  1708. 30 31 32 33 34 35 36 37 38 39 3a 3d 3c 3d 3e 3f
  1709. 40 41 42 43 44 45 46 47 48 49 4a 4d 4c 4d 4e 4f
  1710. 50 51 52 53 54 55 56 57 58 59 5a 5d 5c 5d 5e 5f
  1711. 60 61 62 63 64 65 66 67 68 69 6a 6d 6c 6d 6e 6f
  1712. 70 71 72 73 74 75 76 77 78 79 7a 7d 7c 7d 7e 7f
  1713. 80 81 82 83 84 85 86 87 88 89 8a 8d 8c 8d 8e 8f
  1714. 90 91 92 93 94 95 96 97 98 99 9a 9d 9c 9d 9e 9f
  1715. a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ad ac ad ae af
  1716. b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bd bc bd be bf
  1717. c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cd cc cd ce cf
  1718. d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da dd dc dd de df
  1719. e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea ed ec ed ee ef
  1720. f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fd fc fd fe ff
  1721. > readonly put
  1722. } if
  1723. .getpost
  1724. .pickcmap
  1725. mark
  1726. //.pdfcharkeys exec
  1727. //.ttkeys exec
  1728. /FontType 42
  1729. /PaintType 0
  1730. /.render_notdef .render_notdef
  1731. TTFDEBUG {
  1732. (numloca=) print numloca =
  1733. } if
  1734. .dicttomark
  1735. dup /FontName font_name put % replace any definition of /FontName
  1736. end end
  1737. .completefont
  1738. } .forcebind odef
  1739. %--------- Define main type42font loading routines, after their dependencies ------------
  1740. % <file> .loadttfont <type42font>
  1741. /.loadttfont {
  1742. TTFDEBUG { (.loadttfont) = } if
  1743. //false
  1744. % if this came from Fontmap, there may be a dictionary on the dict stack
  1745. % with a SubfontID in it. Validate it *is* a Fontmap record by also
  1746. % checking for a Path key
  1747. /SubfontID where
  1748. {
  1749. dup /Path known
  1750. {/SubfontID get}
  1751. {pop 0} ifelse
  1752. }
  1753. {0} ifelse
  1754. .loadttfonttables
  1755. .makesfnts
  1756. .getpost
  1757. .pickcmap
  1758. mark
  1759. % if we're loading to substitute for TTF in a PDF,
  1760. % load the font the "PDF way"
  1761. /prebuilt_encoding where
  1762. {pop //.pdfcharkeys exec}
  1763. {.charkeys} ifelse
  1764. //.ttkeys exec
  1765. /FontType 42
  1766. /PaintType 0
  1767. TTFDEBUG {
  1768. (numloca=) print numloca =
  1769. } if
  1770. .dicttomark
  1771. end end dup /FontName get exch definefont
  1772. } .forcebind def
  1773. % <file> .loadwofffont <type42font>
  1774. /.loadwofffont
  1775. {
  1776. TTFDEBUG { (.loadwofffont) = } if
  1777. //false 0 //.loadwofftables exec
  1778. .makesfnts
  1779. .getpost
  1780. .pickcmap
  1781. mark
  1782. .charkeys
  1783. //.ttkeys exec
  1784. /FontType 42
  1785. /PaintType 0
  1786. TTFDEBUG {
  1787. (numloca=) print numloca =
  1788. } if
  1789. .dicttomark
  1790. end end dup /FontName get exch
  1791. definefont
  1792. } .forcebind def
  1793. % ----- Utilities for loading possible TrueType font ------
  1794. % <file> .findttfontname <fname> true
  1795. % <file> .findttfontname false
  1796. % Closes the file in either case.
  1797. /.findttfontname {
  1798. //true 0 .loadttfonttables
  1799. tabdict /name .knownget {
  1800. dup 8 getu32 f exch setfileposition
  1801. 12 getu32
  1802. dup 65535 gt { pop 65535 } if % protect against extremely large name
  1803. string f exch readstring pop
  1804. dup
  1805. 6 findname not {
  1806. 4 findname % Try FullName
  1807. } {
  1808. exch pop //true
  1809. }
  1810. ifelse
  1811. } {
  1812. //false
  1813. } ifelse
  1814. f closefile end end
  1815. } .forcebind def
  1816. /.findwoffname {
  1817. //true 0 //.loadwofftables exec
  1818. tabdict /name .knownget {
  1819. dup /clen exch 8 getu32 def
  1820. dup /olen exch 12 getu32 def
  1821. 4 getu32 f exch setfileposition
  1822. olen dup 65535 gt { pop 65535 } if % protect against extremely large name
  1823. /fs
  1824. clen olen ne
  1825. {f clen () /SubFileDecode filter /FlateDecode filter}
  1826. {f clen () /SubFileDecode filter}
  1827. ifelse def
  1828. string fs exch readstring pop
  1829. fs closefile
  1830. dup
  1831. 6 findname not {
  1832. 4 findname % Try FullName
  1833. } {
  1834. exch pop //true
  1835. }
  1836. ifelse
  1837. } {
  1838. //false
  1839. } ifelse
  1840. f closefile end end
  1841. } .forcebind def
  1842. /tt_tag_dict << <00010000> 0 (true) 0 (typ1) 0 (ttcf) 0 >> readonly def
  1843. /ttf_otf_tag_dict << <00010000> 0 (true) 0 (typ1) 0 (ttcf) 0 (OTTO) 0>> readonly def
  1844. % The wOFF tag is immediately followed by the sfnt "flavour" so for simplicity
  1845. % combine them
  1846. /woff_tag_dict <<
  1847. (wOFF) 0
  1848. <774F464600010000> 0 % (wOFF)<00010000> .concatstrings
  1849. (wOFFtrue) 0
  1850. (wOFFtyp1) 0
  1851. >> readonly def
  1852. % <file> .is_ttf_or_otf <bool>
  1853. /.is_ttf_or_otf {
  1854. dup 0 setfileposition (1234) .peekstring { //ttf_otf_tag_dict exch known } { //false } ifelse
  1855. } .forcebind def
  1856. /.is_woff {
  1857. dup 0 setfileposition (1234) .peekstring { //woff_tag_dict exch known } { //false } ifelse
  1858. } .forcebind def
  1859. % <file> <key> .findfontvalue <value> true
  1860. % <file> <key> .findfontvalue false
  1861. % Closes the file in either case.
  1862. /.findnonttfontvalue /.findfontvalue load def
  1863. /.findfontvalue {
  1864. 1 index //.is_woff exec {
  1865. dup /FontType eq {
  1866. pop closefile 42 //true
  1867. } {
  1868. dup /FontName eq { pop //.findwoffname exec} { pop closefile //false } ifelse
  1869. } ifelse
  1870. }
  1871. {
  1872. 1 index //.is_ttf_or_otf exec {
  1873. % If this is a font at all, it's a TrueType font.
  1874. dup /FontType eq {
  1875. pop closefile 42 //true
  1876. } {
  1877. dup /FontName eq { pop //.findttfontname exec} { pop closefile //false } ifelse
  1878. } ifelse
  1879. } {
  1880. % Not a TrueType font.
  1881. .findnonttfontvalue
  1882. } ifelse
  1883. } ifelse
  1884. } .forcebind def
  1885. % Load a font file that might be a TrueType font.
  1886. % <file> .loadfontfile -
  1887. /.loadnonttfontfile /.loadfontfile load def
  1888. /.loadfontfile {
  1889. dup (12345678) .peekstring { //woff_tag_dict exch known } { //false } ifelse
  1890. {
  1891. //.loadwofffont exec pop
  1892. }
  1893. {
  1894. dup (1234) .peekstring { //tt_tag_dict exch known } { //false } ifelse {
  1895. % If this is a font at all, it's a TrueType font.
  1896. //.loadttfont exec pop
  1897. } {
  1898. % Not a TrueType font.
  1899. .loadnonttfontfile
  1900. } ifelse
  1901. } ifelse
  1902. } .forcebind def
  1903. % Undef the local utility funcs
  1904. [
  1905. /.findttfontname
  1906. /.findwoffname
  1907. /ttf_otf_tag_dict
  1908. /tt_tag_dict
  1909. /woff_tag_dict
  1910. /.is_ttf_or_otf
  1911. /.is_woff
  1912. ] currentdict .undefinternalnames
  1913. % ----- END .loadfontfile that supports possible TrueType font ------
  1914. % Undef these, not needed outside this file
  1915. [
  1916. /.addglyph
  1917. /.definettcidfont
  1918. /.fill_identity_cmap
  1919. /.findseg
  1920. /.loadttfontdict
  1921. /.is_hex_digit
  1922. /.pop3ex
  1923. /.popfex
  1924. /.ttkeys
  1925. /.printtab
  1926. /.readttdata
  1927. /.nname
  1928. /.loadttfont
  1929. /.loadwofffont
  1930. /.loadwofftables
  1931. /.findcmap
  1932. /.pdfmapsymbolic
  1933. /.pdfcharkeys
  1934. /.pdfmapchars
  1935. ] systemdict .undefinternalnames