% Copyright (C) 1995, 2000 Aladdin Enterprises. All rights reserved. % % This file is part of Aladdin Ghostscript. % % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author % or distributor accepts any responsibility for the consequences of using it, % or for whether it serves any particular purpose or works at all, unless he % or she says so in writing. Refer to the Aladdin Ghostscript Free Public % License (the "License") for full details. % % Every copy of Aladdin Ghostscript must include a copy of the License, % normally in a plain ASCII text file named PUBLIC. The License grants you % the right to copy, modify and redistribute Aladdin Ghostscript, but only % under certain conditions described in the License. Among other things, the % License requires that the copyright notice and this notice be preserved on % all copies. % $Id: gs_cidfn.ps,v 1.3 2000/03/10 04:53:25 lpd Exp $ % ProcSet for implementing CIDFont and CIDMap resources. % When this is run, systemdict is still writable. % ---------------- Defining CIDFont resources ---------------- % % Define a CIDFont resource. This is the defineresource implementation for % the CIDFont resource category. /.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse .cidfonttypes begin % The key in .cidfonttypes is the CIDFontType value; % the value is a procedure that takes a font name and the CIDFont dictionary % and replaces the latter with a real font. 0 { % CIDFontType 0 = FontType 9 currentglobal 3 1 roll dup gcheck setglobal dup /FontType 9 put dup /FontMatrix known not { dup /FontMatrix [0.001 0 0 0.001 0 0] put dup /FDArray get { /FontMatrix get [1000 0 0 1000 0 0] 1 index concatmatrix pop } forall } if dup /FDArray get mark exch { % Add pro forma entries currentglobal exch dup gcheck setglobal dup /FontType 1 put dup /CharStrings mark /.notdef () .dicttomark put dup /Encoding [] put % Create a dummy Subrs array now, if there isn't one here % already (which can only happen if we're giving another % name to an existing font). dup /Private get dup /Subrs known not { dup /SubrCount .knownget { array 1 index /Subrs 3 -1 roll put } if readonly } if pop exch setglobal dup /FontName .knownget not { () } if exch .buildfont1 exch pop } forall ] 1 index /FDepVector 3 -1 roll put 3 -1 roll setglobal 1 index exch .buildfont9 exch pop } bind def 1 { % CIDFontType 1 = FontType 10 dup /FontType 10 put 1 index exch .buildfont10 exch pop } bind def 2 { % CIDFontType 2 = FontType 11 dup /FontType 11 put 1 index exch .buildfont11 exch pop } bind def end % .cidfonttypes % ---------------- Reading CIDFontType 0 files ---------------- % 30 dict begin % We add the following entries to the CIDFont dictionary, in addition to % the ones documented by Adobe: % ReadString - procedure for reading a string from the binary data % SubrCache - dictionary for caching Subr arrays % For CIDFonts where we read the data from disk incrementally: % DataOffset - starting position of data in file % (if data are in hex) OffsetMap - map from logical data positions to % physical positions in file /StartData % <(Binary)|(Hex)> StartData - % (currentdict is CID font dict) { % If we're loading a resource file, we can just save a % pointer to the binary data and load it incrementally. % Check for this by opening the resource file, % positioning it to currentfile's position plus the % data length, and checking for %%EndData. mark { currentfile fileposition CIDFontName 100 string ResourceFileName (r) file mark { % Stack: (Binary)|(Hex) length -mark- pos resfile % -mark- 5 index (Hex) eq { 1 index 3 index setfileposition 1 index 5 index .skiphex %**************** SKIP > AND WHITESPACE SOMEHOW } { 1 index 3 index 6 index add setfileposition } ifelse 1 index 9 string readstring pop (%%EndData) ne { stop } if } .internalstopped { cleartomark closefile stop } if pop % pop the mark } .internalstopped { % File is not positionable, load the data now. cleartomark exch (Hex) eq { { currentfile exch readhexstring pop } } { { currentfile exch readstring pop } } ifelse /ReadString exch def dup 65535 le { % readstring with a 0-length string causes a rangecheck, % but a data length of 0 is allowed. string dup () ne { ReadString } if } { mark exch { dup 0 eq { pop exit } if dup 65535 min dup string ReadString 3 1 roll sub } loop ] } ifelse /GlyphData exch def % If we were reading hex data, skip past the >. /ReadString load 2 get { readhexstring } 0 get eq { currentfile 0 (>) /SubFileDecode filter dup flushfile closefile } if /.vmreadstring cvx } { % File is positionable, just save a pointer. % Stack: (Binary)|(Hex) length -mark- pos file 4 1 roll /DataOffset exch def pop /GlyphData exch def exch (Hex) eq { % Hex data, build the offset map. .buildoffsetmap /.hexreadstring } { % Binary data, just skip over it. currentfile DataOffset GlyphData add setfileposition /.binaryreadstring } ifelse cvx 2 packedarray cvx } ifelse /ReadString exch def /SubrCache 10 dict def CIDFontName currentdict /CIDFont defineresource pop end % CID font dict end % resource category dict } bind def % Skip a given distance in an ASCIIHex encoded file. We use this at % rendering time as well. /.skiphex % .skiphex - { exch /ASCIIHexDecode filter dup 3 -1 roll () /SubFileDecode filter dup flushfile closefile closefile } bind def % Build the map from logical offsets to physical offsets in ASCIIHex % encoded data. /.buildoffsetmap { /OffsetMap GlyphData 256 idiv 8000 min array def 2 dict begin /block GlyphData OffsetMap length idiv def 0 1 OffsetMap length 1 sub { OffsetMap exch currentfile fileposition put currentfile block .skiphex } for GlyphData block mod dup 0 eq { pop } { currentfile exch .skiphex } ifelse end % scratch dict } bind def % Some Adobe fonts include the line % /Setup /cid_Setup load def % This is apparently included only to prevent proper, conforming PostScript % interpreters (as opposed to ATM or a special Adobe font loader) from % loading the font, since Setup is not referenced anywhere else in the file. %/cid_Setup { } def currentdict end % ---------------- Rendering ---------------- % % ------ Generic ------ % % Read a string at a given offset in a "file" (binary file, ASCII hex file, % or GlyphData in RAM). /.binaryreadstring % .binaryreadstring { dup 4 -1 roll DataOffset add setfileposition exch readstring pop } bind def /.hexreadstring % .hexreadstring { % Use the OffsetMap to get to the block of hex data, % then skip to the correct position by reading. GlyphData OffsetMap length idiv % Stack: pos string file blocklen 3 index 1 index idiv OffsetMap exch get 2 index exch setfileposition % Skip the next (pos % blocklen) hex bytes. 4 -1 roll exch mod 1 index exch .skiphex % Stack: string file exch readhexstring pop } bind def /.vmreadstring % .vmreadstring { GlyphData .stringsreadstring } bind def /.stringsreadstring % .stringsreadstring % { dup type /stringtype eq { 3 1 roll length getinterval } { { % Stack: pos string glyphdata dup 0 get length dup 4 index gt { exit } if 4 -1 roll exch sub 3 1 roll dup length 1 sub 1 exch getinterval } loop % Stack: pos string glyphdata glyphdata[0]length % We know no request can span more than 2 strings. 3 index 3 index length add 1 index le { % Request fits in a single string: just return a substring. pop 0 get 3 1 roll length getinterval } { % Request spans 2 strings. Copy the first part. 1 index 0 get 4 index 3 -1 roll 1 index sub getinterval 2 index copy % Copy the second part. % Stack: pos str glyphdata str1 length exch 1 get 0 3 index length 3 index sub getinterval 2 index 3 1 roll putinterval exch pop } ifelse } ifelse } bind def % Interpret a byte string as a (big-endian) integer. /.cvbsi % .cvbsi { 0 exch { exch 8 bitshift add } forall } bind def % Read an integer from binary data. /.readint % .readint { string ReadString .cvbsi } bind def % Read the glyph data for a given CID. The CIDFont is currentdict. % Note that the data must be read into the same VM as the CharStrings % dictionary of the selected subfont. /.readglyphdata { % .readglyphdata currentdict /GlyphDirectory .knownget { dup type /arraytype eq { 1 index get } { 1 index .knownget not { null } if } ifelse % Stack: cid string|null dup null ne { exch pop .readgdirdata } { pop .readbytedata } ifelse } { % Stack: cid .readbytedata } ifelse } bind def /.readgdirdata { % .readgdirdata dup null eq { FDepVector 0 get exch } { FDBytes 0 eq { FDepVector 0 get exch } { % Note: FDBytes > 1 is not supported. dup 0 get FDepVector exch get exch dup length 1 sub 1 exch getinterval } ifelse } ifelse } bind def /.readbytedata { % .readbytedata dup dup 0 ge exch CIDCount lt and { FDBytes GDBytes add mul CIDMapOffset add dup FDBytes .readint exch FDBytes add dup GDBytes .readint exch GDBytes add FDBytes add GDBytes .readint % Stack: fd pos nextpos 1 index sub dup 0 eq { pop pop pop FDepVector 0 get null } { % Stack: fd pos len FDepVector 4 -1 roll get dup /CharStrings get gcheck .currentglobal exch .setglobal % Stack: pos len subfont global 4 2 roll string ReadString exch .setglobal } ifelse } { pop FDepVector 0 get null } ifelse } bind def % ------ CIDFontType 0 ------ % % Read some Subrs for the current Type 1 subfont. % The subfont's Private dict is currentdict; the CIDFont itself is the % next dictionary on the stack. /.readsubrs { % .readsubrs 1 SubrCount 1 sub { dup SDBytes mul SubrMapOffset add dup SDBytes .readint exch SDBytes add SDBytes .readint 1 index sub string ReadString 2 index 3 1 roll put } for } bind def % Ensure that all the Subrs for the current Type 1 subfont are loaded. % The subfont's Private dict is currentdict; the CIDFont itself is the % next dictionary on the stack. /.loadsubrs { currentdict /SubrMapOffset .knownget { Subrs length 0 eq { true } { Subrs 0 get null ne } ifelse { pop % We've already loaded the Subrs. } { currentglobal exch currentdict gcheck setglobal SubrCache 1 index .knownget { % We've already loaded some Subrs at this offset. % Make sure we've got as many as we need. dup length SubrCount lt { % We need to load more. SubrCount array exch 1 index copy length .readsubrs SubrCache 3 -1 roll 2 index put } if } { % We haven't loaded any Subrs at this offset yet. SubrCount array 0 .readsubrs SubrCache 3 -1 roll 2 index put } ifelse Subrs copy pop setglobal } ifelse } if } bind def % BuildGlyph procedure for CIDFontType 0. % ****** WHY NOT USE .type1execchar FOR THIS? ****** % The name %Type9BuildGlyph is known to the interpreter. /.cid0buildstring 10 string def (%Type9BuildGlyph) cvn { % %Type9BuildGlyph - .currentglobal 3 1 roll 1 index gcheck .setglobal 1 index begin dup .readglyphdata dup null eq { % Substitute CID 0. **** WRONG **** pop pop 0 .readglyphdata } if % Stack: cidfont cid subfont charstring dup null eq { pop pop pop pop } { %**** WRONG **** 4 -1 roll pop exch dup /Private get begin .loadsubrs end 3 -1 roll //.cid0buildstring cvs cvn 3 1 roll dup /CharStrings get 3 index 4 -1 roll put setfont dup .glyphwidth setcharwidth 0 0 moveto glyphshow } ifelse %**** WRONG **** end .setglobal } bind def % ------ CIDFontType 2 ------ % % BuildGlyph procedure for CIDFontType 2. % ****** ADD THE OUTLINE STRING AS AN ARGUMENT TO .type42execchar. ****** % The name %Type11BuildGlyph is known to the interpreter. (%Type11BuildGlyph) cvn { % %Type11BuildGlyph - .currentglobal 3 1 roll 1 index gcheck .setglobal 1 index begin % We must be prepared for out-of-range CIDs. dup GDBytes mul GDBytes string CIDMap mark 4 1 roll { .stringsreadstring } .internalstopped { %**** 0 IS WRONG cleartomark 0 GDBytes string CIDMap .stringsreadstring } { exch pop } ifelse .cvbsi % Stack: cidfont cid glyphindex 1 index exch .type42execchar end .setglobal } bind def % ---------------- Define resources ---------------- % languagelevel exch 2 .setlanguagelevel % Define the CIDInit ProcSet resource. % The ProcSet dictionary is still on the stack. /CMap /Generic /Category findresource dup length dict .copydict /Category defineresource pop % We might have loaded CMap support already. /CIDInit /ProcSet 2 copy resourcestatus { pop pop findresource dup length 4 index length add dict .copydict 4 -1 roll exch .copydict } { 3 -1 roll } ifelse exch defineresource pop % Define the CIDFont resource category. % We break out .buildcidfont because it appears that at least for % Type 32 (CIDFontType 4) fonts, the font can be registered in the Font % category with only a CIDFontType and no FontType. /.buildcidfont { % .buildcidfont % dup /CIDFontType get //.cidfonttypes exch get exec } odef /CIDFont /Generic /Category findresource dup length dict .copydict dup /InstanceType /dicttype put dup /DefineResource { .buildcidfont /Generic /Category findresource /DefineResource get exec } put /Category defineresource pop % Add the new FontType resources. 9 1 11 { dup /FontType defineresource pop } for % Add the new FMapType resource. 9 dup /FMapType defineresource pop % Define the CIDMap resource category. % These aren't documented, but it's clear what they are for: % to give names to CIDMaps for CIDFontType 2 fonts. /CIDMap /Generic /Category findresource dup length dict .copydict dup /.CheckResource { % Allow either a string or an array of strings. dup type dup /stringtype eq { pop true } { dup /arraytype eq exch /packedarraytype eq or { true exch { type /stringtype ne { pop false exit } if } forall } { false } ifelse } ifelse } bind put /Category defineresource pop .setlanguagelevel