% Copyright (C) 2001-2022 Artifex Software, Inc. % 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. % % Refer to licensing information at http://www.artifex.com or contact % Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, % CA 94945, U.S.A., +1(415)492-9861, for further information. % % PDF font operations. % Since PDF font are not unique and can collide with external font resources % or each other, use font dictionaries obtained from PDF directly, never % register them as resources or look them up by name. Use findfont oparator % for non-embedded fonts only. CIDFont resources still use the old logic % described below. % Finding a font by name can't give a proper result when PDF font names aren't unique. % But it is only the way to obtain a font in Postscript after a font file is executed. % Therefore using a FontName (and findfont) is allowed only % immediately after a font file is executed. % In all other cases the font to be found by a pointer through PDF structures. % % This ideal logics can't work for documents, % which define a font resource with an embedded font, % and another font resource with same BaseFont but with no embedded font % (and possibly with no font descriptor). % Our testbase does contain such examples. % In this case we do find font by FontName (with findfont), % since there is no other way to get a reasonable result. /.setlanguagelevel where { pop 2 .setlanguagelevel } if .currentglobal //true .setglobal /GS_PDF_ProcSet load begin % from userdict at this point pdfdict begin % We cache the PostScript font in an additional element of the % font resource dictionary, called PSFont. % ---------------- Encodings ---------------- % /.notdefEncoding 256 { /.notdef } repeat 256 packedarray def % Apply a list of differences to an Encoding. % Note that the differences may cause the array to grow. /updateencoding { % updateencoding % Calculate the length of the result. % in case the incoming Encoding is null, use .notdefEncoding exch dup //null eq { pop .notdefEncoding } if 0 0 3 index { dup type /nametype ne { exch pop oforce } { pop 1 add } ifelse % Differences list may not be in order, update the largest_index % stack: 2 copy lt { exch pop dup } if % at_index is new largest } forall pop 1 index length .max array dup 0 4 -1 roll putinterval exch 0 exch { % Stack: enc' code element dup type /nametype ne { exch pop oforce } { 3 copy put pop 1 add } ifelse } forall pop } bind executeonly def /good_encoding_names << /MacRomanEncoding 0 /MacExpertEncoding 0 /WinAnsiEncoding 0 >> readonly def /known_symbolic_fonts << /Wingdings2 0 /ZapfDingbats 0 >> readonly def % Get the Encoding for a font. /getencoding % getencoding { dup /Encoding knownoget { dup type /nametype eq { % The published PDF specification says the Encoding name % "must be" one of the 3 predefined Encodings, implying % that an error should occur if it isn't. However, Acrobat % Reader simply ignores unknown names, and since there are % some buggy applications that rely on this, we do the same. //good_encoding_names 1 index known { exch /BaseFont knownoget not { 0 } if % Ignore named encodings for known symbolic fonts. See bug 690135. //known_symbolic_fonts exch known { pop } { exch pop findencoding } ifelse } { pop pop } ifelse } { exch pop dup type /arraytype eq { exch pop ( **** Warning: Encoding is an array, not name or dictionary.\n) pdfformatwarning } { dup /BaseEncoding knownoget { %% Originally we ignored the specific invalid name '/' here from Bug #687786, however %% Bug #696942 contains an invalid BaseEncoding '/utf-8', so now we check all BaseEncoding %% against the permitted names, just as we do for Encodings. //good_encoding_names 1 index known{ findencoding 3 -1 roll pop exch }{ ( **** Error: Invalid BaseEncoding name ") print 256 string cvs print (" ignoring BaseEncoding.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror }ifelse } if /Differences knownoget { updateencoding } if } ifelse } ifelse } { pop ( **** Error: Encoding not present.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror } ifelse } bind executeonly def currentdict /good_encoding_names undef currentdict /known_symbolic_fonts undef /checkGlyphNames2Unicode % checkGlyphNames2Unicode - { PDFDEBUG { dup /FontInfo .knownget { /GlyphNames2Unicode .knownget { (Has GlyphNames2Unicode) = pop % { exch //== exec //== exec} forall } if } if } if pop } bind executeonly def % Define a font using it's FontName as the key. % Adjust a font according to the Encoding and Widths in the font resource. /adjustfont { % adjustfont getfontencoding 3 copy .processToUnicode getfontmetrics 5 -1 roll pop .updatefont { %% Bug #696306 has a broken type 1 font where the eexec encrypted portion simply ends %% leaving a partial glyph description and, more importantly, the Private dictionary %% on the operand stack. Ths means the font dictonary does not contain a Private %% dictionary which causes .buildfont1 to throw an error. .completefont calls .buildfont1 %% (which is obscured by a definition in gs_type1.ps) so we need to check the reault %% of .completefont. If it fails we must discard the font dictionary and use a fallback. {.completefont} stopped { (\n *** ERROR: The font ) print /FontName get 256 string cvs print ( is damaged and cannot be used. Switching to a\n) pdfformaterror ( last-ditch fallback, text may not render correctly, or at all.\n\n) pdfformaterror /Helvetica findfont }if } if } bind executeonly def % Get the (possibly modified) encoding of a font. /getfontencoding { % getfontencoding % % Ignore encoding when TrueType is requested % and loaded from an embedded stream. % All other cases are left unchanged. dup /FontType get 42 eq 1 index /PathLoad known not and 2 index /Subtype get /TrueType eq and { //null } { % Acrobat appears to be always using StandardEcoding as the % default encoding for some non-symbolic fonts (rather than, % as the spec states, the encoding specified by the font). % As this is contrary to spec, and we only have a CFF % example, I've restricted this to fonts with Subtype Type1C % *and* that result in a Type 2 PS font. 1 index /FontDescriptor knownoget { dup % Unfortunately, Acrobat doesn't enforce the meaning of % FontFile[23] so whilst, in theory, Type1C should only % occur in FontFile3, we can't rely on that. dup /FontFile knownoget not { dup /FontFile2 knownoget not { dup /FontFile3 knownoget not {1 dict} if } if } if exch pop /Subtype knownoget {/Type1C eq}{//false} ifelse exch /Flags knownoget {4 and 4 eq not}{//false}ifelse and } {//false} ifelse 1 index /FontType get 2 eq and { 2 index /Encoding knownoget {pop StandardEncoding 2 index getencoding} { //null } ifelse } { 2 index /Encoding known { dup /Encoding knownoget { 2 index getencoding } { //null } ifelse } { //null } ifelse } ifelse } ifelse } bind executeonly def % Returns true if the current glyph is in the Differences array at % the specified index value. This is needed because the Widths % array may map to the same glyph at different positions from the % Encoding. We want to use the Width that was associated with the % one specified in the Encoding::Differences list. /match_in_diff % match_in_diff { //false 4 1 roll 0 4 -1 roll % stack: false index glyphname at_index==0 Differences { exch 1 index type /nametype ne { % stack: false index glyphname Diff_element at_index pop % Diff_element is new at_index } { % stack: false index glyphname Diff_element at_index exch 2 index eq { % stack: false index glyphname at_index dup 3 index eq { //true 5 1 roll % stack: true false index glyphname at_index pop exit } if } if 1 add % at_index++ stack: false index glyphname at_index' } ifelse } forall % stack: true false index glyphname % or : false index glyphname at_index pop pop pop } bind executeonly def /unique_name { % unique_name % % Note : this function interacts with pdf_write_encoding in src/gdevpdtw.c % and with copied_drop_extension_glyphs in src\gxfcopy.c % by adding a reserved substring (~GS~). % .namestring % <<>> (root) 0 1 65535 { 5 string cvs % <<>> (root) (0) (~GS~) exch concatstrings 1 index exch % <<>> (root) (root) (~GS~0) concatstrings % <<>> (root) (root~GS~0) dup % <<>> (root) (root~GS~0) (root~GS~0) 3 index exch % <<>> (root) (root~GS~0) <<>> (root~GS~0) known not { exch pop exit % <<>> (root~GS~0) } if pop } for exch pop cvn % /root0 } bind executeonly def % Get the metrics of a font, if specified. /getfontmetrics { % getfontmetrics % % 2 index /Widths oknown { dup //null eq { pop dup /Encoding get } if 7 dict begin dup length dict /Metrics exch def /Encoding exch def /GlyphMap //null def exch dup /Widths oget /Widths exch def % Stack: font font-res % Note that widths are always based on a 1000-unit % character space, but the FontMatrix may specify % some other scale factor. Compensate for this here, % by scaling the Widths if necessary. 0.001 2 index /FontMatrix get 0 get dup 0 eq { % FontMatrix.xx == 0, so we cannot scale down by xx. % - FontMatrix[0] == 0 implies either FontMatrix[1] <> 0 or % FontMatrix cannot be inverted. In the 1st case we have % FontMatrixNonHV == true and will render text with cshow + xshow. % In the 2nd case, metrics in the PDF Font object cannot be enforced % [by altering metrics in PS glyph space]. % HACK: % - we scale down by FontMatrix[1]; % - given the format of Metrics entries we use, wy = 0 in glyph space; % - as a result, the cshow procedure receives as wy the value we % need for wx (all of this in PS user space). pop 2 index /FontMatrix get 1 get dup 0 eq { pop 1 } if % sorry, no way to enforce PDF metrics by altering the font } if div % Stack: font font-res mscale /FirstChar 2 index /FirstChar knownoget not { ( **** Warning: /FirstChar attribute is missing, assuming 0.\n) pdfformatwarning 0 } if def /LastChar 2 index /LastChar knownoget not { ( **** Warning: /LastChar attribute is missing, assuming 255.\n) pdfformatwarning 255 } if def Encoding length LastChar le { ( **** Warning: Font Encoding array size is smaller than character range.\n) pdfformatwarning } if 1 index /FontDescriptor knownoget { /MissingWidth knownoget not { 0 } if } { 1000 } ifelse /MissingWidth exch def Widths length LastChar FirstChar sub le { ( **** Warning: Font Widths array size is smaller than character range.\n) pdfformatwarning /Widths [Widths aload length LastChar FirstChar sub exch sub MissingWidth exch {dup} repeat] def } if FirstChar 0 Encoding { % Stack: font font-res mscale first-char index charname 1 index FirstChar lt { MissingWidth } { 1 index LastChar gt { MissingWidth } { Widths 2 index FirstChar sub get } ifelse } ifelse oforce % Stack: font font-res mscale first-char index charname width 4 index mul % The following 'loop' is only context for 'exit'. { % Work around a bug in pdfTeX, which can generate Encoding % vectors containing nulls : 1 index //null eq { exit } if Metrics 2 index .knownget { 1 index ne } { //false } ifelse { % Two or more Encoding elements refer same glyph name, % and Widths specify different wihts for it. % Since a Postscript font can't have different % Metrics for same glyph name, % we generate an unique name, and create a new % Charstrings entry with same glyph value. GlyphMap //null eq { /Encoding Encoding dup length array copy def /GlyphMap 4 dict def } if % To prevent too many new names, check whether % we can use one already created for same glyph. //true GlyphMap { % f r s c i n w b n1 n2 4 index eq { % f r s c i n w b n1 dup Metrics exch get % f r s c i n w b n1 w1 3 index eq { % f r s c i n w b n1 4 3 roll pop % f r s c i w b n1 3 1 roll pop % f r s c i n1 w Encoding 3 index 3 index put //false % f r s c i n1 w b exit } { pop } ifelse } { % f r s c i n w b n1 pop } ifelse } forall % f r s c i n w b { % Do create a new name. Metrics 2 index //unique_name exec % f r s c i n w nn Encoding 4 index 2 index put GlyphMap 1 index 5 -1 roll put % f r s c i w nn exch % Stack: font font-res mscale first-char index new_name width } if } if 2 copy Metrics 3 1 roll put exit } loop pop pop 1 add } forall pop pop pop exch Encoding Metrics GlyphMap end } { //null //null } ifelse } bind executeonly def currentdict /unique_name undef currentdict /match_in_diff undef /ToUnicodeCMapReader 4 dict begin /defineresource % defineresource { pop dup userdict exch /.lastToUnicode exch put exch pop } bind executeonly def /CIDSystemInfo { ( **** Warning: ToUnicode CMap has invalid syntax near CIDSystemInfo.\n) pdfformatwarning /CIDSystemInfo } bind executeonly def % A work around a bug in Altona.Page_3.2002-09-27.pdf - a slash is missed. /CMapName { ( **** Warning: ToUnicode CMap has no CMapName.\n\ See the comment to revision 6201 in gs/doc/ps2pdf.htm#Problems .\n) pdfformatwarning /CMap1 % arbitrary, PDF defineresource tolerates non-unique names } bind executeonly def % A work around incorrect ToUnicode CMap generated by GS before rev. 6201. % Split large ranges into smaller chunks to stay withing the limits % of various PS% objects and speed up operand stack manipulation, % esp. "counttomatk -3 roll". Bug 691908. /beginbfrange { { pop mark 256 { currentfile token not { /endbfrange exit } if dup /endbfrange eq { exit } if currentfile token not { pop /endbfrange } if currentfile token not { pop pop /endbfrange } if dup ([) eq { pop [ { currentfile token not { exit } if dup (]) eq { pop exit } if } loop ] } if } repeat dup /endbfrange eq { pop endbfrange exit } { endbfrange mark } ifelse } loop } bind executeonly def currentdict end readonly def /string2number % string2number { 0 exch dup 0 exch 1 exch length 1 sub { % n () i 1 index exch get % n () v 3 2 roll 256 mul add exch % v+n*256 () } for pop % N } bind executeonly def /copy&def % copy&def - { { //true } { currentdict gcheck { dup gcheck not } { //false } ifelse } ifelse { currentglobal currentdict gcheck setglobal exch dup length string copy exch setglobal } if def } bind executeonly def /.convert_ToUnicode-into-g2u % .convert_ToUnicode-into-g2u - { CMAPDEBUG { (.convert_ToUnicode-into-g2u beg) = } if 3 2 roll begin /.CodeMapData get % About the data format see gs_cmap.ps, the comment after "CMap operators". 1 get % code maps { CMAPDEBUG { dup //== exec } if dup length 1 sub 0 exch 5 exch { % e [] i 2 copy get % e [] i (prefix) string2number % e [] i prefix 2 index 2 index 1 add get % e [] i prefix (key_size,?is_range,value_type,value_size) dup 0 get 8 mul % e [] i prefix (key_size,?is_range,value_type,value_size) key_size*8 3 2 roll exch bitshift exch % e [] i prefix< .processToUnicode - { //.DoToUnicode? exec { currentdict count 1 sub /.stackdepth exch .forceput currentdict countdictstack /.dstackdepth exch .forceput { 1 index /FontType get 0 eq { 1 index /FDepVector get 0 get dup /FontType .knownget not { dup /CIDFontType .knownget { dup 2 eq {pop 11} if } {-1} % just some value that's not a valid font type ifelse }if 11 eq { /Path known} {pop //false} ifelse } {//false} ifelse % Currently pdfwrite is only device which can handle GlyphNames2Unicoide to % generate a ToUnicode CMaps. So don't bother with other devices. /WantsToUnicode /GetDeviceParam .special_op { exch pop }{ //false }ifelse or { PDFDEBUG { (.processToUnicode beg) = } if 2 index /ToUnicode knownoget { dup type /nametype eq { % This is contrary to the specification but it seems that Acrobat at least will accept % a ToUnicode with a value of Identity-H *and* will use that for search, copy/paste. % We can't pass through a name, so the best we can do is build a GlyphNames2Unicode % map matching that which would have been generated by a full 16-bit Identity CMap % % See bug numbers 701003 and 687351 % dup /Identity-H eq 1 index /Identity-V eq or{ pop 1 index /FontInfo .knownget not { currentglobal 2 index dup gcheck setglobal /FontInfo 5 dict dup 5 1 roll .forceput setglobal } executeonly if dup /GlyphNames2Unicode .knownget not { //true % No existing G2U, make one } { dup wcheck { //false % Existing, writeable G2U, don't make new one } { pop //true % Existing read only G2U, make new one } ifelse } ifelse { currentglobal exch dup gcheck setglobal dup /GlyphNames2Unicode 100 dict dup 4 1 roll .forceput 3 2 roll setglobal } if % font-res font-dict encoding|null font-info g2u 0 1 65535{ % g2u index dup dup 256 mod exch 256 idiv % g2u index lo-byte hi-byte 2 string dup 0 4 -1 roll % g2u index lo-byte () () 0 hi-byte put % g2u index lo-byte (x) dup 1 % g2u index lo-byte (x) (x) 1 4 -1 roll put % g2u index (x) (x) 1 lo-byte -> dict index (xx) 2 index % g2u index (xx) dict 3 1 roll % g2u g2u index (xx) put % g2u } for pop % font-res font-dict encoding|null font-info pop % font-res font-dict encoding|null //false % We built a GlyphNames2Unicode table, don't need to process further } executeonly { //true % name is not Identity-V or H, fail by falling through }ifelse } executeonly { //true } ifelse % not a name, try as a dictionary (as specified) % If the ToUnicode isn't a name, or the name isn't Identity-V or -H then follow the specification % If its not a dictionary type throw an error, otherwise decode it and build a GlyphNames2Unicode % { dup type /dicttype eq { dup /File known not } { //true } ifelse { % We undefine wrong /Length and define /File in stream dictionaries. % Bug687351.pdf defines /ToUnicode /Identity-H, what is incorrect. ( **** Warning: Ignoring bad ToUnicode CMap.\n) pdfformatwarning pop } { /PDFScanRules .getuserparam dup //null eq { pop //PDFScanRules_null } { 1 dict dup /PDFScanRules 4 -1 roll put } ifelse //PDFScanRules_true setuserparams PDFfile fileposition 3 -1 roll count 1 sub countdictstack { //false resolvestream % Following Acrobat we ignore everything outside % begincodespacerange .. endcmap. dup 0 (begincodespacerange) /SubFileDecode filter flushfile /CIDInit /ProcSet findresource begin //ToUnicodeCMapReader begin 12 dict begin /CMapType 2 def mark exch % emulate 'begincodespacerange' 0 (endcmap) /SubFileDecode filter cvx /begincmap cvx exch 2 .execn endcmap userdict /.lastToUnicode currentdict put end end end } PDFSTOPONERROR { { exec } 0 get //false 5 -2 roll 5 } { { stopped } 0 get 4 2 roll 4 } ifelse array astore cvx exec countdictstack exch sub 0 .max { end } repeat count exch sub 2 sub 0 .max { exch pop } repeat 3 1 roll % Stach the stop flag. PDFfile exch setfileposition setuserparams { ( **** Warning: Failed to read ToUnicode CMap.\n) pdfformatwarning } { 1 index /FontInfo .knownget not { currentglobal 2 index dup gcheck setglobal /FontInfo 5 dict dup 5 1 roll .forceput setglobal } if dup /GlyphNames2Unicode .knownget not { //true % No existing G2U, make one } { dup wcheck { //false % Existing, writeable G2U, don't make new one } { pop //true % Existing read only G2U, make new one } ifelse } ifelse { currentglobal exch dup gcheck setglobal dup /GlyphNames2Unicode 100 dict dup 4 1 roll .forceput 3 2 roll setglobal } if % font-res font-dict encoding|null font-info g2u exch pop exch % font-res font-dict g2u encoding|null userdict /.lastToUnicode get % font-res font-dict g2u Encoding|null CMap .convert_ToUnicode-into-g2u % font-res font-dict //null % font-res font-dict //null } ifelse } ifelse } if PDFDEBUG { (.processToUnicode end) = } if } executeonly if } executeonly if } executeonly stopped { .dstackdepth 1 countdictstack 1 sub {pop end} for .stackdepth 1 count 3 sub {pop pop} for } if pop pop pop currentdict /.stackdepth .forceundef currentdict /.dstackdepth .forceundef } executeonly {pop pop pop} ifelse } bind executeonly odef currentdict /.DoToUnicode? .forceundef % ---------------- Descriptors ---------------- % % Partial descriptors for the 14 built-in fonts. Note that % from PDF 1.1 to PDF 1.2, the meaning of the Flag 6 in the FontDescriptor % object has undergone a subtle change in its meaning which has serious % consequences for searching with Acrobat: % In PDF 1.1, the flag meant: Font has StandardEncoding % In PDF 1.2, the flag means: Font has (subset of) StandardRomanCharacterSet /standardfontdescriptors mark /Courier mark /Flags 16#23 .dicttomark /Courier-Oblique 1 index /Courier-Bold 1 index /Courier-BoldOblique 1 index /Helvetica mark /Flags 16#20 .dicttomark /Helvetica-Oblique 1 index /Helvetica-Bold 1 index /Helvetica-BoldOblique 1 index /Times-Roman mark /Flags 16#22 .dicttomark /Times-Bold 1 index /Times-Italic mark /Flags 16#62 .dicttomark /Times-BoldItalic 1 index /Symbol mark /Flags 16#4 .dicttomark /ZapfDingbats 1 index .dicttomark readonly def % ---------------- Utilities ---------------- % /.pdforigfontcache_g 20 dict def currentglobal //false setglobal systemdict /.pdforigfontcache_l 20 dict .forceput setglobal % Find an original font, using cache to prevent adjustfont to accumulate changes. /pdffindcachedfont { % pdffindcachedfont dup //.pdforigfontcache_g exch .knownget { exch pop } { dup .pdforigfontcache_l exch .knownget { exch pop } { dup findfont dup dup gcheck { //.pdforigfontcache_g } { .pdforigfontcache_l } ifelse % Stack : font_name font font cache 4 2 roll .growput } ifelse } ifelse } bind executeonly def % Add original font to cache to prevent adjustfont to accumulate changes. /pdfaddcachedfont { % pdfaddcachedfont dup findfont dup % name font font dup gcheck { //.pdforigfontcache_g } {.pdforigfontcache_l} ifelse 4 2 roll % font d name font put % font } bind executeonly def /.remove_font_name_prefix { % .remove_font_name_prefix dup .namestring (+) search { //true exch { dup 65 lt exch 90 gt or { pop //false exit } if } forall { pop exch pop cvn } { pop pop } ifelse } { pop } ifelse } bind executeonly def % Find a font (except for embedded ones), and adjust its encoding if necessary. /.pdfdfndict mark /defaultfontname /Helvetica .dicttomark readonly def % This code attempts to use the FontName and FontDescriptor to find a % 'better' match for a missing font than the default font. There % are a list of fonts and mappings here (TTfonts) and in gs_font.ps % (.substitutefaces) which we can use to map from a requested font % family name to a substitute family. If that fails we check the % FontDescriptor Flags to attempt a (very slightly) better match. % We use Times-Roman for serif fonts and Helvetica for non-serif. % This all seems pretty poor to me, but its long-standing, so we % won't attempt to meddle with it. /pdfsubstitutefont { % Stack: font-res fontname fontdesc dup /Flags oget dup 16#40 and -6 bitshift % 1, oblique/italic 1 index 16#40000 and -17 bitshift add % 2, bold exch 16#2 and 2 bitshift add % 8, serif % We should look at the fixed flag, too. % Stack: font-res fontname fontdesc properties % Even though /FontName is a required key in FontDescriptor dict % (As of the PDF 1.4 Reference Manual), In the case of missing % /FontName key, we substitue /BaseFont for the value of /FontName. % Yet another case of broken PDF's that Adobe Reader accepts. 1 index dup /FontName known { /FontName oget dup type /nametype ne { ( **** Error: /FontName in FontDescriptor is not a name.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror cvn } if } { ( **** Error: FontDescriptor missing required /FontName key. BaseFont name used.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror pop 2 index % grab the BaseFont from the stack. } ifelse .remove_font_name_prefix exch % Analyzes font name and extract "Bold" and "Narrow" properties % which are not described by the FontDescriptor Flags. % We also allow the font name analysis to override the Flags setting % for Italic/Oblique as this gives us results more consistent with % Acrobat. 0 2 index //.fontnameproperties exec 7 and or % Rebind the default font name to Helvetica so that % fonts with no properties are handled correctly. //.pdfdfndict begin .substitutefontname end % Stack: font-res fontname fontdesc substname|null Fontmap 1 index known {//false} { .buildnativefontmap pop NativeFontmap 1 index known not} ifelse { % No available good substitution, use the standard one. pop 1 index .substitutefont } if dup 3 index ne { QUIET not { (Substituting font ) print dup =only ( for ) print 2 index =only (.) = flush } if % Send a warning to the device, in case its pdfwrite and we are in PDF/A mode % In that case the substituted font may not (probably doesn't) have glyphs which % match the /Widths of the original font, and that will cause a fault with PDF/A % so we need to let the device know. /SubstitutedFont /EventInfo .special_op } if pdffindcachedfont % Stack: font-res fontname fontdesc font % Some non-compliant files are missing FirstChar/LastChar, % despite referencing a non-base14 font 3 index /FirstChar knownoget { 0 % push an initial value for accumating the Widths 0 string % and an empty string to interrogate the font 7 index /Widths knownoget { 0 1 2 index length 1 sub { dup 2 index exch get dup type /packedarraytype eq {exec} if % Handle entries which are indirect references (seriously ? !!) dup 0 gt % We ignore entries of zero in the widths array { exch 5 index add % add FirstChar to the idx to get a char code dup 64 gt 1 index 91 lt and % we only want to consider A~Z and.... 1 index 96 gt 2 index 123 lt and or % ... a~z { exch 5 -1 roll add 4 1 roll % add the width to the accumulator on the stack 1 string dup 0 4 -1 roll put 3 -1 roll concatstrings exch % add the char code to the string } { pop pop } ifelse } { pop pop } ifelse } for pop % get rid of the Widths array 3 -1 roll pop % get rid of the FirstChar value dup length dup 0 gt { 3 -1 roll exch div % calculate an average width from the Widths array gsave 2 index 10 scalefont setfont exch dup length exch stringwidth grestore pop 100 mul exch div div % Only make the font smaller/narrower, not larger/wider dup 1.0 lt { 0 0 2 index 0 0 6 array astore exch //true .copyfontdict dup /FontMatrix get 3 -1 roll matrix concatmatrix exch dup 3 -1 roll /FontMatrix exch put % we don't need to definfont here, we can leave that to .completefont below } { pop } ifelse } { % no suitable Widths entries - carry on and hope for the best...... pop pop pop } ifelse } { % Broken file: no Widths array for non-base14 font - carry on and hope for the best...... ( **** Warning: Widths array missing in FontDescriptor for non-base14 font\n) pdfformatwarning pop pop pop } ifelse } { ( **** Warning: FirstChar value missing in FontDescriptor for non-base14 font\n) pdfformatwarning } ifelse % Stack: font-res fontname fontdesc font % If this is a small-caps font, replace the CharString % entries for a..z. exch /Flags oget 16#20000 and 0 ne { //true .copyfontdict dup /CharStrings 2 copy get dup length dict .copydict % stack: font-res fontname font font /CharStrings CharStringsdict 5 index /FirstChar get 97 .max 6 index /LastChar get 122 .min 1 exch { % Stack: font-res fontname font' font' /CharStrings charstrings code % Note that this only remaps a-z, not accented characters. 6 index /Widths oget 1 index 8 index /FirstChar get sub oget 1 string dup 0 5 -1 roll put % Stack: font-res font' font' /CharStrings charstrings code % width (x) 2 index exch dup cvn exch dup 0 2 copy get 32 sub put 4 -1 roll { % Stack: operand (X) width 0 setcharwidth exch pop currentfont /FontMatrix get matrix invertmatrix concat 0.7 dup scale 0 0 moveto show } /exec cvx 4 packedarray cvx put } for put } if dup /FontName get 2 index ne { //true .copyfontdict 2 copy exch /FontName exch put } if exch pop .completefont } bind executeonly def /pdffindfont { % pdffindfont % If the font isn't available, synthesize one based on % its descriptor. dup /Font resourcestatus { pop pop pdffindcachedfont } { 1 index /FontDescriptor knownoget { /SUBSTFONT where not { pdfsubstitutefont } { % User has defined SUBSTFONT, use the defined substitute font, do not % try to be clever pop % the dictionary containing SUBSTFONT pop % the FontDescriptor pdffindcachedfont }ifelse } { % No descriptor available, use the default algorithm. pdffindcachedfont } ifelse } ifelse exch pop } bind executeonly def % ---------------- Type 1 fonts ---------------- % /buildType1 % buildType1 { dup /BaseFont get pdffindfont } bind executeonly def % Read an embedded Type 1 font. /readfontfilter { % readfontfilter 0 () /SubFileDecode filter } bind executeonly def % Adobe Acrobat doesn't skip space characters after eexec /eexec_pdf_param_dict mark .eexec_param_dict {} forall /keep_spaces //true .dicttomark readonly def % When Type 1 font reading procedure is executing, a copy of this dictionary is current. % topFontDict allows us to *attempt* to handle the case where a Type 1 font definition % does not start by creating it's own dictionary (i.e. a number of the keys end up in % the currentdict rather than the font dictionary). % The whole type1 stream can be executed directly. There's no need to process % Length1, 2, 3 keys. /readtype1dict 10 dict dup begin /prev_definefont /definefont load def /definefont { % if a font defines any keys outside it's own dictionary, % this attempts to cope by copying them into the font dictionary [ /FontType % in PLRM order /FontMatrix /FontName /FontInfo /WMode /Encoding /FontBBox /UniqueID /XUID /PaintType /StrokeWidth /Metrics /Metrics2 /CDevProc /CharStrings /Private /WeightVector ] { 2 copy known {pop} { dup where { 1 index get 2 index 3 1 roll put dup /MisplacedKey 0 put } {pop} ifelse } ifelse } forall dup /MisplacedKey known { ( **** Warning: Type 1 font defines some required keys outside the font dictionary.\n) pdfformatwarning } if dup /CharStrings get /.notdef known not { dup /CharStrings get /.notdef <9E35CED7FFD3622F09> put ( **** Warning: Type 1 font has no /.notdef entry in /CharString dictionary.\n) pdfformatwarning } if dup /UniqueID .knownget { dup dup 0 lt exch 16#ffffff gt or { ( **** Warning: Ignoring invalid /UniqueID = ) exch =string cvs concatstrings (\n) concatstrings pdfformatwarning dup /UniqueID undef } { pop } ifelse } if prev_definefont } bind executeonly def /undef_proc_warning { /Repaired //true store % flag that we have warnings UndefProcList exch 2 copy .knownget { 1 add } { 1 } ifelse put } bind executeonly def /missing-type1-procs 6 dict begin /-| { string currentfile exch readstring pop /-| //undef_proc_warning exec } executeonly bdef /RD { string currentfile exch readstring pop /RD //undef_proc_warning exec } executeonly bdef /|- { noaccess def /|- //undef_proc_warning exec } executeonly bdef /ND { noaccess def /ND //undef_proc_warning exec } executeonly bdef /| { noaccess put /| //undef_proc_warning exec } executeonly bdef /NP { noaccess put /NP //undef_proc_warning exec } executeonly bdef currentdict end readonly def /eexec { % Assume the font dictionary is directly below the file on the stack count 0 gt { /topFontDict 2 index cvlit store } if //eexec_pdf_param_dict /eexecDecode filter //missing-type1-procs begin /userdict .systemvar begin //systemdict begin readtype1dictcopy begin cvx stopped currentfile flushfile % Skip the trailer after return from eexec, bug 690701. { currentdict end //missing-type1-procs eq { exit } if } loop { stop } if } bind executeonly def /readonly-op-dict << /stringtype 0 /arraytype 0 /packedarraytype 0 /dicttype 0 >> readonly def /readonly { % bug 689617 dup type //readonly-op-dict exch known not { ( **** Warning: Type 1 font applies operator readonly to an invalid object type.\n) pdfformatwarning } if } bind executeonly def /prev_get /get load def /get { dup /FontName eq { % No warning, probably FontName is defined elsewhere; see definefont above. .knownget not { /Missing } if } { dup /UniqueID eq { % We don't want fonts to check /UniqueID and do 'restore'. pop pop 16#FEDCBA98 % Arbitrary and invalid value } { prev_get } ifelse } ifelse } bind executeonly def /prev_begin /begin load def /begin { dup //systemdict eq { pop 0 dict } if prev_begin } bind executeonly def { /undef_proc_warning /missing-type1-procs /readonly-op-dict } { currentdict exch undef } forall % Bug703454.pdf contains a number of fonts with multiple definitions % of a given glyph name in the CharStrings dict - i.e. two entries % for /a - the first of which is "correct" the second is "wrong". % Normal Postscript behaviour replaces the first value with the second % for the given key/value pair. % To handle this, *only* for Type 1 fonts embedded in PDFs, we % have a special definition of "def" which won't overwrite existing % values in the CharStrings dict. /def { 3 index /CharStrings eq currentdict 3 index known and { pop pop } { systemdict /def get exec } ifelse } bind executeonly def end readonly def currentdict /eexec_pdf_param_dict .undef /readtype1 { % readtype1 PDFfile fileposition 3 1 roll % pos res stream dup /PFB known exch % pos res pfb? stream //true resolvestream % pos res pfb? file exch { //false /PFBDecode filter % pos res file' } if % Some buggy embedded fonts leave extra junk on the stack, % so we have to make a closure that records the stack depth % in a fail-safe way. This code also removes the mark when % the implied cleartomark is not executed, i.e. Length3 == 0. % Also restore dictstack depth. % //systemdict begin //readtype1dict dup length 5 add dict copy begin % pos res file' /file-position 4 -1 roll def % res file' /stack-count count 3 sub def 1 index /BaseFont oget /savedFontName exch def /topFontDict //null def /readtype1dictcopy currentdict def cvx stopped { currentdict /topFontDict known not { end } { exit } ifelse } loop { /topFontDict //null def } if PDFfile file-position setfileposition count stack-count sub { pop } repeat topFontDict end end } bind executeonly def % ---------------- Type 3 fonts ---------------- % /buildType3 { % buildType3 8 dict begin /FontType 3 def % If the font does not contain a Resources entry, then we use % the resources from our current context. Page 391 of the PDF % 1.6 spec says that the Resources dict is optional and if not % present then we should use the Resources for the page. % However we have a test file (687989) which uses a Type3 font % inside a form XObject and the desired Resources are in the % XObject dict and not in the Page dict. So we are going to % the parent object to find resources instead of only going to % the page dict when a font does not specify its required % resources. /Resources 1 index /Resources knownoget { oforce } { 0 dict } ifelse def /FontBBox 1 index /FontBBox get cvx def /FontMatrix 1 index /FontMatrix oget def /CharProcs 1 index /CharProcs oget def 1 index /Widths knownoget { /Widths exch def 1 index /FirstChar known 2 index /LastChar known and { /FirstChar 1 index /FirstChar oget def /LastChar 1 index /LastChar oget def } { ( **** Error: Requireed entry FirstChar or LastChar is missing from Font.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror /FirstChar 0 def /LastChar Widths length def }ifelse } if /FontName 1 index /Name knownoget not { /PDFType3Untitled } if def /Encoding .notdefEncoding 2 index getencoding def % We have to define BuildChar rather than BuildGlyph: % there is no PDF equivalent of glyphshow, and we need % the character code to access the Widths. /BuildChar { % Stack: font charcode 1 index begin 4 dict begin /Font 3 -1 roll def /CharCode 1 index def Encoding exch get CharProcs exch knownoget { dup /Length get 0 eq { pop %% Detect a 0 length stream. If this occurs %% then we won't execute d0 or d1, and so won't adjust the %% character width. So, pretend we got a %% null d1, just so that we can adjust using the /Widths %% (Bug 697805) 0 0 0 0 0 0 pdfopdict /d1 get exec }{ { dup //false resolvestream % Stack: filepos streamdict stream % Don't let setgcolor set the color inside the BuildGlyph % procedure, because this causes an /undefined error. q %% This is (currently) needed to make sure that the current dictionary, which is %% 'nodict' because we did a gsave, is writeable. If we don't execute gput %% to make a writeable copy then it is a no access dicitonary and the 'def' %% below will fail. It would be nice to fix the cases of this someday, but %% we use 'nodict'[ to store other PDF state stuff that isn't gstate, and we %% probably always will, so it may well be more trouble than its worth. /Dummy //false gput Font /Resources get % Stack: filepos streamdict stream resdict dup length 0 eq { 3 -1 roll /Resources knownoget { exch pop ( **** Warning: Type 3 font has resource dictionary in glyph stream.\n) pdfformatwarning } if } { 3 -1 roll pop } ifelse exch pdfopdict /BuildCharDictDepth countdictstack def .pdfruncontext countdictstack BuildCharDictDepth sub { //pdfdict /.Qqwarning_issued .knownget {not}{//true} ifelse { (\n **** Warning: Type 3 glyph has unbalanced q/Q operators \(too many q's\)\n Output may be incorrect.\n) pdfformatwarning //pdfdict /.Qqwarning_issued //true .forceput } executeonly if Q } executeonly repeat Q } executeonly PDFfile fileposition 2 .execn % Keep pdfcount valid. PDFfile exch setfileposition } executeonly ifelse } executeonly { % PDF Type 3 fonts don't use .notdef % d1 implementation adjusts the width as needed 0 0 0 0 0 0 pdfopdict /d1 get exec } ifelse end end } executeonly bdef dup currentdict Encoding .processToUnicode currentdict end .completefont exch pop } bind executeonly odef /.adjustcharwidth { % .adjustcharwidth % Enforce the metrics, in glyph space, to the values found in the PDF Font object % - force wy == 0 (assumed, and not stored in the PDF font) % Even though PDF1.3-1.7 specifications state that this must be 0, % Distiller sometimes creates Type3 fonts with non-zero wy. We set % it to 0 since this is apparently what Acrobat Reader 4 and 5 do. % PDF1.2 does not mention this restriction, it only says % "see setcharwidth/ setcachedevice in the PostScript Reference". % - get wx from the Widths array (do nothing if not present) pop 0 /Widths where { begin CharCode FirstChar ge CharCode LastChar le and { exch pop Widths CharCode FirstChar sub get exch } if end } if } bind executeonly def % ---------------- TrueType fonts ---------------- % /TTfonts mark /Arial /Helvetica /Arial,Italic /Helvetica-Oblique /Arial,Bold /Helvetica-Bold /Arial,BoldItalic /Helvetica-BoldOblique /CourierNew /Courier /CourierNew,Bold /Courier-Bold /TimesNewRoman /Times-Roman /TimesNewRoman,Italic /Times-Italic /TimesNewRoman,Bold /Times-Bold /TimesNewRoman,BoldItalic /Times-BoldItalic .dicttomark readonly def /buildTrueType { % buildTrueType dup /BaseFont oget dup /font_name gput 1 index /FontDescriptor knownoget { /Flags knownoget { 4 and 0 ne { //true } % symbolic { 1 index /Encoding oknown not} % no encoding => symbolic ifelse } {//false} ifelse } {//false} ifelse /is_symbolic gput 1 index /Encoding oknown { StandardEncoding 3 index getencoding } { //null } ifelse /prebuilt_encoding gput //false /.render_notdef gput % set the default dup /Font resourcestatus dup { exch pop exch pop } if not TTfonts 2 index known and { dup TTfonts exch get QUIET not { (Substituting font ) print dup =only ( for ) print 1 index =only (.) = flush } if exch 3 1 roll pdffindfont //true .copyfontdict 2 copy exch /FontName exch put exch pop .completefont } { pdffindfont } ifelse } bind executeonly def % Read an embedded TrueType font. /readtruetype { % readtruetype 1 index exch PDFfile fileposition 3 1 roll //true resolvestream readfontfilter % Stack: filepos fontres stream 1 index /CIDSystemInfo oknown { 1 index /CIDSystemInfo get dup type /packedarraytype eq {exec}if dup /Registry known not { ( **** Warning: a CIDFont's CIDSystemInfo is missing the required Registry entry\n) pdfformatwarning dup /Registry (Adobe) put } if dup /Ordering known not { ( **** Warning: a CIDFont's CIDSystemInfo is missing the required Ordering entry\n) pdfformatwarning dup /Ordering (Identity) put } if dup /Supplement known not { ( **** Warning: a CIDFont's CIDSystemInfo is missing the required Supplement entry\n) pdfformatwarning dup /Supplement 0 put } if 3 1 roll 1 index /Subtype knownoget { /CIDFontType2 ne { ( **** Error: Subtype of a TT CID font is not /CIDFontType2\n) pdfformaterror 1 index /Subtype /CIDFontType2 put ( Output may be incorrect.\n) pdfformaterror } if } { ( **** Error: Subtype of a TT CID font is missing.\n) pdfformaterror 1 index /Subtype /CIDFontType2 put ( Output may be incorrect.\n) pdfformaterror } ifelse 1 index /BaseFont get % Use the BaseFont name for the font. Otherwise we % would use the name table, or a manufactured name. .loadttcidfont % Stack: filepos fontres cidfont } { % filepos fontres stream 1 index /FontDescriptor oget /Flags oget dup % only believe the symbolic flag if the non-symbolic flag is not also set! 4 and 0 ne exch 32 and 0 eq and { //true % symbolic } { 1 index /Encoding oknown not % no encoding => symbolic } ifelse 2 index /Encoding oknown { StandardEncoding 3 index getencoding } { //null } ifelse dup 4 index exch % filepos fontres stream is_symbolic Encoding fontres Encoding /prebuilt_encoding exch put % filepos fontres stream is_symbolic Encoding 5 index /BaseFont get % Use the BaseFont name for the font. Otherwise we % would use the name table, or a manufactured name. .loadpdfttfont } ifelse exch pop PDFfile 3 -1 roll setfileposition % Ignore both the Encoding and the Widths. exch pop } bind executeonly def % ---------------- Type 0 fonts ---------------- % % Predefine the known CMaps, but only create them on demand. /knownCMaps mark /Identity-H { /Identity-H 0 makeIdentityCMap } /Identity-V { /Identity-V 1 makeIdentityCMap } .dicttomark def /makeIdentityCMap { % .makeIdentityCMap - .currentglobal //true .setglobal 3 1 roll /CIDInit /ProcSet findresource begin 12 dict begin begincmap /WMode exch def /CMapName exch def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering (Identity) def /Supplement 0 def end def %/CMapName (see above) /CMapVersion 1 def /CMapType 1 def %WMode (see above) % The PDF documentation says that these CMaps map CIDs % "1 to 65,536". This is a misprint for 0 to 65,535. 1 begincodespacerange % <0001> <00ff> <0100> <0000> endcodespacerange 1 begincidrange % <0001> <00ff> 1 <0100> 256 <0000> 0 endcidrange endcmap CMapName currentdict /CMap defineresource knownCMaps CMapName 2 index put end % CMap end % CIDInit ProcSet exch .setglobal } bind executeonly def /CMap_read_dict 3 dict begin /defineresource % defineresource { pop /.last_CMap_def 1 index store exch pop } bind executeonly def /CIDSystemInfo { ( **** Error: CMap has invalid syntax near CIDSystemInfo.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror /CIDSystemInfo } bind executeonly def % A work around a bug in Altona.Page_3.2002-09-27.pdf - a slash is missed. /CMapName { ( **** Error: CMap has no CMapName.\n\ See the comment to revision 6201 in gs/doc/ps2pdf.htm#Problems .\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror /CMap1 % arbitrary, PDF defineresource tolerates non-unique names } bind executeonly def % A work around incorrect ToUnicode CMap generated by GS before rev. 6201. currentdict end readonly def % Read an embedded stream that we *hope* is a PostScript CMap. According % to the spec, ths isn't legal, but 'Acrobat opens it'.... % /read_CMap { dup mark exch 0 (begincodespacerange) /SubFileDecode filter cvx exec cleartomark {currentdict dup /CMapType known not {end}{pop exit} ifelse} loop /CMapType 1 def mark exch % emulate 'begincodespacerange' 0 (endcmap) /SubFileDecode filter cvx /begincmap cvx exch 2 .execn endcmap currentdict end dup /CMapName get exch /CMap defineresource end } bind executeonly def % Read embedded CMap stream. % if the parameter is null, it indicates there is no WMode, and we % should not add one. % Following Acrobat we ignore everything outside % begincodespacerange .. endcmap. /read_CMap_stream { % read_CMap //CMap_read_dict begin /CIDInit /ProcSet findresource begin 12 dict begin /o.endmapvalue /.endmapvalue load def /.endmapvalue { dup 65535 gt { ( **** Warning: CMap: CID out of valid range (0-65535).\n) pdfformatwarning pop 65535 } if o.endmapvalue } bind def 4 2 roll dup //null eq { pop } { /WMode exch def } ifelse dup //null eq { pop } { /CIDSystemInfo exch def } ifelse /CMapType 1 def /.last_CMap_def currentdict def % establish binding % The stream may not be seekable, push a ReusableStream to make it seekable. /ReusableStreamDecode filter % Try to skip past the 'header' portion of the PDF file to the body % If the CMap doesn't have a begincodespacerange (eg it uses /UseCMap) % then this will leave us at EOF. dup 0 (begincodespacerange) /SubFileDecode filter flushfile % See if we have anything left in the file dup bytesavailable 0 eq { % We discarded all the file contents, so there was no begincodespacerange % Rewind the file to the beginning dup 0 setfileposition % And try again, this time only discarding to the 'begincmap' dup 0 (begincmap) /SubFileDecode filter flushfile } { % Everything worked as expected, because we have consumed the % begincodespacerange from the file, emulate it mark exch } ifelse 0 (endcmap) /SubFileDecode filter cvx /begincmap cvx exch 2 .execn currentdict /o.endmapvalue undef endcmap /.last_CMap_def load { currentdict end //CMap_read_dict eq { exit } if } loop dup /.last_CMap_def undef /CMap defineresource } bind executeonly def currentdict /CMap_read_dict undef /buildType0 { % buildType0 dup /BaseFont get % FontName 1 index /Encoding oget dup type /nametype eq { dup /CMap resourcestatus { pop pop /CMap findresource } { knownCMaps 1 index .knownget { exch pop exec } { /undefined signalerror } ifelse } ifelse } { %% Bug #696449 Acrobat will read an embedded PostScript %% CMap, whcih according to the spec is not valid, it needs %% to be a PDF CMap stream. Here we check and see if it looks like a CMap %% dictionary. If it is we proceed, if its some other kind of dictionary, %% throw an error, if its neither, treat it as a stream and hope for the best. dup /Type known { dup /Type get /CMap eq { PDFfile fileposition exch dup /CIDSystemInfo knownoget { << exch { oforce } forall >> } { //null } ifelse exch dup /WMode knownoget not {//null} if exch dup /CMapName knownoget not {/null} if exch //true resolvestream read_CMap_stream exch PDFfile exch setfileposition } { PDFSTOPONERROR { /buildType0 cvx /syntaxerror signalerror } if } ifelse }{ PDFfile fileposition exch //true resolvestream read_CMap exch PDFfile exch setfileposition } ifelse } ifelse % CMap [ 3 index /DescendantFonts oget { exec resourcefont } forall ] % subfonts .composefontdict % composefont must insert FontInfo dictionary - see gs_cmap.ps . % Stack: fontres name font 3 copy exch pop //null .processToUnicode exch pop .completefont % Stack: fontres font 1 index /FontMatrix knownoget { dup aload pop //true {0 0 1 0 0 1} {3 -1 roll eq and} forall { 1 index exch makefont exch /FontName get exch exch pop .completefont } { pop } ifelse } if exch pop } bind executeonly def % ---------------- CIDFontType0/2 fonts ---------------- % % Insert metrics into a CIDFont, by saving the PDF W, W2, DW, and DW2 % arrays and using a (currently very inefficient) CDevProc. % For detail, refer "PDF Reference" 2nd ed., p314 "5.6.3 CIDFonts". % It notes default DW is 0, but Acrobat Reader uses 1000 as default. % If DW is 0, currentpoint does not move by default in rendering text % horizontally, the result is unreadable. You can check it by Acrobat. /.pdfDefaultDW 1000 def /.pdfDefaultDW2 [ 880 -1000 ] def /addCIDmetrics { % addCIDmetrics dup length 5 add dict .copydict dup /FID undef dup /UniqueID undef dup /XUID undef % Insert the widths into the font. % Stack: pdfresource newfont 1 index /DW knownoget { 1 index /DW 3 -1 roll put } { dup /DW .pdfDefaultDW put } ifelse 1 index /W knownoget { //false 1 index { xcheck or } forall { oforce_array } if dup 2 index /W 3 -1 roll put .pdfMakeInternalW 1 index /.internalW 3 -1 roll put } if 1 index /DW2 knownoget { 1 index /DW2 3 -1 roll put } { dup /DW2 .pdfDefaultDW2 put } ifelse 1 index /W2 knownoget { //false 1 index { xcheck or } forall { oforce_array } if dup 2 index /W2 3 -1 roll put .pdfMakeInternalW2 1 index /.internalW2 3 -1 roll put } if dup /CDevProc 1 index /CIDWProc load /exec load 3 packedarray cvx put exch pop } bind executeonly def /.pdfMakeInternalMTXArray { % .pdfConvertInternalW % convert /W or /W2 to internal expression % % mtx_array: original /W or /W2 array % item_size: number of metrics values per CID % % for detail of the metrics list format in PDF, % refer PDF Ref. p.317 "Glyph Metrics in CIDFonts". % % format of single entry in internal expression % % [ % [cid_begin cid_end] % value_is_varied (bool) % [ [values for cid_begin...] % [values for cid_begin + 1] % ... ] % ] % 7 dict begin /itemSize exch def /M exch def % original /W or /W2 /Msize M length def /Mi { M i get } def % W[i] /Mi1 { M i 1 add get } def % W[i + 1] /putMTXEntry << /arraytype { [ [Mi Mi Mi1 length itemSize idiv add 1 sub] //true [ 0 itemSize Mi1 length 1 sub { [ exch 1 1 index itemSize add 1 sub { Mi1 exch get } for ] } for ] ] /i i 2 add def } /integertype { [ [Mi Mi1] //false [[ i 2 add 1 i 1 add itemSize add { M exch get } for ]] ] /i i 2 add itemSize add def } >> def /i 0 def [ { putMTXEntry Mi1 type get exec i Msize ge { exit } if } loop ] end } executeonly def /.pdfMakeInternalW { dup length 0 gt { oforce_recursive 1 .pdfMakeInternalMTXArray } if } executeonly def /.pdfMakeInternalW2 { dup length 0 gt { oforce_recursive 3 .pdfMakeInternalMTXArray } if } executeonly def /.pdfGetMTXByCID { % % .pdfGetMTXByCID % { true | false } % get values for given CID from internal format of /W or /W2 exch { { dup 0 get {} forall % Stack: 3 index lt { pop pop //false exit } if 2 index exch sub dup 0 lt { pop pop //false exit } if 1 index 1 get not { pop 0 } if exch 2 get exch get //true exit } loop { exit } if } forall dup type /arraytype eq { exch pop //true } { pop //false } ifelse } executeonly def % Apply the [D]W[2] metrics to a character before displaying. /CIDWProc { % % CIDWproc % ... begin % push to currentdict % won't be used and replaced, discard now 5 1 roll pop pop pop pop % get FontMatrix that applies to this CID % (needs to convert [D]W[2] values to glyph space) currentdict /FontMatrix get % if the currentfont is a CIDFontType 0 CIDFont, % we need FDArray font's FontMatrix too FontType 9 eq { currentdict 2 index .type9mapcid % (charstring) exch pop currentdict /FDArray get exch get /FontMatrix get % matrix concatmatrix } if % preserve this FontMatrix at bottom of the stack 8 1 roll % Stack: { currentdict /DW .knownget not { % no DW .pdfDefaultDW exit % replace by defaultDW } if currentdict /.internalW .knownget not { % no W exit % use already-stacked DW } if dup length 0 eq { % W is null array pop % discard unusable W exit % use already-stacked DW } if % W is finite array, try to get W_cid 2 index .pdfGetMTXByCID { % got W, discard DW exch pop {} forall exit } if exit } loop 0 % % Stack: 9 -2 roll pop pop % discard 7 2 roll % put % Stack: 0 % exch % put % Stack: { currentdict /DW2 .knownget not { % no DW2, use defaultDW2 .pdfDefaultDW2 exit } if currentdict /.internalW2 .knownget not { % has DW2, no W2 exit % use already-stacked DW2 } if dup length 0 eq { % W2 is null array pop % discard unusable W2 exit % use already-stacked DW2 } if 2 index .pdfGetMTXByCID { % got W2_cid, discard DW2 exch pop exit } if % could not get W2_cid exit } loop exch pop % discard % Stack: % { [ ] | [ ] } dup length 2 eq { % this is DW2 aload pop exch 8 index 2 div % = / 2 exch } { % assume W2 aload pop } ifelse % Stack: % now, convert each metrics valude (1000th of text space) to glyph space 10 -2 roll % Stack: 3 { 10 index idtransform exch 1000 div exch 1000 div 6 2 roll } repeat 10 2 roll % Stack: 11 -1 roll pop % Stack: end % recover currentdict } bind executeonly def % tailmatch ==>
 true
%                            ==>  false
/tailmatch {
  2 copy length 1 index length .min
  dup 2 index length exch sub exch getinterval
  1 index eq {
    length 1 index length exch sub
    0 exch getinterval //true
  } {
    pop //false
  } ifelse
} bind executeonly def

/makeboldfont {
  16 dict begin
    /strokewidth exch def
    /basecidfont exch def
    /FontMatrix [ 1 0 0 1 0 0 ] def

    /CIDFontName /.boldfont def
    /CIDFontType 1 def

    /basefont-H /.basefont-H /Identity-H [ basecidfont ] composefont def
    /basefont-V /.basefont-V /Identity-V [ basecidfont ] composefont def

    /CIDSystemInfo dup basecidfont exch get def
    /FontBBox [ basecidfont /FontBBox get cvx exec
      4 2 roll basecidfont /FontMatrix get transform
      4 2 roll basecidfont /FontMatrix get transform
    ] def

    /tmpstr 2 string def
    /BuildGlyph {
      gsave
      exch begin
        dup 256 idiv tmpstr exch 0 exch put
        256 mod tmpstr exch 1 exch put
        rootfont /WMode known { rootfont /WMode get 1 eq } { //false } ifelse
        { basefont-V } { basefont-H } ifelse setfont
        strokewidth setlinewidth
        1 setlinejoin
        newpath
        0 0 moveto tmpstr //false charpath stroke
        0 0 moveto tmpstr show
        currentpoint setcharwidth
      end
      grestore
    } bind def

   currentdict
  end
  dup /CIDFontName get exch /CIDFont defineresource
} bind executeonly def

%   findCIDFont  
%   CIDFont-resource is not modified.
% In various places we do:
% "findCIDFont dup /OrigFont .knownget {exch pop} if"
% because the CIDFont we find may have been "patched" to apply metrics from
% the PDF file (W, W2, etc). We want to avoid applying those metrics more
% than once, hence retrieving the original, unpatched CIDFont dictionary,
% if it exists.
/findCIDFont {
  {
    dup /CIDFont resourcestatus {
      pop pop dup /CIDFont findresource
      dup /Path known
      1 index /ResourcePath known or
      { exch pop exit }
      { pop dup /CIDFont undefineresource }
      ifelse
    } if
    .remove_font_name_prefix
    dup dup length string cvs

    (,Bold) tailmatch {
      exch pop
      % If we're substituting a standard weight font for a
      % "Light,Bold" font, don't artificially bolden further
      dup (Light) tailmatch
      {
        pop cvn findCIDFont
        dup /OrigFont .knownget {exch pop} if
        dup /FontName .knownget
        {
          (Light) tailmatch exch pop
        }
        {
          //true
        } ifelse

        {
          0.03 makeboldfont
        } if
      }
      {
        pop
        cvn findCIDFont
        dup /OrigFont .knownget {exch pop} if
        0.03 makeboldfont
      } ifelse
      exit
    } if
    (,Italic) tailmatch {
      exch pop
      cvn findCIDFont
      dup /OrigFont .knownget {exch pop} if
      [ 1 0 0.3 1 0 0 ] makefont
      exit
    } if
    (,BoldItalic) tailmatch {
      exch pop
      % see above
      dup (Light) tailmatch
      {
        pop cvn findCIDFont
        dup /OrigFont .knownget {exch pop} if
        dup /FontName .knownget
        {
          (Light) tailmatch exch pop
        }
        {
          //true
        } ifelse

        {
          0.03 makeboldfont
        } if
      }
      {
        pop
        cvn findCIDFont
        dup /OrigFont .knownget {exch pop} if
        0.03 makeboldfont
      } ifelse
      [ 1 0 0.3 1 0 0 ] makefont
      exit
    } if
    QUIET not {
      (Can't find CID font ") print dup =string cvs print (".) = flush
    } if
    pop

    1 index /CIDSystemInfo oget begin Registry (-) Ordering end
    concatstrings concatstrings
    cvn
    QUIET not {
      (Attempting to substitute CID font ) print dup ==only
      ( for ) print 1 index ==only (, see doc/Use.htm#CIDFontSubstitution.) = flush
    } if
    exch pop
    dup /CIDFont resourcestatus {
      pop pop /CIDFont { findresource } stopped
      {pop}{exit} ifelse
    } if
    QUIET not {
      (The substitute CID font ") print dup =string cvs print
      (" is not provided either. ) print
    } if

    PDFNOCIDFALLBACK {
      PDFSTOPONERROR {
        (Will exit with error.) = flush
      }
      {
        (Will attempt to continue, but content may be missing.) = flush
      } ifelse
      exit
    } if

    QUIET not {
      (attempting to use fallback CIDFont.) print
      (See doc/Use.htm#CIDFontSubstitution.) = flush
    } if

    PDFNOCIDFALLBACK not {
      % This previously worked by loading the substitute font, and using that
      % as a "template" to create a new CIDFont dictionary with the CIDSystemInfo
      % dict appropriate for the requested font.
      % This, however, caused problems with the CIDMap and thus broke pdfwrite.
      % Hence, we now modify the CIDFont resource .map dictionary on the fly
      % so it includes an appropriate mapping, so the subsitute font is loaded
      % from the beginning with the correct ordering and supplement settings.
      /CIDFont /Category findresource /.map get dup /CIDFallBack .knownget {
        dup type /dicttype eq {
          dup /FileType get /TrueType eq {
            currentglobal
            4 1 roll
            dup gcheck setglobal
            dup length dict copy dup
            6 index /CIDSystemInfo oget dup /Ordering oget exch /Supplement get
            % we have to copy the string, for VM correctness
            exch dup length string copy exch 2 array astore
            /CSI exch put 2 index exch .forceput
            exch setglobal
            {
              % This *should* not execute arbitrary Postscript, so we ought to
              % be safe running in a stopped context, in knowledge we know how
              % to clean up afterwards - this would not be safe if CIDFallBack
              % were a "real" CIDFont.
              /CIDFont findresource
            }
            % if the above fails, try just using the CIDFallBack font directly
            stopped
            {
              pop
              % First, since it didn't work, remove the entry from the CIDFont category
              % .map dictionary.
              currentglobal exch
              /CIDFont /Category findresource /.map get
              dup gcheck setglobal
              exch undef
              setglobal

              (Warning: falling back to Identity ordering\n) print flush
              /CIDFallBack /CIDFont findresource
            } if
            exit
          } executeonly if
        } if
      } if

      pop pop pop
      /CIDFallBack

      QUIET not {
        (The fallback CID font ") print dup =string cvs print
        (" is not provided. ) print
        ( Finally attempting to use ArtifexBullet.\n) print flush
      }if

      % We'll just use Identity for this, we have only one glyph anyway.
      /ArtifexBullet /CIDFont resourcestatus {
        pop pop pop
        /ArtifexBullet /CIDFont findresource
        exit
      }
      {
        pop /ArtifexBullet
      } ifelse

      QUIET not {
        (The CID font ") print dup =string cvs print
        (" is not provided. ) print
        PDFSTOPONERROR
        {
          (Will exit with error.) = flush
        }
        {
          (Will continue, but content may be missing.) = flush
        } ifelse
      } if
    } executeonly if
    /findresource cvx /undefined signalerror
  } executeonly loop
} bind executeonly odef

/buildCIDType0 {	%  buildCIDType0 
  dup /BaseFont get findCIDFont exch pop
} bind executeonly def

/buildCIDType2 {	%  buildCIDType2 
  dup /BaseFont get findCIDFont exch pop
} bind executeonly def

/processCIDToGIDMap { %   processCIDToGIDMap  
  1 index /CIDToGIDMap knownoget {
    PDFfile fileposition 4 1 roll
    dup /Identity eq {
      pop
    } {
      //true resolvestream
                % Stack: filepos fontres font mapstream
      [
      { counttomark 1 add index 32768 string readstring not {
          counttomark 1 eq {
            exch pop dup length
          } {
            ] dup 0 exch { length add } forall
          } ifelse
          exit
        } if
      } loop
      2 idiv
        % Stack: filepos fontres font mapstream array/string CIDCount
      dup 0 ne {
        3 index exch /CIDCount exch put
        exch closefile exch
        dup /CIDMap 4 -1 roll put
      }{
        % If CIDCount is zero, ignore it
        pop pop closefile
      }ifelse
    } ifelse
    3 2 roll PDFfile exch setfileposition
  } if
} bind executeonly def

% Adjust a CIDFontType0 DW[2] in the font resource.
/adjustCIDType0 {		%   adjustfont 
  dup /FontType get 1 eq {
    (   **** Error: Font resource has a wrong /Subtype.\n)  pdfformaterror
    (               Output may be incorrect.\n) pdfformaterror
    adjustfont
  } {
    addCIDmetrics
    dup /CIDFontName get exch /CIDFont defineresource
  } ifelse
} bind executeonly def

% Adjust a CIDFontType2 DW[2] and CIDToGIDMap in the font resource.
/adjustCIDType2 {		%   adjustfont 
  dup /FontType get 1 eq {
    (   **** Error: Font resource has a wrong /Subtype.\n)  pdfformaterror
    (               Output may be incorrect.\n) pdfformaterror
    adjustfont
  } {
    addCIDmetrics
    dup /CIDFontType get 2 eq {   % OpenType CFF font converts to CIDFontType 0
      processCIDToGIDMap          %  that ignores CIDMap.
    } if
    dup /CIDFontName get exch /CIDFont defineresource
  } ifelse
} bind executeonly def

% ---------------- Other embedded fonts ---------------- %

% Read an embedded compressed font.
/readType1C {		%   readType1C 
  1 index exch
  PDFfile fileposition 3 1 roll
  dup //true resolvestream dup readfontfilter
                % Stack: pos resource streamdict stream filter
  3 index /FontDescriptor oget /FontName oget
  1 index
  /FontSetInit /ProcSet findresource begin //true //false ReadData
  %% We need to be careful not to corrupt the stack if something went wrong.
  %% Previously, if the dict was length 0 (an error occured) we would end up
  %% unable to recover the stack in the calling procedure.
  %% Bug #695819.
  dup length 0 ne {
    { exch pop exit } forall
    7 1 roll
  }{
    /invalidfont signalerror
  } ifelse
  closefile closefile pop
  PDFfile 3 -1 roll setfileposition
  pop pop
} bind executeonly def

% Read an embedded CFF CIDFont.
/readCIDFontType0C {  %   readCIDFontType0C 
  PDFfile fileposition 3 1 roll
  dup //true resolvestream dup readfontfilter
                % Stack: pos resource streamdict stream filter
  3 index /FontDescriptor oget /FontName oget
  1 index
  /FontSetInit /ProcSet findresource begin //true //true ReadData pop
  closefile closefile pop
  PDFfile 3 -1 roll setfileposition
                % Some broken Adobe software produces PDF files in which
                % the FontName of the CFF font and the FontName in the
                % FontDescriptor don't match the BaseFont in the font.
                % Use the FontName, rather than the BaseFont, here.
  dup /FontDescriptor oget /FontName oget /CIDFont findresource
  addCIDmetrics dup /CIDFontName get exch /CIDFont defineresource
} bind executeonly def

% Read an embedded OpenType font.
/readOTTOfont {		%   readOTTOfont 
  1 index exch                    % res res strdict
  PDFfile fileposition 3 1 roll   % res pos res strdict
  dup //true resolvestream        % res pos res strdict stream
  dup readfontfilter              % res pos res strdict stream filter
  3 index /FontDescriptor oget
  /FontName oget                  % res pos res strdict stream filter /name
  1 index .init_otto_font_file    % res pos res strdict stream filter /name filter'
  //true
  6 index /CIDSystemInfo known    % res pos res strdict stream filter /name filter' bool bool
  ReadData                        % res pos res strdict stream filter fontset
  { exch pop exit } forall        % res pos res strdict stream filter font
  dup /FontType get 9 eq  {
    % OpenType may contain simple CFF font, which is accesed as a CIDFont by PDF.
    % The font is converted to Type 9 CIDFont resource, which ignores CIDMap attribute.
    % The following code just shuffles GlyphDirectory to the same effect.
    4 index /CIDToGIDMap knownoget {
      dup type /dicttype eq {
        1 index /GlyphDirectory get exch       % res pos res strdict stream filter font dir c2g
        //true resolvestream                   % res pos res strdict stream filter font dir c2g_file
        256 dict begin
        0 2 index 0 get def  % copy .notdef
        0 1 16#7fffffff {
          1 index read not { pop exit } if     % res pos res strdict stream filter font dir c2g_file cid hi
          256 mul                              % res pos res strdict stream filter font dir c2g_file cid hi
          2 index read not { pop pop exit } if % res pos res strdict stream filter font dir c2g_file cid hi lo
          add                                  % res pos res strdict stream filter font dir c2g_file cid gid
          dup 0 ne {
            dup 4 index length lt {
              3 index exch get                 % res pos res strdict stream filter font dir c2g_file cid charstr
              def                              % res pos res strdict stream filter font dir c2g_file
            } {
              pop pop
            } ifelse
          } {
            pop pop
          } ifelse
        } for
        closefile pop                          % res pos res strdict stream filter font
        dup length dict copy                   % res pos res strdict stream filter font'
        dup /GlyphDirectory currentdict put    % res pos res strdict stream filter font'
        end
        dup /GlyphDirectory get 0 exch {
          pop .max
        } forall
        1 index exch /CIDCount exch 1 add put
      } {
      pop
      } ifelse
    } if
  } if
  7 1 roll                        % font res pos res strdict stream filter
  closefile closefile pop pop     % font res pos
  PDFfile exch setfileposition    % font res
  pop                             % font
} bind executeonly def

% ---------------- Font lookup ---------------- %

% Some PDF files mis-identify font type of the embedded font streams or
% include raw PFB font streams. Length1, Length2, Length3 may be wrong or
% missing. Adobe Acrobat corrects these errors transparently to the user.
%
% We ignore the font type keys and recognize the font type by the 1st 4 bytes
% of the font stream. The PFB stream is recognized by the 1st 2 bytes.

/fonttypeprocs mark		%  -proc- 
  /Type0 //buildType0
  /Type1 //buildType1
  /MMType1 //buildType1
  /Type3 /buildType3 load
  /TrueType //buildTrueType
  /CIDFontType0 //buildCIDType0
  /CIDFontType2 //buildCIDType2
.dicttomark readonly def

/adjustfonttypes mark
  /Type1 //adjustfont
  /MMType1 //adjustfont
  /TrueType //adjustfont
  /CIDFontType0 //adjustCIDType0
  /CIDFontType2 //adjustCIDType2
.dicttomark readonly def

% Bind a proc and define n names
% /name ... /name {proc} n bndef -
/bndef
  { exch bind executeonly exch
    { dup 3 1 roll def } repeat
    pop
  } bind executeonly def

%  run-fonttypeproc 
/run-fonttypeproc {
  dup /Subtype knownoget not { 0 } if % res /subtype
  //fonttypeprocs 1 index known not {
    (   **** Error: Font /Subtype attribute is wrong or missing, /Type1 assumed.\n)
    pdfformaterror
    (               Output may be incorrect.\n) pdfformaterror
    pop /Type1
    2 copy /Subtype exch put
  } if
  //fonttypeprocs exch get exec
} bind executeonly def

% Prototype for all procedures:    foo 
/font_tag_dict 13 dict begin

  % When the font stream is absent or cannot be read we load the font by the name.
  /no_stream
    { pop pop
      run-fonttypeproc
    } bind executeonly def

  /bad_stream
    { (   **** Error: Error reading font stream, attempting to load the font using its name\n)
      pdfformaterror
      (               Output may be incorrect.\n) pdfformaterror
      //no_stream exec
    } bind executeonly def

  <8001>          % PFB
    { dup /PFB //true put
      exch pop readtype1
    } bind executeonly def

  (%!PS) (%!Fo)   % Type1
    { exch pop readtype1
    } 2 bndef

  <01000401> % Type 1C
    {
      exch pop

      1 index /Subtype knownoget {
        dup /CIDFontType2 eq{
          pop
          (   **** Error: Subtype of a Type 1 CID font is not /CIDFontType0\n) pdfformaterror
          (               Output may be incorrect.\n) pdfformaterror
          1 index /Subtype /CIDFontType0 put
          readCIDFontType0C
        }
        {
          /CIDFontType0 eq {
            readCIDFontType0C
          }
          {
            readType1C
          } ifelse
        } ifelse
      } {
        readType1C
      } ifelse
    } bind executeonly def

  <00010000> (true) (typ1) (ttcf)  % TrueType OpenType
    { exch pop readtruetype
    } 4 bndef

  (OTTO)
    { exch pop
      readOTTOfont
    } bind executeonly def

currentdict end readonly def
currentdict /bndef undef

% Used to create a hash for the XUID, ths combines the input PDF file name and the
% object number (currently the object number of the FontDescriptor). NB we *must*
% use an object number, as otherwise all fonts will have the same
% XUID and Ghostscript will think they are the same font. Ths routine must not
% be used unless we have an object number which is believed to be uniqe to
% a particular font instance.
/.CRCHashFilenameAndObject % object_number (filename) CRCHasFilename integer
{
    dup                     % object_number (filename) (filename)
    length                  % object_number (filename) length
    0 exch                  % object_number (filename) hash length
    1 sub                   % object_number (filename) hash length-1
    0 1 3 -1 roll           % object_number (filename) hash 0 1 length-1
    {                       % object_number (filename) hash index
      2 index exch get      % object_number (filename) hash char
      exch                  % object_number (filename) char hash
      dup 16#F8000000 and   % object_number (filename) char hash top5bits
      -27 bitshift          % object_number (filename) char hash top5>>27
      exch 5 bitshift       % object_number (filename) char top5>>27 hash<<5
      16#7FFFFFFF and
      xor                   % object_number (filename) char CRC
      xor                   % object_number (filename) newhash
    } for
    exch pop              % object_number newhash
    dup 16#F8000000 and   % object_number newhash top5bits
    -27 bitshift          % object_number newhash top5>>27
    exch 5 bitshift       % object_number top5>>27 newhash<<5
    16#7FFFFFFF and
    xor                   % object_number CRC
    xor                   % final hashed value
}bind executeonly def

% Either patch or create a new XUID based on the existing
% XUID or UniqueID and incorporating the PDF object number
% so we get an XUID we can use to improve cache efficiency
% in multipage documents.
/patch_font_XUID     %   patch_font_XUID 
{
  dup //null eq
  {pop}
  {
    //pdfdict /InputPDFFileName .knownget {.CRCHashFilenameAndObject} if
    exch dup /.OrigUniqueIDXUID .knownget not
    {
      dup /XUID .knownget not
      {
        dup /UniqueID .knownget
        {1 array astore}{ [] } ifelse
      } if
    } if

    dup //null eq
    {
          pop exch pop
    }
    {
      [ 1000000 3 -1 roll 4 index exch {exch} forall ]
      exch //true .copyfontdict
      dup 3 -1 roll /XUID exch put
      exch pop
      .completefont
    } ifelse
  } ifelse
} bind executeonly def

/resourcefont                   %  resourcefont 
{
  dup /PSFont .knownget dup {
    pop /FID knownoget dup { pop type /fonttype eq } if
  } if {
    /PSFont get
  } {

    dup /Subtype get /Type0 eq {
      % if the font was defined in-line, we won't have a object number
      dup /.gs.pdfobj# .knownget not { //null } if
    } {
          % if the font was defined in-line, we won't have a object number
      dup /.gs.pdfobj# .knownget not { //null }if
      dup //null eq not {
         1 index /FontDescriptor knownoget {
           dup /FontFile knownoget not {
           dup /FontFile2 knownoget not {
              dup /FontFile3 knownoget not {
                pop pop //null
              } {pop pop}ifelse
            } {pop pop}ifelse
           }{pop pop}ifelse
         }
         {
           pop //null
         } ifelse
      }if
    } ifelse
    3 1 roll

    % In the event we have a Type 0 dictionary with a spurious
    % FontDescriptor object, remove it here to prevent confusion
    % later on.
    % Bug 691589
    dup /Subtype get /Type0 eq 1 index /FontDescriptor known and
    {
        dup /FontDescriptor undef
    }if
    dup /CIDSystemInfo .knownget
    {
      oforce_recursive
      1 index exch /CIDSystemInfo exch put
    } if

    dup dup /FontDescriptor knownoget {
                                          % font-res font-res font-desc
      % The same font descriptor can be reused in a CID and non-CID contexts.
      % Store CID and non-CID fonts under different keys. Bug 689301
      1 index /Subtype knownoget dup {
        pop dup /CIDFontType0 eq exch /CIDFontType2 eq or
      } if { /CIDFontObject } { /FontObject } ifelse
                                          % font-res font-res font-desc /key
      2 index 1 index .knownget {
        4 1 roll pop pop pop              % font-res obj
      } {
        4 1 roll                          % /key font-res font-res font-desc

        dup /FontFile knownoget not {
          dup /FontFile2 knownoget not {
            dup /FontFile3 knownoget not {
              //null
            } if
          } if
        } if
                                          % /key res res desc stream
        dup //null ne {
          PDFfile fileposition
          mark {
            2 index //true resolvestream dup
            4 string readstring pop
            exch closefile
          } stopped {
            cleartomark /bad_stream
          } {
            exch pop
          } ifelse
          PDFfile 3 -1 roll setfileposition
          dup length 4 lt { pop /bad_stream } if
        } {
          /no_stream
        } ifelse
                                          % /key res res desc stream tag

        //font_tag_dict 1 index known not {
          %
          % The tag is the first 4 (?) bytes frm the font stream, if we get here then
          % it didn't match any of the keys in the dictionary. There seems to be
          % a possibility that a PFB font could be undetected (because its only 2 bytes?)
          % but the main problem is CFF fonts. These lack a magic number, and the header
          % can vary in the last 3 of the 4 bytes. We've now found 7 different possible
          % values for these bytes, adding more seems pointless and isn't future proof.
          % Instead check the dictionary for its Subtype.
          %
          dup 0 2 getinterval <8001> eq {
            0 2 getinterval               % /key res res desc stream pfb_tag
          } {
            1 index /Subtype known {
              1 index /Subtype get
                dup /Type1C eq 1 index /CIDFontType0C eq or exch /CIDFontType1C eq or {
                pop <01000401>            % discard the data we read and pretend we read the original Type1C tag
                //false
              }{
                //true
              }ifelse
            } {
              //true                      % no /Subtype, give up.
            }ifelse

            {
              (12345678>\n) dup /ASCIIHexEncode filter dup 4 -1 roll writestring closefile
              (   **** Error: unrecognized font file starts with <) exch concatstrings
              pdfformaterror
              (               Output may be incorrect.\n) pdfformaterror
              /no_stream                    % /key res res desc stream unknown_tag
            }if
          } ifelse
        } if
        //font_tag_dict exch get          % /key res res desc stream {proc}
        { stopped } 0 get                 % /key res res desc stream {proc} --stopped--
        count                             % /key res res desc stream {proc} --stopped-- #
        countdictstack                    % /key res res desc stream {proc} --stopped-- # ##
        PDFfile fileposition              % /key res res desc stream {proc} --stopped-- # ## ###
        5 array astore cvx                % /key res res desc stream {{proc} --stopped-- # ## ###}
        exec
        4 -1 roll {
          PDFSTOPONERROR not {
            PDFfile exch setfileposition
            countdictstack exch sub 0 .max { end } repeat
            count 4 add exch sub 0 .max { pop } repeat
            //null
          } {
            /resourcefont cvx /undefinederror signalerror
          } ifelse
        } {
          PDFfile exch setfileposition
          countdictstack exch sub 0 .max { end } repeat
          count 3 sub exch sub 0 .max { pop } repeat
        } ifelse
        dup //null eq {
          PDFSTOPONERROR not {
            pop
            (   **** Error: can't process embedded font stream,\n        attempting to load the font using its name.\n)
            pdfformaterror
            (               Output may be incorrect.\n) pdfformaterror
            dup run-fonttypeproc            % /key res font
          } {
            /resourcefont cvx /undefinederror signalerror
          } ifelse
        } if
        1 index                           % /key res font res
        4 -1 roll 2 index                 % res font desc /key font
        put  % Save pointer to the font.
      } ifelse
    } {
      run-fonttypeproc
    } ifelse
        % Stack: font-res font
    1 index exch
    1 index /Subtype get
    //adjustfonttypes exch .knownget { exec } { exch pop } ifelse
    4 -1 roll patch_font_XUID
    dup 3 1 roll /PSFont exch put
  } ifelse
  dup checkGlyphNames2Unicode
} bind executeonly def

currentdict /font_tag_dict .undef
currentdict /fonttypeprocs .undef
currentdict /adjustfonttypes .undef

drawopdict begin
  /d0 {
    currentcolor currentcolorspace .swapcolors setcolorspace setcolor .swapcolors
    .adjustcharwidth setcharwidth
  } bind executeonly def
  /d1 {
    2 copy                           % ... llx lly urx ury | urx ury
    0 ne exch 0 ne                   % ... llx lly urx ury | ury!=0 urx!=0
    3 index 6 index eq and           % ... llx lly urx ury | ury!=0 (urx!=0 && llx==urx)
    exch 2 index 5 index eq and or { % ... llx lly urx ury | (urx!=0 && llx==urx) || (ury!=0 && lly==ury)
      % The bounding box is empty and likely incorrect. Don't cache.
      pop pop pop pop
      //d0 exec
    } {
      currentcolor currentcolorspace .swapcolors setcolorspace setcolor .swapcolors
      6 -2 roll .adjustcharwidth 6 2 roll setcachedevice
    } ifelse
  } bind executeonly def
  /Tf {
    1 index Page /Font rget {
      dup type /dicttype eq {
        resourcefont exch
        Tf pop
      }
      {
        PDFSTOPONERROR
        {
          /typecheck signalerror
        }
        {
          % Bug 689450
          type
          (   **** Error: Tf refers to a resource key with an invalid value type: ) pdfformaterror
          .namestring pdfformaterror
          (. Assuming resource key: ) pdfformaterror
          1 index .namestring pdfformaterror
          ( is a font name.\n) pdfformaterror
          (               Output may be incorrect.\n) pdfformaterror
         Tf
        } ifelse
      }ifelse
    }
    {
      PDFSTOPONERROR
      {
          pop /undefined signalerror
      }
      {
        % Bug 689037
        (   **** Error: Tf refers to an unknown resource name: ) pdfformaterror
        1 index .namestring pdfformaterror
        ( Assuming it's a font name.\n) pdfformaterror
        (               Output may be incorrect.\n) pdfformaterror
        Tf
      } ifelse
    } ifelse
  } bind executeonly def
end

end			% pdfdict
end			% GS_PDF_ProcSet
.setglobal