445 lines
17 KiB
PostScript
445 lines
17 KiB
PostScript
% Copyright (C) 2000 artofcode LLC. 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: gs_cidcm.ps,v 1.12 2004/10/25 15:11:37 igor Exp $
|
|
% Extending Font resource category with CIDFont-CMap fonts.
|
|
|
|
languagelevel 2 .setlanguagelevel currentglobal true setglobal
|
|
|
|
|
|
% In the comments below, 'CSI' is an abbreviation/acronym for CIDSystemInfo.
|
|
% We pre-scan resource files to retrieve the CSI from them.
|
|
% First we define a hidden procset .prs_dict containing
|
|
% necessary variables and procedures.
|
|
% Then we redefine the old /Font category using this procset.
|
|
|
|
% We maintain internal caches for the CSI values retrieved from
|
|
% resource files. This supposes that document doesn't uninstall
|
|
% resource files. To disable caching, set enable_cache to false.
|
|
|
|
% We assume that names starting with '.prs' do not appear in resource files.
|
|
% If this causes any problem, this prefix should be systematically changed
|
|
% in this file. ('prs' is an abbreviation for 'prescan'.)
|
|
|
|
25 dict begin
|
|
|
|
% Define local variables :
|
|
|
|
/.prs_dict currentdict def % self-reference (constant)
|
|
/.prs_empty 0 dict readonly def
|
|
/path_buffer 8192 string def
|
|
/name_buffer 1024 string def
|
|
/minus (-) 0 get def % character code constant for '-'
|
|
/period (.) 0 get def % character code constant for '.'
|
|
/CMap 10 dict def % CSI cache for CMaps
|
|
/CIDFont 10 dict def % CSI cache for CIDFonts
|
|
/enable_cache true def % set false to disable cache
|
|
|
|
% The folloving variables are just placeholders for ones to be set
|
|
% dynamically :
|
|
/.prsFile 0 def % file to prescan
|
|
/.prsResult 0 def % result of prescan
|
|
/.prsDictCount 0 def % save the dictionary stack depth
|
|
|
|
% Define a dummy CIDInit procset to use while pre-scanning :
|
|
|
|
/DummyCIDInit 15 dict
|
|
begin
|
|
|
|
/begincmap {} def
|
|
/usecmap {pop} bind def
|
|
|
|
{stop} bind
|
|
[ /begincodespacerange /endcodespacerange /beginnotdefchar /endnotdefchar
|
|
/beginnotdefrange /endnotdefrange /begincidchar /endcidchar /begincidrange
|
|
/endcidrange /endcmap /usefont /StartData
|
|
] {
|
|
1 index def
|
|
} bind forall
|
|
pop
|
|
|
|
currentdict end def
|
|
|
|
% Define a local 'findresource' for pre-scanning :
|
|
% (it returns the dummy CIDInit instead of the regular CIDInit ProcSet)
|
|
|
|
/findresource { % <InstName> <CatName> findresource <inst>
|
|
2 copy /ProcSet eq exch % /InstName /CatName bool /InstName
|
|
/CIDInit eq and {
|
|
pop pop //DummyCIDInit
|
|
} {
|
|
//findresource exec
|
|
} ifelse
|
|
} bind def
|
|
|
|
% Define procedures for pre-scanning :
|
|
|
|
/StopIfCSIDefined { % - StopIfCSIDefined -
|
|
|
|
% Check if the dictionary stack contains a dictionary containing /CIDSystemInfo.
|
|
% The search is limited to the top .prsDictCount dictionaries in the stack.
|
|
% If so, retrieve the CSI, and execute stop to terminate the pre-scanning of the file.
|
|
% Otherwise, do nothing, so the pre-scanning continues.
|
|
|
|
countdictstack //.prs_dict /.prsDictCount get sub dup {
|
|
currentdict /CIDSystemInfo .knownget {
|
|
//.prs_dict exch /.prsResult exch put
|
|
stop
|
|
} if
|
|
currentdict exch end
|
|
} repeat {
|
|
begin
|
|
} repeat
|
|
} bind def
|
|
|
|
/PrescanFile { % - PrescanFile -
|
|
{ //.prs_dict /.prsFile get token {
|
|
dup type % token type
|
|
dup /nametype eq exch /operatortype eq or {
|
|
dup xcheck {
|
|
exec
|
|
//StopIfCSIDefined exec
|
|
} if
|
|
} if
|
|
} {
|
|
stop
|
|
} ifelse
|
|
} loop
|
|
} bind odef
|
|
|
|
/GetCIDSystemInfoFromFile { % <file> GetCIDSystemInfoFromFile <CSI>
|
|
|
|
% This procedure reads resource files with 'token',
|
|
% executing the tokens untill /CIDSystemInfo appears to be defined.
|
|
% Normally the resource file creates a new dictionary on
|
|
% dictionary stack and defines /CIDSystemInfo in it.
|
|
%
|
|
% Returns an empty dictionary if no CIDSystemInfo is found.
|
|
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfoFromFile beg) = } if
|
|
//.prs_dict begin
|
|
/.prsFile exch def
|
|
/.prsResult //.prs_empty def
|
|
/.prsDictCount countdictstack def
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfoFromFile will PrescanFile.) = } if
|
|
{ //PrescanFile } stopped pop
|
|
//.prs_dict /.prsResult get
|
|
end
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfoFromFile end) = } if
|
|
} bind def
|
|
|
|
/GetCIDSystemInfo { % <InstName> <CatName> GetCIDSystemInfo <CSI>
|
|
|
|
% Retrieve CSI, using caches.
|
|
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfo beg) = } if
|
|
/Category findresource begin % /InstName
|
|
dup ResourceStatus
|
|
{
|
|
pop 2 lt {
|
|
FindResource /CIDSystemInfo .knownget not {
|
|
//.prs_empty
|
|
} if % CSI
|
|
} { % /InstName
|
|
currentdict /GetCIDSystemInfoFromMap .knownget {
|
|
exec
|
|
} if
|
|
dup type /nametype eq
|
|
{
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfo got a name.) = } if
|
|
//.prs_dict Category get % /InstName CSIs
|
|
dup 2 index known
|
|
//enable_cache and {
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfo from cache.) = } if
|
|
exch get % CSI
|
|
} {
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfo from file.) = } if
|
|
exch % CSIs /InstName
|
|
dup //path_buffer ResourceFileName % CSIs /InstName (path)
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfo from file ) print dup = } if
|
|
currentglobal exch true setglobal % CSIs /InstName g (path)
|
|
mark exch % CSIs /InstName g [ (path)
|
|
{ (r) file % CSIs /InstName g [ file
|
|
//GetCIDSystemInfoFromFile exec % CSIs /InstName g [ CSI
|
|
} stopped {
|
|
cleartomark //.prs_empty
|
|
} {
|
|
exch pop
|
|
} ifelse % CSIs /InstName g CSI
|
|
exch setglobal % CSIs /InstName CSI
|
|
dup 4 1 roll % CSI CSIs /InstName CSI
|
|
put % CSI
|
|
RESMPDEBUG {
|
|
(cidcm GetCIDSystemInfo got from file : <<) print
|
|
dup { exch //=string cvs print ( ) print
|
|
//=string cvs print ( ) print
|
|
} forall
|
|
(>>) =
|
|
} if
|
|
} ifelse
|
|
} if
|
|
} ifelse
|
|
} {
|
|
pop //.prs_empty
|
|
} ifelse
|
|
end
|
|
RESMPDEBUG { (cidcm GetCIDSystemInfo end) = } if
|
|
} bind def
|
|
|
|
/IsCompatibleCSI { % <CSI-M> <CSI-F> IsCompatibleCSI <bool>
|
|
|
|
% The CSI in a CIDFont may be an array, a dict, or null.
|
|
% If it is an array, it must be of 1 element, which is a dict.
|
|
% In this case the dict is used for testing the compatibility.
|
|
% Two dicts are compatible iff they contain same /Ordering and /Registry.
|
|
|
|
exch % CSI-F CSI-M
|
|
{ dup type /arraytype eq {
|
|
dup length 1 ne {
|
|
pop pop false exit
|
|
} if
|
|
0 get
|
|
} if % CSI-F CSI-M
|
|
dup type /dicttype ne {
|
|
pop pop false exit
|
|
} if % CSI-F <<CSI-M>>
|
|
exch % <<CSI-M>> CSI-F
|
|
dup type /dicttype ne {
|
|
pop pop false exit
|
|
} if % <<CSI-M>> <<CSI-F>>
|
|
true % <<CSI-M>> <<CSI-F>> bEQ
|
|
[/Registry /Ordering] {
|
|
2 index 1 index .knownget not {
|
|
1234567
|
|
} if % <<CSI-M>> <<CSI-F>> bEQ /key vF
|
|
exch % <<CSI-M>> <<CSI-F>> bEQ vF /key
|
|
4 index exch .knownget not {
|
|
7654321
|
|
} if % <<CSI-M>> <<CSI-F>> bEQ vF vM
|
|
eq and % <<CSI-M>> <<CSI-F>> bEQ
|
|
} forall
|
|
exch pop exch pop % bEQ
|
|
exit
|
|
} loop
|
|
} bind def
|
|
|
|
/IsWellComposed { % <CIDFontName> <CMapName> IsWellComposed <bool>
|
|
|
|
% Check if the given CIDFont and CMap have compatible CSIs.
|
|
exch % /CMapName /CIDFontName
|
|
/CIDFont //GetCIDSystemInfo exec % /CMapName CSI-F
|
|
dup type /dicttype eq {
|
|
dup length 0 ne {
|
|
exch % CSI-F /CMapName
|
|
/CMap //GetCIDSystemInfo exec % CSI-F CSI-M
|
|
//IsCompatibleCSI exec % bool
|
|
} {
|
|
pop pop false
|
|
} ifelse
|
|
} {
|
|
pop pop false
|
|
} ifelse
|
|
} bind def
|
|
|
|
/IsComposedFont { % <FontName> IsComposedFont <CIDFontName> <CMapName> true
|
|
% <FontName> IsComposedFont false
|
|
|
|
% Check if the given font name may be decomposed into CIDFont.CMap, CIDFont-CMap
|
|
% or into CIDFont--CMap, such that CIDFont and CMap have compatible CSIs.
|
|
% FontName
|
|
dup type /stringtype ne {
|
|
//name_buffer cvs
|
|
} if % (FontName)
|
|
{ dup length 2 sub -1 1 {
|
|
% (FontName) i
|
|
2 copy get dup //minus eq exch //period eq or {
|
|
2 copy 2 copy % (FontName) i (FontName) i (FontName) i
|
|
2 copy get //minus eq {
|
|
2 copy 1 sub get //minus eq {
|
|
1 sub
|
|
} if
|
|
} if % (FontName) i (FontName) i (FontName) i0
|
|
0 exch getinterval cvn % (FontName) i (FontName) i /CIDFontName
|
|
3 1 roll % (FontName) i /CIDFontName (FontName) i
|
|
1 add dup % (FontName) i /CIDFontName (FontName) i1 i1
|
|
5 index length % (FontName) i /CIDFontName (FontName) i1 i1 l
|
|
exch sub getinterval cvn % (FontName) i /CIDFontName /CMapName
|
|
2 copy //IsWellComposed exec { % (FontName) i /CIDFontName /CMapName
|
|
4 2 roll pop pop % /CIDFontName /CMapName
|
|
stop
|
|
} if
|
|
pop pop pop
|
|
} {
|
|
pop
|
|
} ifelse % (FontName)
|
|
} for
|
|
pop
|
|
} stopped
|
|
} bind def
|
|
|
|
/ComposeName { % <CIDFont> <CMap> <scr> ComposeName <CIDFont-CMap>
|
|
dup dup 5 2 roll % (scr) (scr) /CIDFont /CMap (scr)
|
|
3 2 roll exch cvs length dup % (scr) (scr) /CMap l0 l0
|
|
4 -1 roll exch //minus put % (scr) /CMap l0
|
|
1 add dup % (scr) /CMap l1 l1
|
|
3 index dup length % (scr) /CMap l1 l1 (scr) L
|
|
2 index sub % (scr) /CMap l1 l1 (scr) LT
|
|
3 2 roll % (scr) /CMap l1 (scr) LT l1
|
|
exch getinterval % (scr) /CMap l1 (scrT)
|
|
3 2 roll exch cvs length % (scr) l1 l2
|
|
add 0 exch getinterval % (CIDFont-CMap)
|
|
} bind def
|
|
|
|
% Redefine the /Font category with CIDFont-CMap construction :
|
|
|
|
% The following code supposes that the following names are not
|
|
% defined in the old /Font category dictionary :
|
|
% /IsComposedFont, /IsWellComposed .
|
|
|
|
|
|
/Font /Category findresource dup length dict copy begin
|
|
|
|
/FindResource { % <InstName> FindResource <inst>
|
|
dup //ResourceStatus exec {
|
|
pop pop //FindResource exec
|
|
} {
|
|
dup //IsComposedFont exec { % /FontName /CIDFontName /CMapName
|
|
exch [ exch ] composefont % inst
|
|
} {
|
|
//FindResource exec
|
|
} ifelse
|
|
} ifelse
|
|
} bind def
|
|
|
|
/ResourceStatus { % <InstName> ResourceStatus <nStatus> <nSize> true
|
|
% <InstName> ResourceStatus false
|
|
dup //ResourceStatus exec {
|
|
3 2 roll pop true % nStatus nSize true
|
|
} {
|
|
//IsComposedFont exec { % /CIDFontName /CMapName
|
|
/CMap resourcestatus { % /CIDFontName nStatusM nSizeM
|
|
exch pop exch % nSizeM /CIDFontName
|
|
/CIDFont resourcestatus { % nSizeM nStatusF nSizeF
|
|
exch pop % nSizeF nSizeM
|
|
dup 0 ge {
|
|
exch dup 0 ge {
|
|
add
|
|
} {
|
|
exch pop
|
|
} ifelse
|
|
} {
|
|
pop
|
|
} ifelse % nSize
|
|
2 exch true % nStatus nSize true
|
|
} {
|
|
pop pop pop false % work around buggy resource file
|
|
} ifelse
|
|
} {
|
|
pop pop pop false % work around buggy resource file
|
|
} ifelse
|
|
} {
|
|
false
|
|
} ifelse
|
|
} ifelse
|
|
} bind def
|
|
|
|
/ResourceForAll { % <template> <proc> <scratch> ResourceForAll -
|
|
|
|
% We suppose that the resourceforall procedure does not
|
|
% define or install new fonts, CMaps, and/or CIDFonts.
|
|
|
|
% First we create 3 temporary dictionaries to store temporary data
|
|
% about fonts, CMaps and CIDFonts.
|
|
% These dictionaries must be created dynamically, to allow for a possible
|
|
% recursive call to resourceforall from the resourceforall procedure.
|
|
currentglobal false setglobal
|
|
20 dict 20 dict 20 dict
|
|
|
|
4 -1 roll setglobal % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
|
|
|
|
% Store resource identifiers into local dictionaries
|
|
% A resource instance can have a key that is not a name or a string. In this
|
|
% case, resourceforall passes the key directly to proc instead of copying it
|
|
% into the scratch string. This case can arise only for a resource instance
|
|
% defined in virtual memory by a previous defineresource
|
|
|
|
% Discard non-string keys of CIDFont and CMap because <CIDFontName>- -<CMapName>
|
|
% is only defined for names.
|
|
|
|
{ /.DisableResourceOrdering pop % gs_resmp accesses this through execstack - don't remove !
|
|
|
|
5 index [ 2 index {exch //null put} aload pop ] cvx bind 5 index //ResourceForAll exec
|
|
|
|
(*) [ 3 index {exch dup type /stringtype eq { cvn dup put } { pop pop } ifelse } aload pop
|
|
] cvx bind 5 index /CMap resourceforall
|
|
|
|
(*) [ 4 index {exch dup type /stringtype eq { cvn dup put } { pop pop } ifelse } aload pop
|
|
] cvx bind 5 index /CIDFont resourceforall
|
|
|
|
exit
|
|
} loop % This loop is a pattern for execstack_lookup - don't remove !
|
|
|
|
%% Make the list of fonts in the form (/Name status) :
|
|
|
|
% (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
|
|
dup {
|
|
pop dup
|
|
//ResourceStatus exec {
|
|
pop 2 index % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>> /Name nStatus <<Font>>
|
|
3 1 roll put % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
|
|
} {
|
|
pop
|
|
} ifelse
|
|
} forall % (templ) proc (scr) <<CIDFont>> <<CMap>> <<Fonts>>
|
|
|
|
%% Add CIDFont-CMap to it (filtering duplicates) :
|
|
|
|
3 2 roll {
|
|
3 index {
|
|
3 1 roll % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /CIDFont /CMap
|
|
6 index //ComposeName exec % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap (Font)
|
|
dup 8 index .stringmatch {
|
|
cvn % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font
|
|
dup 4 index exch known {
|
|
pop pop
|
|
} {
|
|
2 index % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CMap /Font /CIDFont
|
|
4 2 roll % (templ) proc (scr) <<CMap>> <<Font>> /Font /CIDFont /CIDFont /CMap
|
|
//IsWellComposed exec {
|
|
exch 2 index exch 2 put % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont
|
|
} {
|
|
exch pop
|
|
} ifelse
|
|
} ifelse
|
|
} {
|
|
pop pop
|
|
} ifelse
|
|
dup % (templ) proc (scr) <<CMap>> <<Font>> /CIDFont /CIDFont
|
|
} forall
|
|
pop pop % (templ) proc (scr) <<CMap>> <<Font>>
|
|
} forall % (templ) proc (scr) <<CMap>> <<Font>>
|
|
exch pop % (templ) proc (scr) <<Font>>
|
|
4 3 roll pop % proc (scr) <<Font>>
|
|
|
|
% Make the enumerator and apply it :
|
|
/MappedCategoryRedefiner /ProcSet findresource /MakeResourceEnumerator get exec exec
|
|
|
|
} bind def
|
|
|
|
|
|
currentdict end /Font exch /Category defineresource pop
|
|
end
|
|
setglobal .setlanguagelevel
|