home *** CD-ROM | disk | FTP | other *** search
/ swCHIP 1991 January / swCHIP_95-1.bin / utility / gs333ini / gs3.33 / gs_fonts.ps < prev    next >
Text File  |  1995-12-09  |  21KB  |  664 lines

  1. %    Copyright (C) 1990, 1995 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % Font initialization and management code.
  16.  
  17. % Define the default font.
  18. /defaultfontname /Courier def
  19.  
  20. % Define the name of the font map file.
  21. /fontmapname (Fontmap) def
  22.  
  23. % If DISKFONTS is true, we load individual CharStrings as they are needed.
  24. % (This is intended primarily for machines with very small memories.)
  25. % In this case, we define another dictionary, parallel to FontDirectory,
  26. % that retains an open file for every font loaded.
  27. /FontFileDirectory 10 dict def
  28.  
  29. % Load the font name -> font file name map.
  30. userdict /Fontmap FontDirectory maxlength dict put
  31. /.loadFontmap        % <file> .loadFontmap -
  32.  {  { dup token not { closefile exit } if
  33.         % stack: <file> fontname
  34.       1 index token not
  35.        { (File or alias name missing in Fontmap!  Giving up.\n) print flush
  36.          {.loadFontmap} 0 get 1 .quit
  37.        } if
  38.       dup type dup /stringtype eq exch /nametype eq or not
  39.        { (Invalid file or alias name in Fontmap!  Giving up.\n) print flush
  40.          {.loadFontmap} 0 get 1 .quit
  41.        } if
  42.         % stack: <file> fontname filename|aliasname
  43.         % Read and pop tokens until a semicolon.
  44.        { 2 index token not
  45.       { (Semicolon missing in Fontmap!  Giving up.\n) print flush
  46.         {.loadFontmap} 0 get 1 .quit
  47.       } if
  48.      dup /; eq { pop .definefontmap exit } if
  49.      pop
  50.        } loop
  51.     } loop 
  52.  } bind def
  53. % Make an entry in Fontmap.  We redefine this if the Level 2
  54. % resource machinery is loaded.
  55. /.definefontmap            % <fontname> <file|alias> .definefontmap -
  56.  { Fontmap 3 1 roll .growput
  57.  } bind def
  58.  
  59. % If there is no FONTPATH, get one from the environment.
  60. /FONTPATH where
  61.  { pop }
  62.  { (GS_FONTPATH) getenv { /FONTPATH exch def } if }
  63. ifelse
  64.  
  65. % If we can't find a Fontmap, try using the FONTPATH.
  66. fontmapname findlibfile
  67.  { exch pop .loadFontmap }
  68.  { pop /FONTPATH where
  69.     { pop }
  70.     { fontmapname /undefinedfilename signalerror }
  71.    ifelse
  72.  }
  73. ifelse
  74.  
  75. % Parse a font file just enough to find the FontName or FontType.
  76. /.findfontvalue        % <file> <key> .findfontvalue <name> true
  77.             % <file> <key> .findfontvalue false
  78.             % Closes the file in either case.
  79.  { exch dup read not { -1 } if
  80.    2 copy unread 16#80 eq
  81.     { dup (xxxxxx) readstring pop pop }        % skip .PFB header
  82.    if
  83.     { dup token not { false exit } if        % end of file
  84.       dup /eexec eq { pop false exit } if    % reached eexec section
  85.       dup /Subrs eq { pop false exit } if    % Subrs without eexec
  86.       dup /CharStrings eq { pop false exit } if    % CharStrings without eexec
  87.       dup 3 index eq
  88.        { xcheck not { dup token exit } if }    % found key
  89.        { pop }
  90.       ifelse
  91.     } loop
  92.    dup { 4 } { 3 } ifelse -2 roll closefile pop
  93.  } bind def
  94. /.findfontname
  95.  { /FontName .findfontvalue
  96.  } bind def
  97.  
  98. /FONTPATH where not { (%END FONTPATH) .skipeof } if
  99. pop
  100.  
  101. % Scan directories looking for plausible fonts.  "Plausible" means that
  102. % the file begins with %!PS-AdobeFont- or %!FontType1-, or with \200\001
  103. % followed by four arbitrary bytes and then either of these strings.
  104. % To speed up the search, we skip any file whose name appears in
  105. % the Fontmap (with any extension and upper/lower case variation) already,
  106. % and any file whose extension definitely indicates it is not a font.
  107. %
  108. % NOTE: The current implementation of this procedure is Unix/DOS-
  109. % specific.  It assumes that '/' and '\' are directory separators; that
  110. % the part of a file name following the last '.' is the extension;
  111. % that ';' cannot appear in a file name; and that ':' can appear in a
  112. % file name only if the file name doesn't begin with '/', '\', or '.'.
  113. % (this is so that Unix systems can use ':' as the separator).
  114. %
  115. /.lowerstring        % <string> .lowerstring <lowerstring>
  116.  { 0 1 2 index length 1 sub
  117.     { 2 copy get dup 65 ge exch 90 le and
  118.        { 2 copy 2 copy get 32 add put }
  119.      if pop
  120.     }
  121.    for
  122.  } bind def
  123. /.splitfilename        % <dir.../base.extn> .basename <base> <extn>
  124.  {  { (/) search { true } { (\\) search } ifelse
  125.        { pop pop }
  126.        { exit }
  127.       ifelse
  128.     }
  129.    loop
  130.    dup { (.) search { pop pop } { exit } ifelse } loop
  131.    2 copy eq
  132.     { pop () }
  133.     { exch dup length 2 index length 1 add sub 0 exch getinterval exch }
  134.    ifelse
  135. % Following is debugging code.
  136. %   (*** Split => ) print 2 copy exch ==only ( ) print ==only
  137. %   ( ***\n) print flush
  138.  } bind def
  139. /.scanfontdict Fontmap maxlength dict def
  140. /.scanfontbegin
  141.  {    % Construct the table of all file names already in Fontmap.
  142.    Fontmap
  143.     { exch pop dup type /stringtype eq
  144.        { .splitfilename pop =string copy .lowerstring cvn
  145.          .scanfontdict exch true .growput
  146.        }
  147.        { pop
  148.        }
  149.       ifelse
  150.     }
  151.    forall
  152.  } bind def
  153. /.scanfontskip mark
  154.         % Strings are converted to names anyway, so....
  155.   /afm true
  156.   /bat true
  157.   /c true
  158.   /cmd true
  159.   /com true
  160.   /dll true
  161.   /doc true
  162.   /exe true
  163.   /h true
  164.   /o true
  165.   /obj true
  166.   /pfm true
  167.   /txt true
  168. .dicttomark def
  169. /.scan1fontstring 128 string def
  170. /.fontheaders [(%!PS-AdobeFont-*) (%!FontType1-*)] def
  171. 0 .fontheaders { length max } forall 6 add    % extra for PFB header
  172. /.scan1fontfirst exch string def
  173. /.scan1fontdir        % <dirname> .scan1fontdir -
  174.  { QUIET not { (Scanning ) print dup print ( for fonts...) print flush } if
  175.    (/*) concatstrings 0 0 0 4 -1 roll    % found scanned files
  176.     {        % stack: <fontcount> <scancount> <filecount> <filename>
  177.       exch 1 add exch                   % increment filecount
  178.       dup .splitfilename .lowerstring
  179.         % stack: <fontcount> <scancount> <filecount+1> <filename>
  180.         %    <BASE> <ext>
  181.       .scanfontskip exch known exch .scanfontdict exch known or
  182.        { pop
  183.         % stack: <fontcount> <scancount> <filecount+1>
  184.        }
  185.        { 3 -1 roll 1 add 3 1 roll
  186.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  187.          dup (r) { file } stopped
  188.       { pop pop null () 
  189.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  190.         %    null ()
  191.           }
  192.       { 
  193.         % On some platforms, the file operator will open directories,
  194.         % but an error will occur if we try to read from one.
  195.         % Handle this possibility here.
  196.         dup .scan1fontfirst { readstring } stopped
  197.          { pop pop () }
  198.          { pop }
  199.         ifelse 
  200.         % stack: <fontcount> <scancount+1> <filecount+1>
  201.         %    <filename> <file> <header>
  202.           }
  203.      ifelse
  204.         % Check for PFB file header.
  205.      dup (\200\001????*) .stringmatch
  206.       { dup length 6 sub 6 exch getinterval }
  207.      if
  208.         % Check for font file headers.
  209.      false .fontheaders { 2 index exch .stringmatch or } forall exch pop
  210.       {    % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  211.         %    <file>
  212.             dup 0 setfileposition .findfontname
  213.          { dup Fontmap exch known
  214.         { pop pop
  215.         }
  216.         { exch copystring exch
  217.           DEBUG { ( ) print dup =only } if
  218.           1 index .definefontmap
  219.           .splitfilename pop true .scanfontdict 3 1 roll .growput
  220.             % Increment fontcount.
  221.           3 -1 roll 1 add 3 1 roll
  222.         }
  223.            ifelse
  224.          }
  225.         if
  226.       }
  227.         % .findfontname will have done a closefile in the above case.
  228.       { dup null eq { pop } { closefile } ifelse pop 
  229.           }
  230.      ifelse
  231.        }
  232.       ifelse
  233.     }
  234.    .scan1fontstring filenameforall
  235.    QUIET
  236.     { pop pop pop }
  237.     { ( ) print =only ( files, ) print =only ( scanned, ) print
  238.       =only ( new fonts.\n) print flush
  239.     }
  240.    ifelse
  241.  } bind def
  242. % Scan all the directories mentioned in FONTPATH (or GS_FONTPATH).
  243. /FONTPATH where
  244.  { pop .scanfontbegin
  245.     % Parsing the list of dictionaries is messy, since we have to
  246.     % handle both the Unix : and the other-system ; as separators.
  247.     % See the earlier comment for the restrictions that make this work.
  248.    FONTPATH
  249.     { dup length 0 eq { pop exit } if
  250.       (;) search
  251.        { exch pop
  252.        }
  253.        { dup 0 1 getinterval (/\\.) exch search
  254.           { pop pop pop (:) search
  255.          { exch pop }
  256.          { () exch }
  257.         ifelse
  258.       }
  259.       { pop () exch
  260.       }
  261.      ifelse
  262.        }
  263.       ifelse .scan1fontdir
  264.     }
  265.    loop
  266.  }
  267. if
  268.  
  269. %END FONTPATH
  270.  
  271. % Define definefont.  This is a procedure built on a set of operators
  272. % that do all the error checking and key insertion.
  273. mark
  274.     /.buildfont0 where { pop 0 /.buildfont0 cvx } if
  275.     /.buildfont1 where { pop 1 /.buildfont1 cvx } if
  276.     /.buildfont3 where { pop 3 /.buildfont3 cvx } if
  277. .dicttomark /.buildfontdict exch def
  278. /.growfontdict
  279.  {    % Grow the font dictionary, if necessary, to ensure room for an
  280.     % added entry, making sure there is at least one slot left for FID.
  281.    dup maxlength 1 index length sub 2 lt
  282.     { dup dup wcheck
  283.        { .growdict }
  284.        { .growdictlength dict copy }
  285.       ifelse
  286.     }
  287.     { dup wcheck not { dup maxlength dict copy } if
  288.     }
  289.    ifelse
  290.  } bind def  
  291. /definefont
  292.  { 1 dict begin count /d exch def    % save stack depth in case of error
  293.     {        % Check for disabled platform fonts.
  294.       NOPLATFONTS
  295.        {    % Make sure we leave room for FID.
  296.      .growfontdict dup /ExactSize 0 put
  297.        }
  298.        {    % Hack: if the Encoding looks like it might be the
  299.         % Symbol or Dingbats encoding, load those now (for the
  300.         % benefit of platform font matching) just in case
  301.         % the font didn't actually reference them.
  302.      dup /Encoding get length 65 ge
  303.       { dup /Encoding get 64 get
  304.         dup /congruent eq { SymbolEncoding pop } if
  305.         /a9 eq { DingbatsEncoding pop } if
  306.       }
  307.      if
  308.        }
  309.       ifelse
  310.       dup /FontType get //.buildfontdict exch get exec
  311.       DISKFONTS
  312.        { FontFileDirectory 2 index known
  313.           { dup /FontFile FontFileDirectory 4 index get .growput
  314.       }
  315.      if
  316.        }
  317.       if
  318.       readonly
  319.     }
  320.    stopped
  321.     { count d sub { pop } repeat end /invalidfont signalerror
  322.     }
  323.     { end        % stack: name fontdict
  324.         % If the current allocation mode is global, also enter
  325.         % the font in LocalFontDirectory.
  326.       .currentglobal
  327.        { systemdict /LocalFontDirectory .knownget
  328.       { 2 index 2 index .growput }
  329.      if
  330.        }
  331.       if
  332.       dup FontDirectory 4 -2 roll .growput
  333.     }
  334.    ifelse
  335.  } odef
  336.  
  337. % Define a procedure for defining aliased fonts.
  338. % We can't just copy the font (or even use the same font unchanged),
  339. % because a significant number of PostScript files assume that
  340. % the FontName of a font is the same as the font resource name or
  341. % the key in [Shared]FontDirectory; on the other hand, some Adobe files
  342. % rely on the FontName of a substituted font *not* being the same as
  343. % the requested resource name.  We address this issue heuristically:
  344. % we substitute the new name iff the font name doesn't have MM in it.
  345. /.aliasfont        % <name> <font> .aliasfont <newFont>
  346.  { .currentglobal 3 1 roll dup .gcheck .setglobal
  347.    dup length 2 add dict
  348.    dup 3 -1 roll { 1 index /FID eq { pop pop } { put dup } ifelse } forall
  349.         % Stack: global fontname newfont newfont.
  350.         % We might be defining a global font whose FontName
  351.         % is a local string.  This is weird, but legal,
  352.         % and doesn't cause problems anywhere else.
  353.         % To avoid any possible problems, do a cvn.
  354.    2 index =string cvs (MM) search
  355.     { pop pop pop pop
  356.     }
  357.     { /FontName exch dup type /stringtype eq { cvn } if put
  358.     }
  359.    ifelse
  360.    systemdict /definefont get exec    % Don't bind, since Level 2
  361.                     % redefines definefont
  362.    exch .setglobal
  363.  } odef        % so findfont will bind it
  364.  
  365. % Define .loadfont for loading a font.  If we recognize Type 1 fonts,
  366. % gs_type1.ps will redefine this.
  367. /.loadfont { cvx exec } bind def
  368.  
  369. % Find an alternate font to substitute for an unknown one.
  370. % We go to some trouble to parse the font name and extract
  371. % properties from it.
  372. /.substitutefaces [
  373.     % Condensed or narrow fonts map to the only narrow family we have.
  374.   [(Condensed) /Helvetica-Narrow]
  375.   [(Narrow) /Helvetica-Narrow]
  376.     % If the family name appears in the font name,
  377.     % use a font from that family.
  378.   [(Avant) /AvantGarde]
  379.   [(Bookman) /Bookman]
  380.   [(Cour) /Courier]
  381.   [(Helv) /Helvetica]
  382.   [(Pala) /Palatino]
  383.   [(Schlbk) /NewCenturySchlbk]
  384.   [(Times) /Times]
  385.     % Guess at suitable substitutions for other fonts.
  386.   [(Grot) /Times]
  387.   [(Roman) /Times]
  388.   [(Book) /NewCenturySchlbk]
  389. ] readonly def
  390. /.substituteproperties [
  391.   [(Italic) 1] [(Oblique) 1]
  392.   [(Bold) 2] [(bold) 2] [(Demi) 2]
  393. ] readonly def
  394. /.substitutefamilies mark
  395.   /AvantGarde
  396.     {/AvantGarde-Book /AvantGarde-BookOblique
  397.      /AvantGarde-Demi /AvantGarde-DemiOblique}
  398.   /Bookman
  399.     {/Bookman-Demi /Bookman-DemiItalic /Bookman-Light /Bookman-LightItalic}
  400.   /Courier
  401.     {/Courier /Courier-Oblique /Courier-Bold /Courier-BoldOblique}
  402.   /Helvetica
  403.     {/Helvetica /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
  404.   /Helvetica-Narrow
  405.     {/Helvetica-Narrow /Helvetica-Narrow-Oblique
  406.      /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique}
  407.   /NewCenturySchlbk
  408.     {/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic
  409.      /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic}
  410.   /Palatino
  411.     {/Palatino-Roman /Palatino-Italic /Palatino-Bold /Palatino-BoldItalic}
  412.   /Times
  413.     {/Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic}
  414. .dicttomark readonly def
  415. /.substitutefont        % <fontname> .substitutefont <altname>
  416.  {    % Look for properties and/or a face name in the font name.
  417.     % If we find any, use Helvetica as the base font;
  418.     % otherwise, use the default font.
  419.     % Note that the "substituted" font name may be the same as
  420.     % the requested one; the caller must check this.
  421.    dup length string cvs
  422.     {defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
  423.    exch 0 exch    % stack: fontname facelist properties fontname
  424.     % Look for a face name.
  425.    .substitutefaces
  426.     { 2 copy 0 get search
  427.        { pop pop pop 1 get .substitutefamilies exch get
  428.      4 -1 roll pop 3 1 roll
  429.        }
  430.        { pop pop
  431.        }
  432.       ifelse
  433.     }
  434.    forall
  435.    .substituteproperties
  436.     { 2 copy 0 get search
  437.        { pop pop pop 1 get 3 -1 roll or exch }
  438.        { pop pop }
  439.       ifelse
  440.     }
  441.    forall pop get exec
  442.     % Only accept fonts known in the Fontmap.
  443.    Fontmap 1 index known not { pop defaultfontname } if
  444.  } bind def
  445. % Substitute for a font, or indicate an error.
  446. /.findsubstfont        % -mark- <alias>* <fontname> .findsubstfont
  447.             %   -mark- <alias>* <fontname> <substname>
  448.  {        % If we're already trying to substitute for this name, give up.
  449.    counttomark 1 sub -1 1
  450.     { index 1 index eq
  451.        { QUIET not
  452.       { (Unable to substitute for font ) print dup cvx =only
  453.         (.\n) print flush
  454.       } if
  455.      /findfont cvx /invalidfont signalerror
  456.        }
  457.       if
  458.     }
  459.    for
  460.    dup .substitutefont
  461.    QUIET not
  462.     { (Substituting font ) print dup cvx =only
  463.       ( for ) print 1 index cvx = flush
  464.     } if
  465.  } bind def
  466.  
  467. % If requested, make (and recognize) fake entries in FontDirectory for fonts
  468. % present in Fontmap but not actually loaded.  Thanks to Ray Johnston for
  469. % the idea behind this code.
  470. FAKEFONTS not { (%END FAKEFONTS) .skipeof } if
  471.  
  472. % We use the presence or absence of the FontMatrix key to indicate whether
  473. % a font is real or fake.
  474.  
  475. /definefont        % <name> <font> definefont <font>
  476.  { dup /FontMatrix known not { /FontName get findfont } if
  477.    //definefont
  478.  } bind odef
  479.  
  480. /scalefont        % <font> <scale> scalefont <font>
  481.  { exch dup /FontMatrix known not { /FontName get findfont } if
  482.    exch //scalefont
  483.  } bind odef
  484.  
  485. /makefont        % <font> <matrix> makefont <font>
  486.  { exch dup /FontMatrix known not { /FontName get findfont } if
  487.    exch //makefont
  488.  } bind def
  489.  
  490. /setfont        % <font> setfont -
  491.  { dup /FontMatrix known not { /FontName get findfont } if
  492.    //setfont
  493.  } bind odef
  494.  
  495. % Now load all the fonts defined in the Fontmap into FontDirectory
  496. % as "fake" fonts i.e., font dicts with only FontName defined.
  497. Fontmap
  498.  { pop
  499.    FontDirectory 1 index known not
  500.     { 1 dict dup /FontName 3 index put        
  501.       FontDirectory 3 1 roll put
  502.     }
  503.    if
  504.  } forall
  505.  
  506. %END FAKEFONTS
  507.  
  508. % Define findfont so it tries to load a font if it's not found.
  509. % The Red Book requires that findfont be a procedure, not an operator.
  510. /findfont
  511.  {    % Since PostScript has no concept of goto, or even blocks with
  512.     % exits, we use a loop as a way to get an exitable scope.
  513.     % The loop is never executed more than once.
  514.    mark exch
  515.     { .findfontloop
  516.     } stopped
  517.     { counttomark 1 sub { pop } repeat exch pop stop
  518.     }
  519.     {    % Define any needed aliases.
  520.       counttomark 1 sub { .aliasfont } repeat
  521.       exch pop
  522.     }
  523.    ifelse
  524.  } bind def
  525. /.findfontloop
  526.  {  {        % Stack: mark <alias>* fontname
  527.  
  528.     dup FontDirectory exch .knownget    % Already loaded?
  529.      { FAKEFONTS { dup /FontMatrix known } { true } ifelse
  530.         { exch pop exit
  531.         }
  532.         {                % In FontDirectory, but fake.
  533.           pop FontDirectory 1 index undef
  534.         }
  535.        ifelse
  536.      }
  537.     if
  538.  
  539.     dup Fontmap exch .knownget not        % Unknown font name.
  540.      { dup defaultfontname eq
  541.         { (Default font ) print dup cvx =only
  542.           ( not found in Fontmap!  Giving up.\n) print flush
  543.           /findfont cvx /invalidfont signalerror
  544.         } if
  545.        .findsubstfont .findfontloop exit
  546.      }
  547.     if
  548.  
  549.     % Check for a font alias.
  550.     dup type /nametype eq
  551.      { .findfontloop exit
  552.      }
  553.     if
  554.  
  555.     % Check for a font with a procedural definition.
  556.     dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and
  557.      {    % The procedure will load the font.
  558.        exec .findfontloop exit
  559.      }
  560.     if
  561.  
  562.     % If we can't open the file, substitute for the font.
  563.     findlibfile
  564.      {    % Stack: fontname fontfilename fontfile
  565.        DISKFONTS
  566.         { .currentglobal true .setglobal
  567.           2 index (r) file
  568.           FontFileDirectory exch 4 index exch .growput
  569.           .setglobal
  570.         }
  571.        if
  572.        QUIET not
  573.         { (Loading ) print 2 index =only
  574.           ( font from ) print 1 index print (... ) print flush
  575.         }
  576.        if
  577.        % Load the font into local or global VM according to FontType.
  578.        /setglobal where
  579.         { pop /FontType .findfontvalue { 1 eq } { false } ifelse
  580.           currentglobal exch setglobal
  581.           1 index (r) file .loadfont FontDirectory exch
  582.           setglobal
  583.         }
  584.         { .loadfont FontDirectory
  585.         }
  586.        ifelse
  587.  
  588.         % Stack: fontname fontfilename fontdirectory
  589.        QUIET not
  590.         { systemdict /level2dict known
  591.            { .currentglobal false .setglobal vmstatus
  592.              true .setglobal vmstatus 3 -1 roll pop
  593.          6 -1 roll .setglobal 5
  594.            }
  595.            { vmstatus 3
  596.            }
  597.           ifelse { =only ( ) print } repeat
  598.           (done.\n) print flush
  599.         } if
  600.  
  601.        % Check to make sure the font was actually loaded.
  602.        dup 3 index known { pop pop .findfontloop exit } if
  603.  
  604.        % Maybe the file had a different FontName.
  605.        % See if we can get a FontName from the file, and if so,
  606.        % whether a font by that name exists now.
  607.        exch (r) file .findfontname
  608.         { 2 copy .knownget
  609.            {    % Yes.  Stack: origfontname fontdirectory filefontname fontdict
  610.          3 -1 roll pop exch
  611.          QUIET
  612.           { pop
  613.           }
  614.           { (Using ) print cvx =only
  615.             ( font for ) print 1 index cvx =only
  616.             (.\n) print flush
  617.           }
  618.          ifelse exit
  619.            }
  620.           if pop
  621.         }
  622.        if pop
  623.  
  624.        % The font definitely did not load correctly.
  625.        QUIET not
  626.         { (Loading ) print dup cvx =only
  627.           ( font failed.\n) print flush
  628.         } if
  629.        .findsubstfont .findfontloop exit
  630.      }
  631.     if
  632.  
  633.     % findlibfile failed, substitute the default font.
  634.     % Stack: fontname fontfilename
  635.     (Can't find \(or can't open\) font file )
  636.     2 index defaultfontname eq
  637.      { print print ( for default font \() print cvx =only
  638.        (\)!  Giving up.\n) print flush
  639.        /findfont cvx /invalidfont signalerror
  640.      }
  641.      { QUIET
  642.         { pop pop
  643.         }
  644.         { print print (.\n) print flush
  645.         }
  646.        ifelse
  647.        .findsubstfont .findfontloop
  648.      }
  649.     ifelse
  650.     exit
  651.  
  652.     } loop        % end of loop
  653.  
  654.  } bind def
  655.  
  656. % Define a procedure to load all known fonts.
  657. % This isn't likely to be very useful.
  658. /loadallfonts
  659.  { Fontmap { pop findfont pop } forall
  660.  } bind def
  661.