]>
Commit | Line | Data |
---|---|---|
caddbb58 | 1 | % Copyright (C) 1990, 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved. |
2777fb4c | 2 | % |
3 | % This file is part of GNU Ghostscript. | |
4 | % | |
5 | % GNU Ghostscript is distributed in the hope that it will be useful, but | |
caddbb58 | 6 | % WITHOUT ANY WARRANTY. No author or distributor accepts responsibility |
7 | % to anyone for the consequences of using it or for whether it serves any | |
8 | % particular purpose or works at all, unless he says so in writing. Refer | |
9 | % to the GNU General Public License for full details. | |
2777fb4c | 10 | % |
11 | % Everyone is granted permission to copy, modify and redistribute GNU | |
12 | % Ghostscript, but only under the conditions described in the GNU General | |
caddbb58 | 13 | % Public License. A copy of this license is supposed to have been given |
14 | % to you along with GNU Ghostscript so you can know your rights and | |
2777fb4c | 15 | % responsibilities. It should be in a file named COPYING. Among other |
16 | % things, the copyright notice and this notice must be preserved on all | |
17 | % copies. | |
18 | % | |
caddbb58 | 19 | % Aladdin Enterprises supports the work of the GNU Project, but is not |
20 | % affiliated with the Free Software Foundation or the GNU Project. GNU | |
21 | % Ghostscript, as distributed by Aladdin Enterprises, does not require any | |
22 | % GNU software to build or run it. | |
2777fb4c | 23 | |
b5cb0608 | 24 | % $Id: gs_fonts.ps,v 1.2.2.1 2001/05/13 18:38:31 mike Exp $ |
2777fb4c | 25 | % Font initialization and management code. |
26 | ||
27 | % Define the default font. | |
28 | /defaultfontname /Courier def | |
29 | ||
30 | % Define the name of the font map file. | |
31 | /defaultfontmap (Fontmap) def | |
32 | ||
33 | % ------ End of editable parameters ------ % | |
34 | ||
caddbb58 | 35 | % If SUBSTFONT is defined, make it the default font. |
36 | /SUBSTFONT where { pop /defaultfontname /SUBSTFONT load def } if | |
37 | ||
38 | % Define a reliable way of accessing FontDirectory in systemdict. | |
39 | /.FontDirectory | |
40 | { /FontDirectory .systemvar | |
41 | } .bind odef | |
42 | ||
2777fb4c | 43 | % If DISKFONTS is true, we load individual CharStrings as they are needed. |
44 | % (This is intended primarily for machines with very small memories.) | |
45 | % In this case, we define another dictionary, parallel to FontDirectory, | |
46 | % that retains an open file for every font loaded. | |
47 | /FontFileDirectory 10 dict def | |
48 | ||
caddbb58 | 49 | % Define a temporary string for local use, since using =string |
50 | % interferes with some PostScript programs. | |
51 | /.fonttempstring 128 string def | |
52 | ||
2777fb4c | 53 | % Split up a search path into individual directories or files. |
54 | /.pathlist % <path> .pathlist <dir1|file1> ... | |
55 | { { dup length 0 eq { pop exit } if | |
56 | .filenamelistseparator search not { exit } if | |
57 | exch pop exch | |
58 | } | |
59 | loop | |
60 | } bind def | |
61 | ||
62 | % Load a font name -> font file name map. | |
caddbb58 | 63 | userdict /Fontmap .FontDirectory maxlength dict put |
2777fb4c | 64 | /.loadFontmap % <file> .loadFontmap - |
65 | { % We would like to simply execute .definefontmap as we read, | |
66 | % but we have to maintain backward compatibility with an older | |
67 | % specification that makes later entries override earlier. | |
68 | 50 dict exch | |
69 | { dup token not { closefile exit } if | |
70 | % stack: <file> fontname | |
71 | % This is a hack to get around the absurd habit of MS-DOS editors | |
72 | % of adding an EOF character at the end of the file. | |
73 | dup (\032) eq { pop closefile exit } if | |
74 | 1 index token not | |
75 | { (Fontmap entry for ) print dup =only | |
76 | ( has no associated file or alias name! Giving up.\n) print flush | |
77 | {.loadFontmap} 0 get 1 .quit | |
78 | } if | |
79 | dup type dup /stringtype eq exch /nametype eq or not | |
80 | { (Fontmap entry for ) print 1 index =only | |
81 | ( has an invalid file or alias name! Giving up.\n) print flush | |
82 | {.loadFontmap} 0 get 1 .quit | |
83 | } if | |
84 | % stack: dict file fontname filename|aliasname | |
85 | % Read and pop tokens until a semicolon. | |
86 | { 2 index token not | |
87 | { (Fontmap entry for ) print 1 index =only | |
88 | ( ends prematurely! Giving up.\n) print flush | |
89 | {.loadFontmap} 0 get 1 .quit | |
90 | } if | |
91 | dup /; eq { pop 3 index 3 1 roll .growput exit } if | |
92 | pop | |
93 | } loop | |
94 | } loop | |
95 | { .definefontmap } forall | |
96 | } bind def | |
97 | % Add an entry in Fontmap. We redefine this if the Level 2 | |
98 | % resource machinery is loaded. | |
99 | /.definefontmap % <fontname> <file|alias> .definefontmap - | |
100 | { % Since Fontmap is global, make sure the values are storable. | |
101 | .currentglobal 3 1 roll true .setglobal | |
102 | dup type /stringtype eq | |
103 | { dup .gcheck not { dup length string copy } if | |
104 | } | |
105 | if | |
106 | Fontmap 3 -1 roll 2 copy .knownget | |
107 | { % Add an element to the end of the existing value, | |
108 | % unless it's the same as the current last element. | |
109 | mark exch aload pop counttomark 4 add -1 roll | |
110 | 2 copy eq { cleartomark pop pop } { ] readonly .growput } ifelse | |
111 | } | |
112 | { % Make a new entry. | |
113 | mark 4 -1 roll ] readonly .growput | |
114 | } | |
115 | ifelse .setglobal | |
116 | } bind def | |
117 | ||
118 | % Parse a font file just enough to find the FontName or FontType. | |
119 | /.findfontvalue % <file> <key> .findfontvalue <value> true | |
120 | % <file> <key> .findfontvalue false | |
121 | % Closes the file in either case. | |
122 | { exch dup read not { -1 } if | |
123 | 2 copy unread 16#80 eq | |
124 | { dup (xxxxxx) readstring pop pop } % skip .PFB header | |
125 | if | |
126 | % Stack: key file | |
127 | { dup token not { false exit } if % end of file | |
128 | dup /eexec eq { pop false exit } if % reached eexec section | |
129 | dup /Subrs eq { pop false exit } if % Subrs without eexec | |
130 | dup /CharStrings eq { pop false exit } if % CharStrings without eexec | |
131 | dup 3 index eq | |
132 | { xcheck not { dup token exit } if } % found key | |
133 | { pop } | |
134 | ifelse | |
135 | } loop | |
136 | % Stack: key file value true (or) | |
137 | % Stack: key file false | |
138 | dup { 4 } { 3 } ifelse -2 roll closefile pop | |
139 | } bind def | |
140 | /.findfontname | |
141 | { /FontName .findfontvalue | |
142 | } bind def | |
143 | ||
144 | % If there is no FONTPATH, try to get one from the environment. | |
145 | NOFONTPATH { /FONTPATH () def } if | |
146 | /FONTPATH where | |
147 | { pop } | |
148 | { /FONTPATH (GS_FONTPATH) getenv not { () } if def } | |
149 | ifelse | |
150 | FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if | |
151 | /FONTPATH [ FONTPATH .pathlist ] def | |
152 | ||
153 | % Scan directories looking for plausible fonts. "Plausible" means that | |
154 | % the file begins with %!PS-AdobeFont or %!FontType1, or with \200\001 | |
155 | % followed by four arbitrary bytes and then either of these strings. | |
156 | % To speed up the search, we skip any file whose name appears in | |
157 | % the Fontmap (with any extension and upper/lower case variation) already, | |
158 | % and any file whose extension definitely indicates it is not a font. | |
159 | % | |
160 | % NOTE: The current implementation of this procedure is somewhat Unix/DOS- | |
161 | % specific. It assumes that '/' and '\' are directory separators, and that | |
162 | % the part of a file name following the last '.' is the extension. | |
163 | % | |
164 | /.lowerstring % <string> .lowerstring <lowerstring> | |
165 | { 0 1 2 index length 1 sub | |
166 | { 2 copy get dup 65 ge exch 90 le and | |
167 | { 2 copy 2 copy get 32 add put } | |
168 | if pop | |
169 | } | |
170 | for | |
171 | } bind def | |
172 | /.splitfilename % <dir.../base.extn> .basename <base> <extn> | |
173 | { { (/) search { true } { (\\) search } ifelse | |
174 | { pop pop } | |
175 | { exit } | |
176 | ifelse | |
177 | } | |
178 | loop | |
179 | dup { (.) search { pop pop } { exit } ifelse } loop | |
180 | 2 copy eq | |
181 | { pop () } | |
182 | { exch dup length 2 index length 1 add sub 0 exch getinterval exch } | |
183 | ifelse | |
184 | % Following is debugging code. | |
185 | % (*** Split => ) print 2 copy exch ==only ( ) print ==only | |
186 | % ( ***\n) print flush | |
187 | } bind def | |
188 | /.scanfontdict 1 dict def % establish a binding | |
189 | /.scanfontbegin | |
190 | { % Construct the table of all file names already in Fontmap. | |
191 | currentglobal true setglobal | |
192 | .scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength | |
193 | Fontmap | |
194 | { exch pop | |
195 | { dup type /stringtype eq | |
caddbb58 | 196 | { .splitfilename pop .fonttempstring copy .lowerstring cvn |
2777fb4c | 197 | .scanfontdict exch true put |
198 | } | |
199 | { pop | |
200 | } | |
201 | ifelse | |
202 | } | |
203 | forall | |
204 | } | |
205 | forall | |
206 | setglobal | |
207 | } bind def | |
208 | /.scanfontskip mark | |
209 | % Strings are converted to names anyway, so.... | |
210 | /afm true | |
211 | /bat true | |
212 | /c true | |
213 | /cmd true | |
214 | /com true | |
caddbb58 | 215 | /dir true |
2777fb4c | 216 | /dll true |
217 | /doc true | |
218 | /drv true | |
219 | /exe true | |
220 | /fon true | |
221 | /fot true | |
222 | /h true | |
223 | /o true | |
224 | /obj true | |
225 | /pfm true | |
caddbb58 | 226 | /pss true % Adobe Multiple Master font instances |
2777fb4c | 227 | /txt true |
228 | .dicttomark def | |
229 | /.scan1fontstring 128 string def | |
caddbb58 | 230 | /.scanfontheaders [(%!PS-Adobe*) (%!FontType*)] def |
2777fb4c | 231 | 0 .scanfontheaders { length max } forall 6 add % extra for PFB header |
232 | /.scan1fontfirst exch string def | |
233 | /.scanfontdir % <dirname> .scanfontdir - | |
234 | { currentglobal exch true setglobal | |
235 | QUIET not { (Scanning ) print dup print ( for fonts...) print flush } if | |
236 | (*) 2 copy .filenamedirseparator | |
237 | dup (\\) eq { pop (\\\\) } if % double \ for pattern match | |
238 | exch concatstrings concatstrings | |
239 | 0 0 0 4 -1 roll % found scanned files | |
240 | { % stack: <fontcount> <scancount> <filecount> <filename> | |
241 | exch 1 add exch % increment filecount | |
242 | dup .splitfilename .lowerstring | |
243 | % stack: <fontcount> <scancount> <filecount+1> <filename> | |
244 | % <BASE> <ext> | |
245 | .scanfontskip exch known exch .scanfontdict exch known or | |
246 | { pop | |
247 | % stack: <fontcount> <scancount> <filecount+1> | |
248 | } | |
249 | { 3 -1 roll 1 add 3 1 roll | |
250 | % stack: <fontcount> <scancount+1> <filecount+1> <filename> | |
251 | dup (r) { file } .internalstopped | |
252 | { pop pop null () | |
253 | % stack: <fontcount> <scancount+1> <filecount+1> <filename> | |
254 | % null () | |
255 | } | |
256 | { | |
257 | % On some platforms, the file operator will open directories, | |
258 | % but an error will occur if we try to read from one. | |
259 | % Handle this possibility here. | |
260 | dup .scan1fontfirst { readstring } .internalstopped | |
261 | { pop pop () } | |
262 | { pop } | |
263 | ifelse | |
264 | % stack: <fontcount> <scancount+1> <filecount+1> | |
265 | % <filename> <file> <header> | |
266 | } | |
267 | ifelse | |
268 | % Check for PFB file header. | |
269 | dup (\200\001????*) .stringmatch | |
270 | { dup length 6 sub 6 exch getinterval } | |
271 | if | |
272 | % Check for font file headers. | |
273 | false .scanfontheaders | |
274 | { 2 index exch .stringmatch or | |
275 | } | |
276 | forall exch pop | |
277 | { % stack: <fontcount> <scancount+1> <filecount+1> <filename> | |
278 | % <file> | |
279 | dup 0 setfileposition .findfontname | |
280 | { dup Fontmap exch known | |
281 | { pop pop | |
282 | } | |
283 | { exch copystring exch | |
b5cb0608 | 284 | DEBUG { dup =only (\n) print flush } if |
2777fb4c | 285 | 1 index .definefontmap |
286 | .splitfilename pop true .scanfontdict 3 1 roll .growput | |
287 | % Increment fontcount. | |
288 | 3 -1 roll 1 add 3 1 roll | |
289 | } | |
290 | ifelse | |
291 | } | |
292 | { pop | |
293 | } | |
294 | ifelse | |
295 | } | |
296 | % .findfontname will have done a closefile in the above case. | |
297 | { dup null eq { pop } { closefile } ifelse pop | |
298 | } | |
299 | ifelse | |
300 | } | |
301 | ifelse | |
302 | } | |
303 | .scan1fontstring filenameforall | |
304 | QUIET | |
305 | { pop pop pop } | |
306 | { ( ) print =only ( files, ) print =only ( scanned, ) print | |
307 | =only ( new fonts.\n) print flush | |
308 | } | |
309 | ifelse | |
310 | setglobal | |
311 | } bind def | |
312 | ||
313 | %END FONTPATH | |
314 | ||
caddbb58 | 315 | % Create the dictionary that registers the .buildfont procedure (called by |
316 | % definefont) for each FontType. | |
317 | /buildfontdict 20 dict def | |
318 | ||
319 | % Register Type 3 fonts, which are always supported, for definefont. | |
320 | buildfontdict 3 /.buildfont3 cvx put | |
321 | ||
322 | % Register Type 0 fonts if they are supported. Strictly speaking, | |
323 | % we should do this in its own file (gs_type0.ps), but since this is | |
324 | % the only thing that would be in that file, it's simpler to put it here. | |
325 | /.buildfont0 where { pop buildfontdict 0 /.buildfont0 cvx put } if | |
326 | ||
2777fb4c | 327 | % Define definefont. This is a procedure built on a set of operators |
328 | % that do all the error checking and key insertion. | |
2777fb4c | 329 | /.growfontdict |
330 | { % Grow the font dictionary, if necessary, to ensure room for an | |
331 | % added entry, making sure there is at least one slot left for FID. | |
332 | dup maxlength 1 index length sub 2 lt | |
333 | { dup dup wcheck | |
334 | { .growdict } | |
335 | { .growdictlength dict .copydict } | |
336 | ifelse | |
337 | } | |
338 | { dup wcheck not { dup maxlength dict .copydict } if | |
339 | } | |
340 | ifelse | |
341 | } bind def | |
caddbb58 | 342 | /.completefont { |
343 | { % Check for disabled platform fonts. | |
2777fb4c | 344 | NOPLATFONTS |
345 | { % Make sure we leave room for FID. | |
346 | .growfontdict dup /ExactSize 0 put | |
347 | } | |
348 | { % Hack: if the Encoding looks like it might be the | |
349 | % Symbol or Dingbats encoding, load those now (for the | |
350 | % benefit of platform font matching) just in case | |
351 | % the font didn't actually reference them. | |
caddbb58 | 352 | % Note that some types of font don't have an Encoding. |
353 | dup /Encoding .knownget { | |
354 | dup length 65 ge { | |
355 | 64 get | |
356 | dup /congruent eq { SymbolEncoding pop } if | |
357 | /a9 eq { DingbatsEncoding pop } if | |
358 | } { | |
359 | pop | |
360 | } ifelse | |
361 | } if | |
2777fb4c | 362 | } |
363 | ifelse | |
caddbb58 | 364 | true exch |
365 | dup /FontType known not { | |
366 | % This might be a CIDFont. | |
367 | dup /CIDFontType known { | |
368 | /.buildcidfont where { | |
369 | pop exch pop false exch | |
370 | } if | |
371 | } if | |
372 | } if | |
373 | exch { | |
374 | dup /FontType get //buildfontdict exch get exec | |
375 | } { | |
376 | .buildcidfont | |
377 | } ifelse | |
378 | ||
2777fb4c | 379 | DISKFONTS |
380 | { FontFileDirectory 2 index known | |
381 | { dup /FontFile FontFileDirectory 4 index get .growput | |
382 | } | |
383 | if | |
384 | } | |
385 | if | |
caddbb58 | 386 | readonly % stack: name fontdict |
387 | } stopped { /invalidfont signalerror } if | |
388 | } bind odef | |
389 | /definefont | |
390 | { .completefont | |
2777fb4c | 391 | % If the current allocation mode is global, also enter |
392 | % the font in LocalFontDirectory. | |
caddbb58 | 393 | .currentglobal |
394 | { //systemdict /LocalFontDirectory .knownget | |
395 | { 2 index 2 index .growput } | |
2777fb4c | 396 | if |
2777fb4c | 397 | } |
caddbb58 | 398 | if |
399 | dup .FontDirectory 4 -2 roll .growput | |
2777fb4c | 400 | } odef |
401 | ||
402 | % Define a procedure for defining aliased fonts. | |
caddbb58 | 403 | % We use this only for explicitly aliased fonts, not substituted fonts: |
404 | % we think this matches the observed behavior of Adobe interpreters. | |
2777fb4c | 405 | /.aliasfont % <name> <font> .aliasfont <newFont> |
406 | { .currentglobal 3 1 roll dup .gcheck .setglobal | |
407 | dup length 2 add dict | |
408 | dup 3 -1 roll { 1 index /FID eq { pop pop } { put dup } ifelse } forall | |
409 | % Stack: global fontname newfont newfont. | |
410 | % We might be defining a global font whose FontName | |
411 | % is a local string. This is weird, but legal, | |
caddbb58 | 412 | % and doesn't cause problems anywhere else: |
413 | % to avoid any possible problems in this case, do a cvn. | |
414 | % We might also be defining (as an alias) a global font | |
415 | % whose FontName is a local non-string, if someone passed a | |
416 | % garbage value to findfont. In this case, just don't | |
417 | % call definefont at all. | |
418 | 2 index dup type /stringtype eq exch .gcheck or 1 index .gcheck not or | |
419 | { /FontName 3 index dup type /stringtype eq { cvn } if put | |
420 | % Don't bind in definefont, since Level 2 redefines it. | |
421 | /definefont .systemvar exec | |
2777fb4c | 422 | } |
caddbb58 | 423 | { .completefont pop exch pop |
2777fb4c | 424 | } |
caddbb58 | 425 | ifelse exch .setglobal |
2777fb4c | 426 | } odef % so findfont will bind it |
427 | ||
428 | % Define .loadfontfile for loading a font. If we recognize Type 1 and/or | |
429 | % TrueType fonts, gs_type1.ps and/or gs_ttf.ps will redefine this. | |
caddbb58 | 430 | /.loadfontfile { |
431 | % According to Ed Taft, Adobe interpreters push userdict | |
432 | % before loading a font, and pop it afterwards. | |
433 | userdict begin | |
434 | cvx exec | |
435 | end | |
436 | } bind def | |
2777fb4c | 437 | /.loadfont |
438 | { % Some buggy fonts leave extra junk on the stack, | |
439 | % so we have to make a closure that records the stack depth | |
440 | % in a fail-safe way. | |
441 | /.loadfontfile cvx count 1 sub 2 packedarray cvx exec | |
442 | count exch sub { pop } repeat | |
443 | } bind def | |
444 | ||
445 | % Find an alternate font to substitute for an unknown one. | |
446 | % We go to some trouble to parse the font name and extract | |
447 | % properties from it. Later entries take priority over earlier. | |
448 | /.substitutefaces [ | |
449 | % Guess at suitable substitutions for random unknown fonts. | |
450 | [(Grot) /Times] | |
451 | [(Roman) /Times] | |
452 | [(Book) /NewCenturySchlbk] | |
453 | % If the family name appears in the font name, | |
454 | % use a font from that family. | |
455 | [(Arial) /Helvetica] | |
456 | [(Avant) /AvantGarde] | |
457 | [(Bookman) /Bookman] | |
458 | [(Century) /NewCenturySchlbk] | |
459 | [(Cour) /Courier] | |
caddbb58 | 460 | [(Frut) /Helvetica] |
2777fb4c | 461 | [(Geneva) /Helvetica] |
462 | [(Helv) /Helvetica] | |
463 | [(NewYork) /Times] | |
464 | [(Pala) /Palatino] | |
465 | [(Sans) /Helvetica] | |
466 | [(Schlbk) /NewCenturySchlbk] | |
467 | [(Serif) /Times] | |
468 | [(Swiss) /Helvetica] | |
469 | [(Times) /Times] | |
caddbb58 | 470 | [(Univers) /Helvetica] |
2777fb4c | 471 | % Substitute for Adobe Multiple Master fonts. |
caddbb58 | 472 | [(Minion) /Times] |
473 | [(Myriad) /Helvetica] | |
474 | [(MyriadPkg) /Helvetica-Narrow] | |
2777fb4c | 475 | % Condensed or narrow fonts map to the only narrow family we have. |
476 | [(Cond) /Helvetica-Narrow] | |
477 | [(Narrow) /Helvetica-Narrow] | |
478 | % If the font wants to be monospace, use Courier. | |
479 | [(Monospace) /Courier] | |
480 | [(Typewriter) /Courier] | |
481 | ] readonly def | |
482 | /.substituteproperties [ | |
483 | [(It) 1] [(Oblique) 1] | |
484 | [(Bd) 2] [(Bold) 2] [(bold) 2] [(Demi) 2] [(Heavy) 2] [(Sb) 2] | |
485 | ] readonly def | |
486 | /.substitutefamilies mark | |
487 | /AvantGarde | |
488 | {/AvantGarde-Book /AvantGarde-BookOblique | |
489 | /AvantGarde-Demi /AvantGarde-DemiOblique} | |
490 | /Bookman | |
491 | {/Bookman-Demi /Bookman-DemiItalic /Bookman-Light /Bookman-LightItalic} | |
492 | /Courier | |
493 | {/Courier /Courier-Oblique /Courier-Bold /Courier-BoldOblique} | |
494 | /Helvetica | |
495 | {/Helvetica /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique} | |
496 | /Helvetica-Narrow | |
497 | {/Helvetica-Narrow /Helvetica-Narrow-Oblique | |
498 | /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique} | |
499 | /NewCenturySchlbk | |
500 | {/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic | |
501 | /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic} | |
502 | /Palatino | |
503 | {/Palatino-Roman /Palatino-Italic /Palatino-Bold /Palatino-BoldItalic} | |
504 | /Times | |
505 | {/Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic} | |
506 | .dicttomark readonly def | |
507 | /.substitutefont % <fontname> .substitutefont <altname> | |
508 | { % Look for properties and/or a face name in the font name. | |
509 | % If we find any, use Helvetica as the base font; | |
510 | % otherwise, use the default font. | |
511 | % Note that the "substituted" font name may be the same as | |
512 | % the requested one; the caller must check this. | |
caddbb58 | 513 | dup type dup /stringtype eq exch /nametype eq or |
514 | { dup length string cvs } { () } ifelse | |
2777fb4c | 515 | {defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique} |
516 | exch 0 exch % stack: fontname facelist properties fontname | |
517 | % Look for a face name. | |
518 | .substitutefaces | |
519 | { 2 copy 0 get search | |
520 | { pop pop pop 1 get .substitutefamilies exch get | |
521 | 4 -1 roll pop 3 1 roll | |
522 | } | |
523 | { pop pop | |
524 | } | |
525 | ifelse | |
526 | } | |
527 | forall | |
528 | .substituteproperties | |
529 | { 2 copy 0 get search | |
530 | { pop pop pop 1 get 3 -1 roll or exch } | |
531 | { pop pop } | |
532 | ifelse | |
533 | } | |
caddbb58 | 534 | forall pop get exec |
2777fb4c | 535 | % Only accept fonts known in the Fontmap. |
536 | Fontmap 1 index known not { pop defaultfontname } if | |
537 | } bind def | |
538 | ||
539 | % If requested, make (and recognize) fake entries in FontDirectory for fonts | |
540 | % present in Fontmap but not actually loaded. Thanks to Ray Johnston for | |
541 | % the idea behind this code. | |
542 | FAKEFONTS not { (%END FAKEFONTS) .skipeof } if | |
543 | ||
544 | % We use the presence or absence of the FontMatrix key to indicate whether | |
caddbb58 | 545 | % a font is real or fake. We must pop the arguments at the very end, |
546 | % so that stack protection will be effective. | |
547 | ||
548 | /definefont { % <name> <font> definefont <font> | |
549 | dup /FontMatrix known { | |
550 | //definefont | |
551 | } { | |
552 | 2 copy /FontName get findfont //definefont exch pop exch pop | |
553 | } ifelse | |
554 | } bind odef | |
555 | ||
556 | /scalefont { % <font> <scale> scalefont <font> | |
557 | 1 index /FontMatrix known { | |
558 | //scalefont | |
559 | } { | |
560 | 1 index /FontName get findfont 1 index //scalefont | |
561 | exch pop exch pop | |
562 | } ifelse | |
563 | } bind odef | |
564 | ||
565 | /makefont { % <font> <matrix> makefont <font> | |
566 | 1 index /FontMatrix known { | |
567 | //makefont | |
568 | } { | |
569 | 1 index /FontName get findfont 1 index //makefont | |
570 | exch pop exch pop | |
571 | } ifelse | |
572 | } bind odef | |
573 | ||
574 | /setfont { % <font> setfont - | |
575 | dup /FontMatrix known { | |
576 | //setfont | |
577 | } { | |
578 | dup /FontName get findfont //setfont pop | |
579 | } ifelse | |
580 | } bind odef | |
2777fb4c | 581 | |
582 | %END FAKEFONTS | |
583 | ||
584 | % Define findfont so it tries to load a font if it's not found. | |
caddbb58 | 585 | % The Red Book requires that findfont be a procedure, not an operator, |
586 | % but it still needs to restore the stacks reliably if it fails, | |
587 | % so we do all the work in an operator. | |
588 | /.findfont { | |
589 | mark 1 index | |
590 | //systemdict begin .dofindfont | |
591 | % Define any needed aliases. | |
592 | counttomark 1 sub { .aliasfont } repeat end | |
593 | exch pop exch pop | |
594 | } odef | |
595 | /findfont { | |
596 | .findfont | |
597 | } bind def | |
2777fb4c | 598 | % Check whether the font name we are about to look for is already on the list |
599 | % of aliases we're accumulating; if so, cause an error. | |
600 | /.checkalias % -mark- <alias1> ... <name> .checkalias <<same>> | |
601 | { counttomark 1 sub -1 1 | |
602 | { index 1 index eq | |
603 | { pop QUIET not | |
604 | { (Unable to substitute for font.\n) print flush | |
605 | } if | |
606 | /findfont cvx /invalidfont signalerror | |
607 | } | |
608 | if | |
609 | } | |
610 | for | |
611 | } bind def | |
612 | % Get a (non-fake) font if present in a FontDirectory. | |
613 | /.fontknownget % <fontdir> <fontname> .fontknownget <font> true | |
614 | % <fontdir> <fontname> .fontknownget false | |
615 | { .knownget | |
616 | { FAKEFONTS | |
617 | { dup /FontMatrix known { true } { pop false } ifelse } | |
618 | { true } | |
619 | ifelse | |
620 | } | |
621 | { false | |
622 | } | |
623 | ifelse | |
624 | } bind def | |
625 | % Do the work of findfont, including substitution, defaulting, and | |
626 | % scanning of FONTPATH. | |
627 | /.dofindfont % <fontname> .dofindfont <font> | |
628 | { { .tryfindfont { exit } if | |
629 | % We didn't find the font. If we haven't scanned | |
630 | % all the directories in FONTPATH, scan the next one now, | |
631 | % and look for the font again. | |
632 | null 0 1 FONTPATH length 1 sub | |
633 | { FONTPATH 1 index get null ne { exch pop exit } if pop | |
634 | } | |
635 | for dup null ne | |
636 | { dup 0 eq { .scanfontbegin } if | |
637 | FONTPATH 1 index get .scanfontdir | |
638 | FONTPATH exch null put | |
639 | % Start over with an empty alias list. | |
640 | counttomark 1 sub { pop } repeat | |
641 | .dofindfont exit | |
642 | } | |
643 | if pop | |
caddbb58 | 644 | % No luck. Make sure we're not already |
645 | % looking for the default font. | |
2777fb4c | 646 | dup defaultfontname eq |
647 | { QUIET not | |
648 | { (Unable to load default font ) print | |
649 | dup =only (! Giving up.\n) print flush | |
650 | } | |
651 | if /findfont cvx /invalidfont signalerror | |
652 | } | |
2777fb4c | 653 | if |
caddbb58 | 654 | % Substitute for the font. Don't alias. |
655 | /SUBSTFONT where { | |
656 | pop QUIET not { | |
657 | (Substituting for font ) print dup =only | |
658 | (.\n) print flush | |
659 | } if | |
660 | cleartomark mark defaultfontname | |
661 | } { | |
662 | dup .substitutefont | |
663 | 2 copy eq { pop defaultfontname } if | |
664 | .checkalias | |
665 | QUIET not { | |
666 | (Substituting font ) print dup =only ( for ) print | |
667 | 1 index =only (.\n) print flush | |
668 | } if | |
669 | % Remove all the accumulated aliases. | |
670 | counttomark 1 add 1 roll cleartomark mark exch | |
671 | } ifelse | |
2777fb4c | 672 | } |
673 | loop | |
674 | } bind def | |
675 | % Try to find a font using only the present contents of Fontmap. | |
676 | /.tryfindfont % <fontname> .tryfindfont <font> true | |
677 | % <fontname> .tryfindfont false | |
caddbb58 | 678 | { .FontDirectory 1 index .fontknownget |
2777fb4c | 679 | { % Already loaded |
680 | exch pop true | |
681 | } | |
682 | { dup Fontmap exch .knownget not | |
caddbb58 | 683 | { % Unknown font name. Look for a file with the |
684 | % same name as the requested font. | |
685 | dup dup type /nametype eq { .namestring } if .loadfontloop | |
2777fb4c | 686 | } |
2777fb4c | 687 | { % Try each element of the Fontmap in turn. |
caddbb58 | 688 | false exch % (in case we exhaust the list) |
689 | % Stack: fontname false fontmaplist | |
2777fb4c | 690 | { exch pop |
691 | dup type /nametype eq | |
692 | { % Font alias | |
693 | .checkalias .tryfindfont exit | |
694 | } | |
695 | { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and | |
696 | { % Font with a procedural definition | |
697 | exec % The procedure will load the font. | |
698 | % Check to make sure this really happened. | |
caddbb58 | 699 | .FontDirectory 1 index .knownget |
2777fb4c | 700 | { exch pop true exit } |
701 | if | |
702 | } | |
703 | { % Font file name | |
704 | .loadfontloop { true exit } if | |
705 | } | |
706 | ifelse | |
707 | } | |
708 | ifelse false | |
709 | } | |
caddbb58 | 710 | forall |
711 | % Stack: font true -or- fontname false | |
712 | { true | |
713 | } | |
714 | { % None of the Fontmap entries worked. | |
715 | % Try loading a file with the same name | |
716 | % as the requested font. | |
717 | dup dup type /nametype eq { .namestring } if .loadfontloop | |
718 | } | |
719 | ifelse | |
2777fb4c | 720 | } |
721 | ifelse | |
722 | } | |
723 | ifelse | |
724 | } bind def | |
725 | % Attempt to load a font from a file. | |
726 | /.loadfontloop % <filename> .loadfontloop <font> true | |
727 | % <filename> .loadfontloop false | |
728 | { % See above regarding the use of 'loop'. | |
729 | ||
730 | { | |
caddbb58 | 731 | % Is the font name a string? |
732 | dup type /stringtype ne | |
733 | { QUIET not | |
734 | { (Can't find font with non-string name: ) print dup =only (.\n) print flush | |
735 | } | |
736 | if pop false exit | |
737 | } | |
738 | if | |
2777fb4c | 739 | % Can we open the file? |
740 | findlibfile not | |
741 | { QUIET not | |
742 | { (Can't find \(or can't open\) font file ) print dup print | |
743 | (.\n) print flush | |
744 | } | |
745 | if pop false exit | |
746 | } | |
747 | if | |
748 | ||
749 | % Stack: fontname fontfilename fontfile | |
750 | DISKFONTS | |
751 | { .currentglobal true .setglobal | |
752 | 2 index (r) file | |
753 | FontFileDirectory exch 5 index exch .growput | |
754 | .setglobal | |
755 | } | |
756 | if | |
757 | QUIET not | |
758 | { (Loading ) print 2 index =only | |
759 | ( font from ) print 1 index print (... ) print flush | |
760 | } | |
761 | if | |
762 | % If LOCALFONTS isn't set, load the font into local or global | |
763 | % VM according to FontType; if LOCALFONTS is set, load the font | |
764 | % into the current VM, which is what Adobe printers (but not | |
765 | % DPS or CPSI) do. | |
766 | LOCALFONTS { false } { /setglobal where } ifelse | |
767 | { pop /FontType .findfontvalue { 1 eq } { false } ifelse | |
768 | % .setglobal, like setglobal, aliases FontDirectory to | |
769 | % GlobalFontDirectory if appropriate. However, we mustn't | |
770 | % allow the current version of .setglobal to be bound in, | |
771 | % because it's different depending on language level. | |
caddbb58 | 772 | .currentglobal exch /.setglobal .systemvar exec |
2777fb4c | 773 | % Remove the fake definition, if any. |
caddbb58 | 774 | .FontDirectory 3 index .undef |
775 | 1 index (r) file .loadfont .FontDirectory exch | |
776 | /.setglobal .systemvar exec | |
2777fb4c | 777 | } |
caddbb58 | 778 | { .loadfont .FontDirectory |
2777fb4c | 779 | } |
780 | ifelse | |
781 | % Stack: fontname fontfilename fontdirectory | |
782 | QUIET not | |
783 | { //systemdict /level2dict known | |
784 | { .currentglobal false .setglobal vmstatus | |
785 | true .setglobal vmstatus 3 -1 roll pop | |
786 | 6 -1 roll .setglobal 5 | |
787 | } | |
788 | { vmstatus 3 | |
789 | } | |
790 | ifelse { =only ( ) print } repeat | |
791 | (done.\n) print flush | |
792 | } if | |
793 | ||
794 | % Check to make sure the font was actually loaded. | |
795 | dup 3 index .fontknownget | |
796 | { 4 1 roll pop pop pop true exit } if | |
797 | ||
798 | % Maybe the file had a different FontName. | |
799 | % See if we can get a FontName from the file, and if so, | |
800 | % whether a font by that name exists now. | |
801 | exch (r) file .findfontname | |
802 | { 2 copy .fontknownget | |
803 | { % Yes. Stack: origfontname fontdirectory filefontname fontdict | |
804 | 3 -1 roll pop exch | |
805 | QUIET | |
806 | { pop | |
807 | } | |
808 | { (Using ) print =only | |
809 | ( font for ) print 1 index =only | |
810 | (.\n) print flush | |
811 | } | |
812 | ifelse true exit | |
813 | } | |
814 | if pop | |
815 | } | |
816 | if pop | |
817 | ||
818 | % The font definitely did not load correctly. | |
819 | QUIET not | |
820 | { (Loading ) print dup =only | |
821 | ( font failed.\n) print flush | |
822 | } if | |
823 | false exit | |
824 | ||
825 | } loop % end of loop | |
826 | ||
827 | } bind def | |
828 | ||
829 | % Define a procedure to load all known fonts. | |
830 | % This isn't likely to be very useful. | |
831 | /loadallfonts | |
832 | { Fontmap { pop findfont pop } forall | |
833 | } bind def | |
834 | ||
835 | % If requested, load all the fonts defined in the Fontmap into FontDirectory | |
caddbb58 | 836 | % as "fake" fonts i.e., font dicts with only FontName and FontType defined. |
837 | % (We define FontType only for the sake of some questionable code in the | |
838 | % Apple Printer Utility 2.0 font inquiry code.) | |
839 | % | |
840 | % Note that this procedure only creates fake fonts in the FontDirectory | |
841 | % associated with the current VM. This is because in multi-context systems, | |
842 | % creating the fake fonts in local VM leads to undesirable complications. | |
2777fb4c | 843 | /.definefakefonts |
844 | { | |
845 | } | |
caddbb58 | 846 | { |
847 | (gs_fonts FAKEFONTS) VMDEBUG | |
848 | Fontmap { | |
849 | pop dup type /stringtype eq { cvn } if | |
850 | .FontDirectory 1 index known not { | |
851 | 2 dict dup /FontName 3 index put | |
852 | dup /FontType 1 put | |
853 | .FontDirectory 3 1 roll put | |
854 | } { | |
855 | pop | |
856 | } ifelse | |
857 | } forall | |
2777fb4c | 858 | } |
caddbb58 | 859 | FAKEFONTS { exch } if pop def % don't bind, .current/setglobal get redefined |
2777fb4c | 860 | |
861 | % Install initial fonts from Fontmap. | |
862 | /.loadinitialfonts | |
863 | { NOFONTMAP not | |
864 | { /FONTMAP where | |
865 | { pop [ FONTMAP .pathlist ] | |
866 | { dup VMDEBUG findlibfile | |
867 | { exch pop .loadFontmap } | |
868 | { /undefinedfilename signalerror } | |
869 | ifelse | |
870 | } | |
871 | } | |
872 | { LIBPATH | |
873 | { defaultfontmap 2 copy .filenamedirseparator | |
874 | exch concatstrings concatstrings dup VMDEBUG | |
875 | (r) { file } .internalstopped | |
876 | { pop pop } { .loadFontmap } ifelse | |
877 | } | |
878 | } | |
879 | ifelse forall | |
880 | } | |
881 | if | |
caddbb58 | 882 | .definefakefonts % current VM is global |
2777fb4c | 883 | } def % don't bind, .current/setglobal get redefined |
caddbb58 | 884 | |
885 | % ---------------- Synthetic font support ---------------- % | |
886 | ||
887 | % Create a new font by modifying an existing one. paramdict contains | |
888 | % entries with the same keys as the ones found in a Type 1 font; | |
889 | % it should also contain enough empty entries to allow adding the | |
890 | % corresponding non-overridden entries from the original font dictionary, | |
891 | % including FID. If paramdict includes a FontInfo entry, this will | |
892 | % also override the original font's FontInfo, entry by entry; | |
893 | % again, it must contain enough empty entries. | |
894 | ||
895 | % Note that this procedure does not perform a definefont. | |
896 | ||
897 | /.makemodifiedfont % <fontdict> <paramdict> .makemodifiedfont <fontdict'> | |
898 | { exch | |
899 | { % Stack: destdict key value | |
900 | 1 index /FID ne | |
901 | { 2 index 2 index known | |
902 | { % Skip fontdict entry supplied in paramdict, but | |
903 | % handle FontInfo specially. | |
904 | 1 index /FontInfo eq | |
905 | { 2 index 2 index get % new FontInfo | |
906 | 1 index % old FontInfo | |
907 | { % Stack: destdict key value destinfo key value | |
908 | 2 index 2 index known | |
909 | { pop pop } | |
910 | { 2 index 3 1 roll put } | |
911 | ifelse | |
912 | } | |
913 | forall pop | |
914 | } | |
915 | if | |
916 | } | |
917 | { % No override, copy the fontdict entry. | |
918 | 2 index 3 1 roll put | |
919 | dup dup % to match pop pop below | |
920 | } | |
921 | ifelse | |
922 | } | |
923 | if | |
924 | pop pop | |
925 | } forall | |
926 | } bind def | |
927 | ||
928 | % Make a modified font and define it. Note that unlike definefont, | |
929 | % this does not leave the font on the operand stack. | |
930 | ||
931 | /.definemodifiedfont % <fontdict> <paramdict> .definemodifiedfont - | |
932 | { .makemodifiedfont | |
933 | dup /FontName get exch definefont pop | |
934 | } bind def |