shithub: riscv

ref: 985b2457cda207c2c65edeb647aedbb6e92dac46
dir: /sys/src/cmd/gs/lib/wrfont.ps/

View raw version
%    Copyright (C) 1991, 1995, 1996, 2002 Aladdin Enterprises.  All rights reserved.
% 
% This software is provided AS-IS with no warranty, either express or
% implied.
% 
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
% 
% For more information about licensing, please refer to
% http://www.ghostscript.com/licensing/. For information on
% commercial licensing, go to http://www.artifex.com/licensing/ or
% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
% San Rafael, CA  94903, U.S.A., +1(415)492-9861.

% $Id: wrfont.ps,v 1.5 2002/04/19 06:52:25 lpd Exp $
% wrfont.ps
% Write out a Type 1 font in readable, reloadable form.
% Note that this does NOT work on protected fonts, such as Adobe fonts
% (unless you have loaded unprot.ps first, in which case you may be
% violating the Adobe license).

% ****** NOTE: This file must be kept consistent with gs_pfile.ps.

/wrfont_dict 100 dict def
wrfont_dict begin

% ------ Options ------ %

% Define whether to use eexec encryption for the font.
% eexec encryption is only useful for compatibility with Adobe Type Manager
% and other programs; it only slows Ghostscript down.
   /eexec_encrypt false def

% Define whether to write out the CharStrings in binary or in hex.
% Binary takes less space on the file, but isn't guaranteed portable.
   /binary_CharStrings false def

% Define whether to use binary token encodings when possible.
% Binary tokens are smaller and load faster, but are a Level 2 feature.
   /binary_tokens false def

% Define whether to encrypt the CharStrings on the file.  (CharStrings
% are always encrypted in memory.)  Unencrypted CharStrings load about
% 20% slower, but make the files compress much better for transport.
   /encrypt_CharStrings true def

% Define whether the font must provide standard PostScript language
% equivalents for any facilities it uses that are provided in Ghostscript
% but are not part of the standard PostScript language.
   /standard_only true def

% Define the value of lenIV to use in writing out the font.
% use_lenIV = 0 produces the smallest output, but this may not be
% compatible with old Adobe interpreters.  use_lenIV = -1 means
% use the value of lenIV from the font.
   /use_lenIV -1 def

% Define whether to produce the smallest possible output, relying
% as much as possible on Ghostscript-specific support code.
% Taking full advantage of this requires the following settings:
% binary_CharStrings = true, binary_tokens = true, standard_only = false.
   /smallest_output false def

% Define whether to write out all currently known Encodings by name,
% or only StandardEncoding and ISOLatin1Encoding.
   /name_all_Encodings false def

% ---------------- Runtime support ---------------- %

/.packedfilefilter where
 { pop }
 { (gs_pfile.ps) runlibfile }
ifelse

% ------ Output utilities ------ %

% By convention, the output file is named psfile.

% Define some utilities for writing the output file.
   /wtstring 2000 string def
   /wb {psfile exch write} bind def
   /wnb {/wb load repeat} bind def
   /w1 {psfile exch write} bind def
   /ws {psfile exch writestring} bind def
   /wl {ws (\n) ws} bind def
   /wt {wtstring cvs ws ( ) ws} bind def
   /wd		% Write a dictionary.
    { dup length wo {dict dup begin} wol { we } forall
      {end} wol
    } bind def
   /wld		% Write a large dictionary more efficiently.
   		% Ignore the readonly attributes.
    { dup length wo {dict dup begin} wol
      0 exch
       { exch wo wo () wl
	 1 add dup 200 eq
	  { wo ({def} repeat) wl 0 }
	 if
       }
      forall
      dup 0 ne
       { wo ({def} repeat) wl }
       { pop }
      ifelse
      (end) ws
    } bind def
   /we		% Write a dictionary entry.
    { exch wo wo /def cvx wo (\n) ws
    } bind def
   /wcs		% Write a CharString (or Subrs entry)
    { dup type /stringtype eq
       { 4330 exch changelenIV 0 ge
          {	% Add some leading garbage bytes.
	    wtstring changelenIV 2 index length getinterval
	    .type1decrypt exch pop
	    wtstring exch 0 exch length changelenIV add getinterval
	  }
	  {	% Drop some leading garbage bytes.
	    wtstring .type1decrypt exch pop
	    changelenIV neg 1 index length 1 index sub getinterval
	  }
	 ifelse
         binary_tokens encrypt_CharStrings and
	  { % Suppress recognizing the readonly status of the string.
	    4330 exch dup .type1encrypt exch pop wo
	  }
	  { encrypt_CharStrings
	     { 4330 exch dup .type1encrypt exch pop
	     } if
	    smallest_output
	     { wo
	     }
	     { readonly dup length wo
	       binary_tokens not { ( ) ws } if
	       readproc ws wx
	     }
	    ifelse
	  }
	 ifelse
       }
       { wo		% PostScript procedure
       }
      ifelse
    } bind def

% Construct the inversion of the system name table.
  (\210\001) token pop exch pop 1 eq {	% i.e., do we have binary tokens?
    /snit 256 dict def
    0 1 255 {
      (\221 ) dup 1 3 index put
      { token } stopped {
	pop pop
      } {
		% Stack: char () token true
	pop exch pop exch snit 3 1 roll put
      } ifelse
    } for
  } {
    /snit 1 dict def
  } ifelse

% Write an object, using binary tokens if requested and possible.
   /woa		% write in ascii
    { psfile exch write==only
    } bind def

			% Lookup table for ASCII output.

   /intbytes	% int nbytes -> byte*
    { { dup 255 and exch -8 bitshift } repeat pop
    } bind def
   /wotta 10 dict dup begin
      { /booleantype /integertype }
      { { ( ) ws woa } def }
     forall
		% Iterate over arrays so we can print operators.
     /arraytype
      { dup xcheck {(}) ({)} {(]) ([)} ifelse ws exch dup wol exch ws wop
      } bind def
     /dicttype
      { ( ) ws wd } def
     /nametype
      { dup xcheck { ( ) ws } if woa
      } bind def
		% Map back operators to their names,
		% so we can write procedures.
     /nulltype
      { pop ( null) ws
      } bind def
     /operatortype
      { wtstring cvs cvn cvx wo
      } bind def
		% Convert reals to integers if possible.
     /realtype
      { dup cvi 1 index eq { cvi wo } { ( ) ws woa } ifelse
      } bind def
		% == truncates strings longer than 200 characters!
     /stringtype
      { (\() ws dup
	 { dup dup 32 lt exch 127 ge or
	    { (\\) ws dup -6 bitshift 48 add w1
	      dup -3 bitshift 7 and 48 add w1
	      7 and 48 add
	    }
	    { dup dup -2 and 40 eq exch 92 eq or {(\\) ws} if
	    }
	   ifelse w1
	 }
	forall
	(\)) ws wop
      } bind def
     /packedarraytype
      { ([) ws dup { wo } forall
	encodingnames 1 index known
		% This is an encoding, but not one of the standard ones.
		% Use the built-in encoding only if it is available.
	 { encodingnames exch get wo
	   ({findencoding}stopped{pop) ws
	   (}{counttomark 1 add 1 roll cleartomark}ifelse)
	 }
	 { pop ()
	 }
	ifelse
	(/packedarray where{pop counttomark packedarray exch pop}{]readonly}ifelse) ws
	wl
      }
     def
   end def

			% Lookup table for binary output.

   /wottb 8 dict dup begin
   wotta currentdict copy pop
     /integertype
      { dup dup 127 le exch -128 ge and
         { 136 wb 255 and wb }
	 { dup dup 32767 le exch -32768 ge and
	    { 134 wb 2 intbytes wb wb }
	    { 132 wb 4 intbytes wb wb wb wb }
	   ifelse
	 }
	ifelse
      } bind def
     /nametype
      { dup snit exch known
         { dup xcheck { 146 } { 145 } ifelse wb
	   snit exch get wb
	 }
	 { wotta /nametype get exec
	 }
	ifelse
      } bind def
     /stringtype
      { dup dup length dup 255 le { 142 2 } { 2 intbytes 143 3 } ifelse wnb
	ws wop
      } bind def
   end def

   /wop		% Write object protection
     { wcheck not { /readonly cvx wo } if
     } bind def
   /wo		% Write an object.
     { dup type binary_tokens { wottb } { wotta } ifelse
       exch get exec
     } bind def
   /wol		% Write a list of objects.
     { { wo } forall
     } bind def

% Write a hex string for Subrs or CharStrings.
   /wx		% string ->
    { binary_CharStrings
       { ws
       }
       { % Some systems choke on very long lines, so
	 % we break up the hexstring into chunks of 50 characters.
	  { dup length 25 le {exit} if
	    dup 0 25 getinterval psfile exch writehexstring (\n) ws
	    dup length 25 sub 25 exch getinterval
	  } loop
	 psfile exch writehexstring
       } ifelse
    } bind def

% ------ CharString encryption utilities ------ %

/enc_dict 20 dict def
1 dict begin
/bind { } def		% make sure we can print out the procedures
enc_dict begin

(type1enc.ps) runlibfile
enc_dict /.type1decrypt undef		% we don't need this

end end

enc_dict { 1 index where { pop pop pop } { def } ifelse } forall

% ------ Other utilities ------ %

% Test whether two values are equal (for default dictionary entries).
   /valueeq		% <obj1> <obj2> valueeq <bool>
    { 2 copy eq
       { pop pop true }
       {	% Special hack for comparing FontMatrix values
	 dup type /arraytype eq 2 index type /arraytype eq and
	  { dup length 2 index length eq
	     { true 0 1 3 index length 1 sub
		{	% Stack: arr1 arr2 true index
		  3 index 1 index get 3 index 3 -1 roll get eq not
		   { pop false exit }
		  if
		}
	       for 3 1 roll pop pop
	     }
	     { pop pop false
	     }
	    ifelse
	  }
	  { pop pop false
	  }
	 ifelse
       }
      ifelse
    } bind def

% ------ The main program ------ %

% Define the dictionary of keys to skip because they are treated specially.
/.fontskipkeys mark
  /CharStrings dup
  /Encoding dup
  /FDepVector dup
  /FID dup
  /FontInfo dup
  /Metrics dup
  /Metrics2 dup
  /Private dup
.dicttomark def
/.minfontskipkeys mark
  .fontskipkeys { } forall
  /FontName dup
  /UniqueID dup
.dicttomark def
/.privateskipkeys mark
  /ND dup
  /NP dup
  /RD dup
  /Subrs dup
.dicttomark def
/.minprivateskipkeys mark
  .privateskipkeys { } forall
  /MinFeature dup
  /Password dup
  /UniqueID dup
.dicttomark def

% Define the procedures for the Private dictionary.
% These must be defined without `bind',
% for the sake of the DISKFONTS feature.
4 dict begin
 /-! {string currentfile exch readhexstring pop} def
 /-| {string currentfile exch readstring pop} def
 /|- {readonly def} def
 /| {readonly put} def
currentdict end /encrypted_procs exch def
4 dict begin
 /-! {string currentfile exch readhexstring pop
   4330 exch dup .type1encrypt exch pop} def
 /-| {string currentfile exch readstring pop
   4330 exch dup .type1encrypt exch pop} def
 /|- {readonly def} def
 /| {readonly put} def
currentdict end /unencrypted_procs exch def

% Construct an inverse dictionary of encodings.
/encodingnames mark
 StandardEncoding /StandardEncoding
 ISOLatin1Encoding /ISOLatin1Encoding
 SymbolEncoding /SymbolEncoding
 DingbatsEncoding /DingbatsEncoding
 /resourceforall where
  { pop (*) { cvn dup findencoding exch } 100 string /Encoding resourceforall }
 if
.dicttomark def

% Invert the standard encodings.
.knownEncodings length 256 mul dict begin
  0 .knownEncodings
   {  { currentdict 1 index known { pop } { 1 index def } ifelse
	1 add
      }
     forall
   }
  forall pop
currentdict end /inverseencodings exch def

/writefont		% <psfile> writefont - (writes the current font)
 { /psfile exch def
   /Font currentfont def
   /FontInfo Font /FontInfo .knownget not { 0 dict } if def
   /FontType Font /FontType get def
   /hasPrivate Font /Private known def
   /Private hasPrivate { Font /Private get } { 0 dict } ifelse def
   /readproc binary_CharStrings { (-| ) } { (-! ) } ifelse def
   /privateprocs
     encrypt_CharStrings binary_tokens not and
      { encrypted_procs } { unencrypted_procs } ifelse
     def
   /addlenIV false def
   /changelenIV use_lenIV 0 lt
    { 0 }
    { use_lenIV Private /lenIV .knownget not
       { 4 /addlenIV use_lenIV 4 ne def } if sub }
   ifelse def
   /minimize
     smallest_output
     FontType 1 eq and
     Font /UniqueID known and
   def
   (%!FontType) ws FontType wtstring cvs ws (-1.0: ) ws
     currentfont /FontName get wt
     FontInfo /version .knownget not { (001.001) } if wl
   FontInfo /CreationDate .knownget { (%%Creation Date: ) ws wl } if
   FontInfo /VMusage .knownget
    { (%%VMusage: ) ws dup wt wtstring cvs wl }
   if
   (systemdict begin) wl

% If we're going to use eexec, create the filters now.
   /realpsfile psfile def
   eexec_encrypt
    { /eexecfilter psfile binary_CharStrings not
       { pop /bxstring 35 string def
	  { pop dup length 0 ne
	     { realpsfile exch writehexstring realpsfile (\n) writestring }
	     { pop }
	    ifelse bxstring
	  }
	 /NullEncode filter dup /hexfilter exch def
       }
      if 55665 /eexecEncode filter def
    }
   if

% Turn on binary tokens if relevant.
   binary_tokens { (currentobjectformat 1 setobjectformat) wl } if

% If the file has a UniqueID, write out a check against loading it twice.
   minimize
    { Font /FontName get wo
      Font /UniqueID get wo
      Private length addlenIV { 1 add } if wo
      Font length 1 add wo		% +1 for FontFile
      ( .checkexistingfont) wl
    }
    { Font /UniqueID known
       { ({} FontDirectory) ws Font /FontName get dup wo ( known) wl
	 ( {) ws wo ( findfont dup /UniqueID known) wl
	 (    { dup /UniqueID get) ws Font /UniqueID get wo ( eq exch /FontType get 1 eq and }) wl
	 (    { pop false } ifelse) wl
	 (    { pop save /restore load } if) wl
	 ( } if) wl
       }
      if
    }
   ifelse

% If we are writing unencrypted CharStrings for a standard environment,
% write out the encryption procedures.
   privateprocs unencrypted_procs eq standard_only and
    { (systemdict /.type1encrypt known) wl
      ( { save /restore load } { { } } ifelse) wl
      (userdict begin) wl
      enc_dict { we } forall
      (end exec) wl
    }
   if

% Write out the creation of the font dictionary and FontInfo.
   minimize not
    { Font length 1 add wo {dict begin} wol		% +1 for FontFile
    }
   if
   (/FontInfo ) ws FontInfo wd {readonly def} wol

% Write out the other fixed entries in the font dictionary.
   Font begin
   Font
    { minimize
       { .minfontskipkeys 2 index known
	  { pop pop
	  }
	  { //.compactfontdefault 2 index .knownget
	     { 1 index valueeq { pop pop } { we } ifelse }
	     { we }
	    ifelse
	  }
	 ifelse
       }
       { .fontskipkeys 2 index known { pop pop } { we } ifelse
       }
      ifelse
    } forall
   /Encoding
   encodingnames Encoding known
   name_all_Encodings
   Encoding StandardEncoding eq or
   Encoding ISOLatin1Encoding eq or and
    { encodingnames Encoding get cvx }
    { Encoding }
   ifelse
   dup /StandardEncoding cvx eq minimize and
    { pop pop }
    { we }
   ifelse

% Write the FDepVector, if any.
   Font /FDepVector .knownget
    { {/FDepVector [} wol
       { /FontName get wo {findfont} wol () wl } forall
      {] readonly def} wol
    }
   if

% Write out the Metrics, if any.
   Font /Metrics .knownget
    { (/Metrics ) ws wld {readonly def} wol
    }
   if
   Font /Metrics2 .knownget
    { (/Metrics2 ) ws wld {readonly def} wol
    }
   if

% Start the eexec-encrypted section, if applicable.
  eexec_encrypt
   { {currentdict currentfile eexec} wol () wl
     /psfile eexecfilter store
     (\000\000\000\000) ws {begin} wol
   }
  if

% Create and initialize the Private dictionary, if any.
   hasPrivate
{
   Private
   minimize
    { begin {Private dup begin}
    }
    {  dup length privateprocs length add dict copy begin
       privateprocs { readonly def } forall
       /Private wo
       currentdict length 1 add wo {dict dup begin}
    }
   ifelse wol () wl
   currentdict
    { 1 index minimize { .minprivateskipkeys } { .privateskipkeys } ifelse
      exch known
       { pop pop }
       { 1 index /lenIV eq use_lenIV 0 ge and { pop use_lenIV } if we }
      ifelse
    } forall
   addlenIV { /lenIV use_lenIV we } if
}
if

% Write the Subrs entries, if any.
   currentdict /Subrs known
    { (/Subrs[) wl
      Subrs
       { dup null ne
	  { wcs minimize not { () wl } if }
	  { pop /null cvx wo }
	 ifelse
       } forall
      {] dup {readonly pop} forall readonly def} wol () wl
    }
   if

% Wrap up the Private dictionary.
   hasPrivate
    { end			% Private
      minimize
       { {end readonly pop} }	% Private
       { {end readonly def} }	% Private in font
      ifelse wol
    }
   if

% Write the CharStrings entries.
% Detect identical (eq) entries, which bdftops produces.
   currentdict /CharStrings known
{
   /CharStrings wo CharStrings length wo
   minimize
    { encrypt_CharStrings not wo ( .readCharStrings) wl
      CharStrings length dict
      CharStrings
       { exch inverseencodings 1 index .knownget not { dup } if wo
		% Stack: vdict value key
	 3 copy pop .knownget { wo pop pop } { 3 copy put pop wcs } ifelse
       } forall
    }
    { {dict dup Private begin begin} wol () wl
      CharStrings length dict
      CharStrings
       { 2 index 1 index known
	  { exch wo 1 index exch get wo {load def} wol () wl
	  }
	  { 2 index 1 index 3 index put
	    exch wo wcs ( |-) wl
	  }
	 ifelse
       } forall
      {end end} wol
    }
   ifelse
   pop
    { readonly def }	% CharStrings in font
   wol
}
if

% Terminate the output.
   end			% Font
   eexec_encrypt
    { {end mark currentfile closefile} wol () wl
      eexecfilter dup flushfile closefile	% psfile is eexecfilter
      binary_CharStrings not { hexfilter dup flushfile closefile } if
      /psfile realpsfile store
      8
       { (0000000000000000000000000000000000000000000000000000000000000000)
         wl
       }
      repeat {cleartomark} wol
    }
   if
    { FontName currentdict end definefont pop
    }
   wol
   Font /UniqueID known { /exec cvx wo } if
   binary_tokens { /setobjectformat cvx wo } if
   ( end) wl		% systemdict

 } bind def

% ------ Other utilities ------ %

% Prune garbage characters and OtherSubrs out of the current font,
% if the relevant dictionaries are writable.
/prunefont
 { currentfont /CharStrings get wcheck
    { currentfont /CharStrings get dup [ exch
       { pop dup (S????00?) .stringmatch not { pop } if
       } forall
      ] { 2 copy undef pop } forall pop
    }
   if
 } bind def

end			% wrfont_dict

/writefont { wrfont_dict begin writefont end } def