home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 October / Chip_2002-10_cd1.bin / zkuste / pdf / download / gs704w32.exe / gs7.04 / lib / pdf_font.ps < prev    next >
Encoding:
Text File  |  2002-01-31  |  30.7 KB  |  958 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of AFPL Ghostscript.
  3. % AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  4. % distributor accepts any responsibility for the consequences of using it, or
  5. % for whether it serves any particular purpose or works at all, unless he or
  6. % she says so in writing.  Refer to the Aladdin Free Public License (the
  7. % "License") for full details.
  8. % Every copy of AFPL Ghostscript must include a copy of the License, normally
  9. % in a plain ASCII text file named PUBLIC.  The License grants you the right
  10. % to copy, modify and redistribute AFPL Ghostscript, but only under certain
  11. % conditions described in the License.  Among other things, the License
  12. % requires that the copyright notice and this notice be preserved on all
  13. % copies.
  14.  
  15. % $Id: pdf_font.ps,v 1.23 2001/10/19 16:42:47 masata-y Exp $
  16. % pdf_font.ps
  17. % PDF font operations.
  18.  
  19. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  20. .currentglobal true .setglobal
  21. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  22. GS_PDF_ProcSet begin
  23. pdfdict begin
  24.  
  25. % We cache the PostScript font in an additional element of the
  26. % font resource dictionary, called PSFont.
  27.  
  28. % ---------------- Encodings ---------------- %
  29.  
  30. % Apply a list of differences to an Encoding.
  31. % Note that the differences may cause the array to grow.
  32. /updateencoding {    % <encoding> <differences> updateencoding <enc'>
  33.     % Calculate the length of the result.
  34.   exch 0 2 index {
  35.     dup type /nametype ne { exch pop } { pop 1 add } ifelse
  36.   } forall
  37.   1 index length .max array dup 0 4 -1 roll putinterval
  38.   exch 0 exch {
  39.         % Stack: enc' code element
  40.     dup type /nametype ne
  41.       { exch pop }
  42.       { 3 copy put pop 1 add }
  43.     ifelse
  44.   } forall pop
  45. } bdef
  46.  
  47. % Get the Encoding for a font.
  48. /getencoding        % <base-encoding> <font-resource> getencoding <enc>
  49.  { /Encoding knownoget
  50.     { dup type /nametype eq
  51.        { 
  52.          % The published PDF specification says the Encoding name
  53.          % "must be" one of the 3 predefined Encodings, implying
  54.          % that an error should occur if it isn't.  However, Acrobat
  55.          % Reader simply ignores unknown names, and since there are
  56.          % some buggy applications that rely on this, we do the same.
  57.  
  58.          dup dup dup /MacRomanEncoding eq
  59.          exch /MacExpertEncoding eq or 
  60.          exch /WinAnsiEncoding eq or
  61.            { exch pop findencoding
  62.            }
  63.            { pop
  64.            }
  65.          ifelse
  66.        }
  67.        { dup /BaseEncoding knownoget
  68.       { findencoding 3 -1 roll pop exch
  69.       }
  70.      if
  71.      /Differences knownoget { updateencoding } if
  72.        }
  73.       ifelse
  74.     }
  75.    if
  76.  } bdef
  77.  
  78. % Rename a font with a generated name.
  79. /renamefont {        % <fontdict> renamefont <font'>
  80.   dup /FontName 2 copy get genfontname dup 5 1 roll put definefont
  81. } bind def
  82.  
  83. % Adjust a font according to the Encoding and Widths in the font resource.
  84. /adjustfont {        % <font-resource> <font> adjustfont <font'>
  85.   getfontencoding
  86.   getfontmetrics 4 -1 roll pop .updatefont { renamefont } if
  87. } bind def
  88.  
  89. % Get the (possibly modified) encoding of a font.
  90. /getfontencoding {    % <font-resource> <font> getfontencoding
  91.             %   <font-resource> <font> <Encoding|null>
  92.   1 index /Encoding known {
  93.     dup /Encoding .knownget { 2 index getencoding } { null } ifelse
  94.   } {
  95.     null
  96.   } ifelse
  97. } bdef
  98.  
  99. /find_in_diff     % <Differences> <index> find_in_diff <bool>
  100. { false exch 0 4 3 roll
  101.   { dup type /nametype ne { exch pop } { pop 1 add } ifelse
  102.     2 copy eq {
  103.       pop pop pop true 0 0 exit
  104.     } if
  105.   } forall
  106.   pop pop
  107. } bdef
  108.  
  109. % Get the metrics of a font, if specified.
  110. /getfontmetrics {    % <font-resource> <font> <Encoding|null> getfontmetrics
  111.             %   <font-resource> <font> <Encoding|null>
  112.             %   <Metrics|null>
  113.   2 index /Widths known {
  114.     dup null eq { pop dup /Encoding get } if
  115.     4 dict begin
  116.       /Encoding exch def
  117.       /Metrics Encoding length dict def
  118.       exch
  119.       dup /Widths oget /Widths exch def
  120.         % Stack: font font-res
  121.         % Note that widths are always based on a 1000-unit
  122.         % character space, but the FontMatrix may specify
  123.         % some other scale factor.  Compensate for this here,
  124.         % by scaling the Widths if necessary.
  125.       0.001 2 index /FontMatrix get 0 get div
  126.         % Stack: font font-res mscale
  127.       1 index /FirstChar oget dup 1 4 index /LastChar oget
  128.        {    % Stack: font font-res mscale first-char index
  129.      Encoding 1 index get
  130.      Widths 2 index 4 index sub oget
  131.          % Stack: font font-res mscale first-char index charname width
  132.      4 index mul
  133.         % The following 'loop' is only context for 'exit'.
  134.      {    
  135.         % Work around a bug in pdfTeX, which can generate Encoding
  136.         % vectors containing nulls :
  137.        1 index null eq { exit } if
  138.         % There is a hack here to deal with encodings where the
  139.         % same character appears more than once, because the Metrics
  140.         % dictionary works by character name, not by character code.
  141.         % We prefer to take (1) non-zero width, and (2) width for 
  142.         % the character code which appears in Differences.
  143.        Metrics 2 index .knownget not { 0 } if 0 ne {
  144.          5 index /Encoding knownoget not { exit } if
  145.          dup type /dicttype ne { pop exit } if
  146.          /Differences knownoget not { exit } if
  147.          3 index //find_in_diff exec not { exit } if
  148.        } if
  149.        2 copy Metrics 3 1 roll put
  150.        exit
  151.      } loop
  152.      pop pop pop
  153.        }
  154.       for pop
  155.         % Now fill in the MissingWidth for any encoded characters
  156.         % that aren't in Metrics already.  Note that built-in
  157.         % fonts may have Widths/FirstChar/LastChar but no
  158.         % FontDescriptor, so we must check for this.
  159.         % Stack: font font-res mscale
  160.       1 index /FontDescriptor knownoget {
  161.     Metrics exch
  162.     /MissingWidth knownoget { 2 index mul } { 0 } ifelse exch
  163.     Encoding {
  164.         % Stack: font font-res mscale missing-width metrics charname
  165.         % Work around the abovementioned pdfTeX bug.
  166.       dup null ne {
  167.         2 copy known not { 2 copy 4 index put } if pop
  168.       } {
  169.         pop
  170.       } ifelse
  171.     } forall pop pop pop
  172.       } {
  173.     pop
  174.       } ifelse
  175.     exch Encoding Metrics end
  176.   } {
  177.     null
  178.   } ifelse
  179. } bdef
  180.  
  181. currentdict /find_in_diff undef
  182.  
  183. % ---------------- Descriptors ---------------- %
  184.  
  185. % Partial descriptors for the 14 built-in fonts.  Note that
  186. % from PDF 1.1 to PDF 1.2, the meaning of the Flag 6 in the FontDescriptor
  187. % object has undergone a subtle change in its meaning which has serious
  188. % consequences for searching with Acrobat:
  189. % In PDF 1.1, the flag meant: Font has StandardEncoding
  190. % In PDF 1.2, the flag means: Font has (subset of) StandardRomanCharacterSet
  191. /standardfontdescriptors mark
  192.   /Courier mark /Flags 16#23 .dicttomark
  193.   /Courier-Oblique 1 index
  194.   /Courier-Bold 1 index
  195.   /Courier-BoldOblique 1 index
  196.   /Helvetica mark /Flags 16#20 .dicttomark
  197.   /Helvetica-Oblique 1 index
  198.   /Helvetica-Bold 1 index
  199.   /Helvetica-BoldOblique 1 index
  200.   /Times-Roman mark /Flags 16#22 .dicttomark
  201.   /Times-Bold 1 index
  202.   /Times-Italic mark /Flags 16#62 .dicttomark
  203.   /Times-BoldItalic 1 index
  204.   /Symbol mark /Flags 16#4 .dicttomark
  205.   /ZapfDingbats 1 index
  206. .dicttomark readonly def
  207.  
  208. % ---------------- Utilities ---------------- %
  209.  
  210. % Fabricate a font name by adding ?'s on the end.
  211. /genfontname        % <name> genfontname <name>
  212.  { dup length string cvs
  213.     { (?) concatstrings
  214.       dup cvn FontDirectory exch known not { cvn exit } if
  215.     }
  216.    loop
  217.  } bdef
  218.  
  219. % Find a font, and adjust its encoding if necessary.
  220. /.pdfdfndict mark
  221.   /defaultfontname /Helvetica
  222. .dicttomark readonly def
  223. /pdffindfont {        % <font-resource> <fontname> pdffindfont <font>
  224.         % If the font isn't available, synthesize one based on
  225.         % its descriptor.
  226.   dup /Font resourcestatus {
  227.     pop pop findfont
  228.   } {
  229.     1 index /FontDescriptor knownoget {
  230.         % Stack: font-res fontname fontdesc
  231.       dup /Flags oget
  232.       dup 16#40 and -6 bitshift        % 1, oblique/italic
  233.       1 index 16#40000 and -17 bitshift add    % 2, bold
  234.       exch 16#2 and 2 bitshift add    % 8, serif
  235.         % We should look at the fixed flag, too.
  236.         % Stack: font-res fontname fontdesc properties
  237.       1 index /FontName oget exch
  238.         % Analyzes font name and extract "Narrow" property
  239.         % which is not described by the FontDescriptor Flags.
  240.       0 2 index .fontnameproperties 4 and or
  241.         % Rebind the default font name to Helvetica so that
  242.         % fonts with no properties are handled correctly.
  243.       //.pdfdfndict begin .substitutefontname end
  244.         % Stack: font-res fontname fontdesc substname|null
  245.       Fontmap 1 index known not {
  246.         % No available good substitution, use the standard one.
  247.     pop 1 index .substitutefont
  248.       } if
  249.       QUIET not {
  250.     (Substituting font ) print dup =only
  251.     ( for ) print 2 index =only (.) = flush
  252.       } if
  253.       3 -1 roll pop findfont
  254.         % Stack: font-res fontdesc font
  255.         % If this is a small-caps font, replace the CharString
  256.         % entries for a..z.
  257.       exch /Flags oget 16#20000 and 0 ne {
  258.     true .copyfontdict
  259.     dup /CharStrings 2 copy get dup length dict .copydict
  260.     4 index /FirstChar get 97 .max
  261.     5 index /LastChar get 122 .min 1 exch {
  262.         % Stack: font-res font' font' /CharStrings charstrings code
  263.         % Note that this only remaps a-z, not accented characters.
  264.       5 index /Widths oget 1 index 7 index /FirstChar get sub oget
  265.       1 string dup 0 5 -1 roll put
  266.         % Stack: font-res font' font' /CharStrings charstrings code
  267.         %   width (x)
  268.       2 index exch dup cvn exch
  269.       dup 0 2 copy get 32 sub put 4 -1 roll {
  270.             % Stack: operand (X) width
  271.         0 setcharwidth exch pop
  272.         currentfont /FontMatrix get matrix invertmatrix concat
  273.         0.7 dup scale 0 0 moveto show
  274.       } /exec cvx 4 packedarray cvx put
  275.     } for put
  276.     renamefont
  277.       } if
  278.     } {
  279.         % No descriptor available, use the default algorithm.
  280.       findfont
  281.     } ifelse
  282.   } ifelse adjustfont
  283. } bdef
  284.  
  285. % ---------------- Type 1 fonts ---------------- %
  286.  
  287. /buildType1        % <Type1-font-resource> buildType1 <font>
  288.  { dup /BaseFont get pdffindfont
  289.  } bdef
  290.  
  291. % The state dictionary for the embedded Type 1 font reading procedure
  292. % has the following keys and values:
  293. %    data - stream (filter)
  294. %    buffer, buffer2 - string
  295. %    hexify - procedure to convert buffer to hex if needed
  296. %    leftstr - string containing (non-negative) integer
  297. %    sectionstr - string containing a character 0 .. 3
  298. %    stream - (stream) dictionary
  299. %    proc - procedure of the form {-dict- type1read}
  300. %       pfbhdr - string containing 16#80 if PFB, 0 otherwise
  301. % When the procedure is executing, this dictionary is current.
  302. % leftstr and sectionstr are strings so that we can change their values
  303. % reliably in case the font executes a restore!
  304. % We also have to do something special about embedded fonts that
  305. % execute definefont more than once -- that is the function of topFontDict.
  306.  
  307. % Read an embedded Type 1 font.
  308. /readfontfilter {    % <proc> readfontfilter <filter>
  309.   0 () /SubFileDecode filter
  310. } bdef
  311. /readtype1dict 5 dict dup begin
  312.   /definefont {
  313.     dup topFontDict eq topFontDict null eq or {
  314.       dup wcheck not { dup length dict copy } if
  315.       exch pop savedFontName exch
  316.     } if
  317.     //systemdict /definefont get exec
  318.   } bdef
  319.   /eexec {
  320.     % Assume the font dictionary is directly below the file on the stack
  321.     count 0 gt { /topFontDict 2 index cvlit store } if
  322.     55665 /eexecDecode filter
  323.     //systemdict begin readtype1dictcopy begin cvx stopped
  324.     currentdict readtype1dictcopy eq { end } if
  325.     currentdict //systemdict eq { end } if
  326.      { stop } if
  327.   } bdef
  328. end readonly def
  329. /readtype1 {        % <font-resource> <stream-dict> readtype1 <font>
  330.         % Read the definition, using a procedure-based filter
  331.         % that turns binary/hex conversion on and off
  332.         % at the right times.
  333.    1 index exch
  334.    PDFfile fileposition 3 1 roll
  335.    11 dict begin
  336.      /leftstr (          ) 10 string copy def
  337.        dup /Length1 oget leftstr cvs pop
  338.      /sectionstr <00> 1 string copy def
  339.      /pfbhdr <00> 1 string copy def
  340.      /stream 1 index def
  341.      true resolvestream /data exch def
  342.      /buffer 1000 string def        % arbitrary
  343.      /buffer2 buffer length 2.1 div cvi 1 sub string def
  344.      /hexify /buf2hex load def
  345.    currentdict end
  346.    /type1read cvx 2 array astore cvx dup 0 get /proc 2 index put
  347.    readfontfilter
  348.         % Some buggy embedded fonts leave extra junk on the stack,
  349.         % so we have to make a closure that records the stack depth
  350.         % in a fail-safe way.
  351.    //systemdict begin
  352.         % The PDF specification is somewhat muddy about whether
  353.         % an embedded font's name is supposed to be the BaseFont
  354.         % from the Font object or the FontName from the descriptor.
  355.         % Acrobat Distiller requires the former.  Save away the
  356.         % name so we can substitute it at definefont time.
  357.    //readtype1dict dup length 3 add dict copy begin
  358.    1 index /BaseFont oget /savedFontName exch def
  359.    /topFontDict null def
  360.    /readtype1dictcopy currentdict def
  361.     { run } aload pop count 1 sub 2 packedarray cvx exec
  362.    end end
  363.    count exch sub { pop } repeat
  364.    PDFfile 3 -1 roll setfileposition
  365.    /BaseFont oget findfont
  366.    adjustfont
  367.  } bdef
  368.  
  369. % Execute the appropriate reading procedure.
  370. /type1read        % <dict> type1read <string>
  371.  { begin leftstr cvi
  372.     { type1read0 type1read1 type1read2 type1read3 } sectionstr 0 get get exec
  373.    (          ) leftstr copy cvs pop end
  374.  } bdef
  375.  
  376. % Read the next block of data into the buffer.
  377. /type1readdata        % <left> <buffer> type1readdata <substring> <left'>
  378.  { 0 2 index 2 index length min getinterval
  379.         % Adobe requires readstring to signal an error if given
  380.         % an empty string.  Work around this nonsense here.
  381.    dup length 0 ne { data exch readstring pop } if
  382.    dup length 3 -1 roll exch sub
  383.    DEBUG
  384.     { dup =only ( read ) print
  385.       1 index length =only (: ) print
  386.       1 index == flush
  387.     } if
  388.  } bdef
  389.  
  390. % Read the initial byte to see if we need to skip a 6 byte PFB header
  391. /type1read0 {         % <left> type1read0 <string> <left'>
  392.   sectionstr 0 1 put    % either way we go to the next stage
  393.   pfbhdr type1readdata
  394.   1 index 0 get 16#80 eq {
  395.     (\n   **** Warning: Embedded Type1 font in PFB format is not valid PDF.)
  396.     pdfformaterror
  397.     DEBUG { (skipping PFB header) = flush } if
  398.     exch pop buffer 0 5 getinterval type1readdata exch
  399.     dup 4 get 256 mul 1 index 3 get add 256 mul
  400.     1 index 2 get add 256 mul 1 index 1 get add
  401.     DEBUG { (PFB segment length = ) print dup = } if
  402.     exch pop  % discard the string keeping the PFB segment length
  403.     2 copy ne {
  404.       (\n   **** Warning: Type 1 PFB segment length and Length 1 value do not match.)
  405.       pdfformaterror
  406.       exch     % keep the PFB length instead
  407.     } if
  408.     pop
  409.     buffer type1readdata    % go ahead and read a block
  410.   }
  411.   if    % if not PFB, return pfbhdr string (first char of file, usually %).
  412. } bdef
  413.  
  414. % Read the next block of the initial text portion.
  415. /type1read1 {        % <left> type1read1 <string> <left'>
  416.   DEBUG { (read1 ) print } if
  417.   dup 0 eq {
  418.     pop sectionstr 0 2 put
  419.     stream /Length2 oget
  420.             % Determine whether to hexify data for eexec.
  421.     dup 8 lt {
  422.       type1read2    % Hexify.
  423.     } {
  424.       DEBUG { (read2 ) print } if
  425.       pfbhdr 0 get 16#80 eq {
  426.         % eat 6 more bytes of PFB junk before proceeding
  427.     DEBUG { (skipping PFB header in segment 2) = flush } if
  428.     buffer 0 6 getinterval type1readdata exch
  429.         dup 5 get 256 mul 1 index 4 get add 256 mul
  430.     1 index 3 get add 256 mul 1 index 2 get add
  431.         DEBUG { (PFB segment length = ) print dup = } if
  432.     exch pop  % discard the string keeping the PFB segment length
  433.     2 copy ne {
  434.           (\n   **** Warning: Type 1 PFB segment length and Length 2 value do not match.)
  435.           pdfformaterror
  436.       dup =
  437.       exch         % keep the PFB length instead
  438.     } if
  439.       pop
  440.       } if
  441.       buffer2 type1readdata exch
  442.             % The check doesn't have to be 100% accurate:
  443.             % hexifying is always OK.
  444.       dup 0 8 getinterval 0 exch { or } forall
  445.       128 ge {
  446.     /hexify { } store
  447.     /buffer2 buffer def    % We don't need an intermediate buffer.
  448.       } if hexify exch
  449.     } ifelse
  450.   } {
  451.     buffer type1readdata
  452.   } ifelse
  453. } bdef
  454.  
  455. % Convert a string from binary to hex for eexec.
  456. % Free variables: buffer.
  457. /buf2hex {        % <string> buf2hex <hexstring>
  458.   buffer /ASCIIHexEncode filter dup 3 -1 roll writestring closefile
  459.   buffer (>) search pop exch pop exch pop
  460. } bdef
  461.  
  462. % Read the next block of the encrypted portion.
  463. /type1trailer
  464. (0000000000000000000000000000000000000000000000000000000000000000\n\
  465. 0000000000000000000000000000000000000000000000000000000000000000\n\
  466. 0000000000000000000000000000000000000000000000000000000000000000\n\
  467. 0000000000000000000000000000000000000000000000000000000000000000\n\
  468. 0000000000000000000000000000000000000000000000000000000000000000\n\
  469. 0000000000000000000000000000000000000000000000000000000000000000\n\
  470. 0000000000000000000000000000000000000000000000000000000000000000\n\
  471. 0000000000000000000000000000000000000000000000000000000000000000\n\
  472. cleartomark\n)
  473. readonly def
  474. /type1read2 {        % <left> type1read2 <string> <left'>
  475.   DEBUG { (read2 ) print } if
  476.    dup 0 eq
  477.     { pop sectionstr 0 3 put
  478.       stream /Length3 oget
  479.       dup 0 eq
  480.        { DEBUG { (trailer ) print } if
  481.      type1trailer exch
  482.        }
  483.        { 
  484.          pfbhdr 0 get 16#80 eq {
  485.            % eat 6 more bytes of PFB junk before proceeding
  486.        DEBUG { (skipping PFB header in segment 3) = flush } if
  487.        buffer 0 6 getinterval type1readdata exch
  488.            dup 5 get 256 mul 1 index 4 get add 256 mul
  489.        1 index 3 get add 256 mul 1 index 2 get add
  490.            DEBUG { (PFB segment length = ) print dup = } if
  491.        exch pop  % discard the string keeping the PFB segment length
  492.        2 copy ne {
  493.            (\n   **** Warning: Type 1 PFB segment length and Length 3 value do not match.)
  494.            pdfformaterror
  495.          exch     % keep the PFB length instead
  496.        } if
  497.        pop
  498.        (\n) pdfformaterror
  499.          } if
  500.          type1read3
  501.        }
  502.       ifelse
  503.     }
  504.     { buffer2 type1readdata exch hexify exch
  505.     }
  506.    ifelse
  507. } bdef
  508.  
  509. % Read the next block of the final text portion.
  510. % When finished, this procedure returns an empty string.
  511. /type1read3        % <left> type1read3 <string> <left'>
  512.  { DEBUG { (read3 ) print } if
  513.    buffer type1readdata
  514.  } bdef
  515.  
  516. % ---------------- Type 3 fonts ---------------- %
  517.  
  518. /.notdefEncoding 256 { /.notdef } repeat 256 packedarray def
  519.  
  520. /buildType3 {        % <Type3-font-resource> buildType3 <font>
  521.   8 dict begin
  522.     /FontType 3 def
  523.     /Resources 1 index /Resources knownoget { oforce } { 0 dict } ifelse def
  524.     /FontBBox 1 index /FontBBox get cvx def
  525.     /FontMatrix 1 index /FontMatrix oget def
  526.     /CharProcs 1 index /CharProcs oget def
  527.     1 index /Widths knownoget {
  528.       /Widths exch def
  529.       /FirstChar 1 index /FirstChar oget def
  530.       /LastChar 1 index /LastChar oget def
  531.     } if
  532.     /FontName 1 index /Name get genfontname def
  533.     /Encoding .notdefEncoding 2 index getencoding def
  534.         % We have to define BuildChar rather than BuildGlyph:
  535.         % there is no PDF equivalent of glyphshow, and we need
  536.         % the character code to access the Widths.
  537.     /BuildChar {
  538.         % Stack: font charcode
  539.       1 index begin 3 dict begin
  540.       /Font 3 -1 roll def /CharCode 1 index def
  541.       % Make unknown characters map to /.notdef
  542.       Encoding exch get dup CharProcs exch known
  543.         { CharProcs exch oget }
  544.     { pop CharProcs /.notdef oget }
  545.       ifelse
  546.       PDFfile fileposition exch
  547.       false resolvestream
  548.         % Stack: filepos stream
  549.         % Don't let setgcolor set the color inside the BuildGlyph
  550.         % procedure, because this causes an /undefined error.
  551.       q null /FillColor gput null /StrokeColor gput
  552.       Font /Resources get exch pdfopdict .pdfruncontext
  553.       Q
  554.       PDFfile exch setfileposition
  555.       end end
  556.     } bdef
  557.     FontName currentdict end definefont exch pop
  558. } bdef
  559. /.adjustcharwidth {    % <wx> <wy> .adjustcharwidth <wx'> <wy'>
  560.   /Widths where {
  561.     begin
  562.     CharCode FirstChar ge CharCode LastChar le and {
  563.       exch pop Widths CharCode FirstChar sub get exch
  564.     } if end
  565.   } if
  566. } bdef
  567.  
  568. % ---------------- TrueType fonts ---------------- %
  569.  
  570. /TTfonts mark
  571.   /Arial /Helvetica
  572.   /Arial,Italic /Helvetica-Oblique
  573.   /Arial,Bold /Helvetica-Bold
  574.   /Arial,BoldItalic /Helvetica-BoldOblique
  575.   /CourierNew /Courier
  576.   /CourierNew,Bold /Courier-Bold
  577.   /TimesNewRoman /Times-Roman
  578.   /TimesNewRoman,Italic /Times-Italic
  579.   /TimesNewRoman,Bold /Times-Bold
  580.   /TimesNewRoman,BoldItalic /Times-BoldItalic
  581. .dicttomark readonly def
  582.  
  583. /buildTrueType {    % <TrueType-font-resource> buildTrueType <font>
  584.   dup /BaseFont get
  585.   dup TTfonts exch .knownget {
  586.     exch pop
  587.         % Hack required by the PDF specification: if the
  588.         % font resource has Subtype = /TrueType but the actual
  589.         % (installed) font is not a TrueType font, ignore the
  590.         % Encoding in the font resource.  However, all current
  591.         % versions of Acrobat Reader have the 14 base TrueType
  592.         % fonts built in, so this produces incorrect output for
  593.         % badly designed PDF files that specify these file names
  594.         % with /Subtype = /TrueType but no embedded definition.
  595.         % Compensate for this by removing the /Subtype key when
  596.         % looking up the font.
  597.     exch dup length dict copy dup /Subtype null put exch
  598.   } if pdffindfont
  599. } bdef
  600.  
  601. % Read an embedded TrueType font.
  602. /readtruetype {        % <font-resource> <stream-dict> readtruetype <font>
  603.         % This is much simpler than readtype1, because we don't
  604.         % have to deal with the tripartite .PFB format.
  605.   1 index exch
  606.   PDFfile fileposition 3 1 roll
  607.   true resolvestream readfontfilter
  608.         % Stack: filepos fontres stream
  609.   1 index /Subtype get /CIDFontType2 eq {
  610.     .loadttcidfont
  611.         % Stack: filepos fontres cidfont
  612.     1 index /CIDToGIDMap knownoget {
  613.       dup /Identity eq {
  614.     pop
  615.       } {
  616.     true resolvestream
  617.         % The following doesn't work for CIDToGIDMaps with more
  618.         % than 32K-1 entries.  We'll fix it later if necessary.
  619.         % Stack: filepos fontres font mapstream
  620.     dup 2 index /CIDCount oget 2 mul string readstring pop exch closefile
  621.     exch dup length 5 add dict .copydict
  622.     dup /FID undef
  623.     dup /CIDMap 4 -1 roll put
  624.     dup /CIDFontName get exch /CIDFont defineresource
  625.       } ifelse
  626.     } if
  627.   } {
  628.     null 2 index getencoding .loadpdfttfont
  629.   } ifelse
  630.   exch pop
  631.   PDFfile 3 -1 roll setfileposition
  632.         % Ignore both the Encoding and the Widths.
  633.   exch pop
  634. } bdef
  635.  
  636. % ---------------- Type 0 fonts ---------------- %
  637.  
  638. % Predefine the known CMaps, but only create them on demand.
  639. /knownCMaps mark
  640.   /Identity-H { /Identity-H 0 makeIdentityCMap }
  641.   /Identity-V { /Identity-V 1 makeIdentityCMap }
  642. .dicttomark def
  643.  
  644. /makeIdentityCMap {        % <cmapname> <wmode> .makeIdentityCMap -
  645.   .currentglobal true .setglobal 3 1 roll
  646.   /CIDInit /ProcSet findresource begin
  647.   12 dict begin
  648.     begincmap
  649.     /WMode exch def
  650.     /CMapName exch def
  651.     /CIDSystemInfo 3 dict dup begin
  652.       /Registry (Adobe) def
  653.       /Ordering (Identity) def
  654.       /Supplement 0 def
  655.     end def
  656.     %/CMapName (see above)
  657.     /CMapVersion 1 def
  658.     /CMapType 1 def
  659.     %WMode (see above)
  660.     % The PDF documentation says that these CMaps map CIDs
  661.     % "1 to 65,536".  This is a misprint for 0 to 65,535.
  662.     1 begincodespacerange
  663.     % <0001> <00ff>  <0100> <ffff>
  664.       <0000> <ffff>
  665.     endcodespacerange
  666.     1 begincidrange
  667.     % <0001> <00ff> 1   <0100> <ffff> 256
  668.       <0000> <ffff> 0
  669.     endcidrange
  670.     endcmap
  671.     CMapName currentdict /CMap defineresource
  672.     knownCMaps CMapName 2 index put
  673.   end        % CMap
  674.   end        % CIDInit ProcSet
  675.   exch .setglobal
  676. } bdef
  677.  
  678. /buildType0 {        % <Type0-font-resource> buildType0 <font>
  679.   dup /BaseFont get    % FontName
  680.   1 index /Encoding oget
  681.   dup type /nametype eq {
  682.     dup /CMap resourcestatus {
  683.     pop pop /CMap findresource
  684.     } {
  685.     knownCMaps 1 index .knownget
  686.       { exch pop exec } { /undefined signalerror } ifelse
  687.     } ifelse
  688.   } {
  689.     PDFfile fileposition exch
  690.     dup /CMapName get exch true resolvestream cvx exec
  691.     /CMap findresource
  692.     exch PDFfile exch setfileposition
  693.   } ifelse        % CMap
  694.   [
  695.     3 index /DescendantFonts oget { exec resourcefont } forall
  696.   ]            % subfonts
  697.   composefont
  698.         % Stack: fontres font
  699.   1 index /FontMatrix knownoget {
  700.     dup aload pop true {0 0 1 0 0 1} {3 -1 roll eq and} forall {
  701.       1 index exch makefont exch /FontName get exch definefont
  702.     } {
  703.       pop
  704.     } ifelse
  705.   } if exch pop
  706. } bdef
  707.  
  708. % ---------------- CIDFontType0/2 fonts ---------------- %
  709.  
  710. % Insert metrics into a CIDFont, by saving the PDF W, W2, DW, and DW2
  711. % arrays and using a (currently very inefficient) CDevProc.
  712. /addCIDmetrics {    % <CIDFont-resource> <CIDFont> addCIDmetrics <fontdict>
  713.   dup length 5 add dict .copydict
  714.   dup /FID undef
  715.   dup /UniqueID undef
  716.   dup /XUID undef
  717.     % Insert the widths into the font.
  718.   {W W2 DW DW2} {
  719.     % Stack: pdfresource newfont key
  720.     2 index 1 index .knownget {
  721.       2 index 3 1 roll put
  722.     } {
  723.       pop
  724.     } ifelse
  725.   } forall
  726.   dup /CDevProc 1 index /CIDWProc load /exec load 3 packedarray cvx put
  727.   exch pop
  728. } bdef
  729.  
  730. % Apply the [D]W[2] metrics to a character before displaying.
  731. /CIDWProc {        % <w0x> <w0y> <llx> <lly> <urx> <ury>
  732.             %   <w1x> <w1y> <vx> <vy> <cid> <font> CIDWproc
  733.             %   <w0x'> ... <vy'>
  734.   begin
  735.     % Look up and apply [D]W
  736.   10 index
  737.   currentdict /DW .knownget { 1000 div exch pop } if
  738.   currentdict /W .knownget {
  739.     % Search the W array for the CID.
  740.     % ****** NOT IMPLEMENTED YET ******
  741.     pop
  742.   } if
  743.   0 13 2 roll 11 -2 roll pop pop
  744.     % Look up and apply [D]W2
  745.     % ****** NOT IMPLEMENTED YET ******
  746.   pop end
  747. } bdef
  748. % <string> <match> tailmatch ==> <pre> true
  749. %                            ==> <string> false
  750. /tailmatch {
  751.   2 copy length 1 index length min
  752.   dup 2 index length exch sub exch getinterval
  753.   1 index eq {
  754.     length 1 index length exch sub
  755.     0 exch getinterval true
  756.   } {
  757.     pop false
  758.   } ifelse
  759. } bind def
  760.  
  761. /makeboldfont {
  762.   16 dict begin
  763.     /strokewidth exch def
  764.     /basecidfont exch def
  765.     /FontMatrix [ 1 0 0 1 0 0 ] def
  766.  
  767.     /CIDFontName /.boldfont def
  768.     /CIDFontType 1 def
  769.  
  770.     /basefont-H /.basefont-H /Identity-H [ basecidfont ] composefont def
  771.     /basefont-V /.basefont-V /Identity-V [ basecidfont ] composefont def
  772.  
  773.     /CIDSystemInfo dup basecidfont exch get def
  774.     /FontBBox [ basecidfont /FontBBox get cvx exec
  775.       4 2 roll basecidfont /FontMatrix get transform
  776.       4 2 roll basecidfont /FontMatrix get transform
  777.     ] def
  778.  
  779.     /tmpstr 2 string def
  780.     /BuildGlyph {
  781.       gsave
  782.       exch begin
  783.         dup 256 idiv tmpstr exch 0 exch put
  784.         256 mod tmpstr exch 1 exch put
  785.         rootfont /WMode known { rootfont /WMode get 1 eq } { false } ifelse
  786.         { basefont-V } { basefont-H } ifelse setfont
  787.         strokewidth setlinewidth
  788.         1 setlinejoin
  789.         newpath
  790.         0 0 moveto tmpstr false charpath stroke
  791.         0 0 moveto tmpstr show
  792.         currentpoint setcharwidth
  793.       end
  794.       grestore
  795.     } bind def
  796.  
  797.    currentdict
  798.   end
  799.   dup /CIDFontName get exch /CIDFont defineresource
  800. } bind def
  801.  
  802. % <CIDFont-resource> <CIDFontName> findCIDFont <CIDFont-resource> <font>
  803. %   CIDFont-resource is not modified.
  804. /findCIDFont {
  805.   {
  806.     dup /CIDFont resourcestatus {
  807.       pop pop /CIDFont findresource
  808.       exit
  809.     } if
  810.  
  811.     dup dup length string cvs
  812.     (,Bold) tailmatch {
  813.       exch pop
  814.       cvn findCIDFont 0.03 makeboldfont
  815.       exit
  816.     } if
  817.     (,Italic) tailmatch {
  818.       exch pop
  819.       cvn findCIDFont
  820.       [ 1 0 0.3 1 0 0 ] makefont
  821.       exit
  822.     } if
  823.     (,BoldItalic) tailmatch {
  824.       exch pop
  825.       cvn findCIDFont 0.03 makeboldfont
  826.       [ 1 0 0.3 1 0 0 ] makefont
  827.       exit
  828.     } if
  829.     pop
  830.  
  831.     1 index /CIDSystemInfo get begin Registry (-) Ordering end
  832.     concatstrings concatstrings
  833.     cvn
  834.     QUIET not {
  835.       (Substituting ) print dup ==only
  836.       ( for ) print 1 index ==only (.\n) print
  837.     } if
  838.     exch pop
  839.     /CIDFont findresource
  840.     exit
  841.   } loop
  842. } bdef
  843.  
  844. /buildCIDType0 {    % <CIDFontType0-font-resource> buildCIDType0 <font>
  845.   dup /BaseFont get exch 1 index findCIDFont
  846.   addCIDmetrics /CIDFont defineresource
  847. } bdef
  848.  
  849. /buildCIDType2 {    % <CIDFontType2-font-resource> buildCIDType2 <font>
  850.   dup /BaseFont get exch 1 index findCIDFont
  851.   addCIDmetrics /CIDFont defineresource
  852. } bdef
  853.  
  854. % ---------------- Other embedded fonts ---------------- %
  855.  
  856. /fontloadprocs mark
  857.   /Type1C /readType1C cvx
  858.   /CIDFontType0C /readCIDFontType0C cvx
  859. .dicttomark readonly def
  860.  
  861. % Read an embedded compressed font.
  862. /readType1C {        % <font-resource> <stream-dict> readType1C <font>
  863.   1 index exch
  864.   PDFfile fileposition 3 1 roll
  865.   dup true resolvestream dup readfontfilter
  866.         % Stack: pos resource streamdict stream filter
  867.   3 index /FontDescriptor oget /FontName oget
  868.   1 index FRD
  869.   closefile closefile pop
  870.   PDFfile 3 -1 roll setfileposition
  871.   /FontDescriptor oget /FontName oget findfont
  872.   adjustfont
  873. } bdef
  874.  
  875. % Read an embedded CFF CIDFont.
  876. /readCIDFontType0C {  % <font-resource> <stream-dict> readCIDFontType0C <font>
  877.   PDFfile fileposition 3 1 roll
  878.   dup true resolvestream dup readfontfilter
  879.         % Stack: pos resource streamdict stream filter
  880.   3 index /FontDescriptor oget /FontName oget
  881.   1 index FRD
  882.   closefile closefile pop
  883.   PDFfile 3 -1 roll setfileposition
  884.         % Some broken Adobe software produces PDF files in which
  885.         % the FontName of the CFF font and the FontName in the
  886.         % FontDescriptor don't match the BaseFont in the font.
  887.         % Use the FontName, rather than the BaseFont, here.
  888.   dup /FontDescriptor oget /FontName oget /CIDFont findresource
  889.   addCIDmetrics dup /CIDFontName get exch /CIDFont defineresource
  890. } bdef
  891.  
  892. % ---------------- Font lookup ---------------- %
  893.  
  894. /fonttypeprocs mark        % <font-resource> -proc- <font>
  895.   /Type0 /buildType0 cvx
  896.   /Type1 /buildType1 cvx
  897.   /MMType1 1 index
  898.   /Type3 /buildType3 cvx
  899.   /TrueType /buildTrueType cvx
  900.   /CIDFontType0 /buildCIDType0 cvx
  901.   /CIDFontType2 /buildCIDType2 cvx
  902. .dicttomark readonly def
  903.  
  904. /resourcefont            % <font-resource> resourcefont <font>
  905.  { dup /PSFont .knownget
  906.     { /FID .knownget { type /fonttype eq } { false } ifelse }
  907.     { false }
  908.    ifelse
  909.     { /PSFont get
  910.     }
  911.     { dup dup /FontDescriptor knownoget
  912.        {    % Stack: font-res font-res font-desc
  913.      dup /FontFile knownoget
  914.       { exch pop readtype1 true }
  915.       { dup /FontFile2 knownoget
  916.          { exch pop readtruetype true }
  917.          { /FontFile3 knownoget
  918.         { dup /Subtype get fontloadprocs exch get exec true }
  919.         { false }
  920.            ifelse
  921.          }
  922.         ifelse
  923.       }
  924.      ifelse
  925.        }
  926.        { false }
  927.       ifelse
  928.         % Stack: font-res font-res false
  929.         %  -or-: font-res font true
  930.       not
  931.        { dup /Subtype get fonttypeprocs exch get exec }
  932.       if
  933.       2 copy /PSFont exch put
  934.       exch pop
  935.     }
  936.    ifelse
  937.  } bdef
  938.  
  939. drawopdict begin
  940.   /d0 {
  941.     .adjustcharwidth setcharwidth
  942.   } bdef
  943.   /d1 {
  944.     6 -2 roll .adjustcharwidth 6 2 roll setcachedevice
  945.   } bdef
  946.   /Tf {
  947.     1 index Page /Font rget not { 1 index /invalidfont signalerror } if
  948.     resourcefont exch Tf pop
  949.   } bdef
  950. end
  951.  
  952. end            % pdfdict
  953. end            % GS_PDF_ProcSet
  954. .setglobal
  955.