diff options
Diffstat (limited to 'Resource')
-rw-r--r-- | Resource/Init/gs_cidfm.ps | 11 | ||||
-rw-r--r-- | Resource/Init/gs_fonts.ps | 21 | ||||
-rw-r--r-- | Resource/Init/gs_init.ps | 47 | ||||
-rw-r--r-- | Resource/Init/gs_lev2.ps | 2 | ||||
-rw-r--r-- | Resource/Init/gs_pdfwr.ps | 2 | ||||
-rw-r--r-- | Resource/Init/gs_res.ps | 2 | ||||
-rw-r--r-- | Resource/Init/gs_ttf.ps | 8 | ||||
-rw-r--r-- | Resource/Init/pdf_base.ps | 138 | ||||
-rw-r--r-- | Resource/Init/pdf_draw.ps | 855 | ||||
-rw-r--r-- | Resource/Init/pdf_font.ps | 387 | ||||
-rw-r--r-- | Resource/Init/pdf_main.ps | 178 | ||||
-rw-r--r-- | Resource/Init/pdf_ops.ps | 204 |
12 files changed, 1252 insertions, 603 deletions
diff --git a/Resource/Init/gs_cidfm.ps b/Resource/Init/gs_cidfm.ps index 5eb25f00..e123bfc1 100644 --- a/Resource/Init/gs_cidfm.ps +++ b/Resource/Init/gs_cidfm.ps @@ -120,7 +120,12 @@ currentdict end def (DroidSansFallback.ttf) } if } if - concatstrings + % If CIDFSubstFont looks like a path/file (rather than just file) + % use it without the CIDFSubstPath string + dup .file_name_directory_separator rsearch + {pop pop pop exch pop} + {pop concatstrings} + ifelse % The CSI data just has to be valid, the substition machinery will % generally overwrite it with appropriate values for the missing font. /CSI [(Identity) 0] @@ -136,7 +141,7 @@ currentdict end def % <dir.../base.extn> .basename <dir> /.splitdirname { (/) rsearch { //true } { (\\) rsearch } ifelse - {3 -2 roll pop pop //true}{//false} ifelse + {exch concatstrings exch pop //true}{//false} ifelse } bind def % <file> .addcidfmappath - @@ -209,7 +214,7 @@ currentdict end def } loop } forall currentdict end - {exch pop (/) concatstrings /PermitFileReading exch .addcontrolpath} forall + {exch pop /PermitFileReading exch .addcontrolpath} forall % Checks for vicious substitution cycles. dup length dict copy % <<map>> diff --git a/Resource/Init/gs_fonts.ps b/Resource/Init/gs_fonts.ps index 8e361552..204e2832 100644 --- a/Resource/Init/gs_fonts.ps +++ b/Resource/Init/gs_fonts.ps @@ -69,7 +69,7 @@ end def % <dir.../base.extn> .basename <dir> /.splitdirname { (/) rsearch { //true } { (\\) rsearch } ifelse - {3 -2 roll pop pop //true}{//false} ifelse + {exch concatstrings exch pop //true}{//false} ifelse } bind def % <dict> .addfontmappermitpaths @@ -1056,6 +1056,25 @@ $error /SubstituteFont { } put //false }ifelse + % If just opening the file didn't work, try opening the file name + % in the font resource directory + { + dup + //.fonttempstring /FontResourceDir getsystemparam .genericrfn + (r) { file } stopped { + pop pop //true + } { + dup .filename + { 3 -1 roll pop exch } + { pop } + ifelse + //false + } ifelse + } + { + //false + }ifelse + { QUIET not { (Can't find \(or can't open\) font file ) print dup print diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps index 722b57c1..05d01c21 100644 --- a/Resource/Init/gs_init.ps +++ b/Resource/Init/gs_init.ps @@ -34,7 +34,7 @@ % Interpreter library version number % NOTE: the interpreter code requires that the first non-comment token % in this file be an integer, and that it match the compiled-in version! -950 +952 % Check the interpreter revision. dup revision ne @@ -197,6 +197,11 @@ currentdict /NOSAFERERRORS known currentdict /SAFERERRORS known } ifelse def +currentdict /ALLOWPSTRANSPARENCY known not +{ + /ALLOWPSTRANSPARENCY //false def +} if + currentdict /SHORTERRORS known /SHORTERRORS exch def currentdict /TTYPAUSE known /TTYPAUSE exch def currentdict /WRITESYSTEMDICT known /WRITESYSTEMDICT exch def @@ -315,7 +320,7 @@ DELAYBIND ( have selected DELAYBIND. Unless you use this option with\n) print ( care \(and specifically, remember to call .bindnow\) it is\n) print ( possible that malicious code may be able to evade the\n) print - ( limited security offered by the SAFER option.\n) print + ( limited security offered by the SAFER option.\n) print flush } if .currentglobal //false .setglobal systemdict /.delaybind 2000 array .forceput @@ -331,7 +336,7 @@ DELAYBIND { pop /.bind cvx exec } ifelse - } .bind def + } .bind odef } executeonly if .currentglobal //true .setglobal @@ -2201,6 +2206,18 @@ systemdict /EPSBoundingBoxInit .forceundef readonly def .setglobal +/SAFERUndefinePostScriptOperators { + [ + % Used by our own test suite files + /.setdotlength % Bug687720.ps + /.sort /.setdebug /.mementolistnewblocks /getenv + /unread + ] + {systemdict exch .forceundef} forall + + //systemdict /SAFERUndefinePostScriptOperators .forceundef +} .bind executeonly def % must be bound and hidden for .forceundef + /tempfilepaths [ (TMPDIR) getenv not @@ -2381,25 +2398,6 @@ currentdict /.locksafe_userparams .undef currentdict /.setsafeglobal .undef currentdict /.locksafeglobal .undef -SAFER { -/SAFERUndefinePostScriptOperators { - [ - % Used by our own test suite files - /.pushpdf14devicefilter % transparency-example.ps - /.poppdf14devicefilter % transparency-example.ps - /.setopacityalpha % transparency-example.ps - /.setshapealpha % transparency-example.ps - /.endtransparencygroup % transparency-example.ps - /.setdotlength % Bug687720.ps - /.sort /.setdebug /.mementolistnewblocks /getenv - /unread - ] - {systemdict exch .forceundef} forall - - //systemdict /SAFERUndefinePostScriptOperators .forceundef -} .bind executeonly def % must be bound and hidden for .forceundef -} if - %% ---------------- SAFER stuff END -------------------%% /UndefinePostScriptOperators { @@ -2648,9 +2646,6 @@ FontDirectory readonly pop % If we are using DELAYBIND we have to defer the undefinition % until .bindnow. DELAYBIND not { - SAFER { - //systemdict /SAFERUndefinePostScriptOperators get exec - } if //systemdict /UndefinePostScriptOperators get exec } if end @@ -2694,7 +2689,7 @@ WRITESYSTEMDICT { ( care and specifically, remember to execute code like:\n) print ( "systemdict readonly pop"\n) print ( it is possible that malicious code may be able to evade the\n) print - ( limited security offered by the SAFER option.\n) print + ( limited security offered by the SAFER option.\n) print flush }if } { diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps index 0fd41646..8c41aba0 100644 --- a/Resource/Init/gs_lev2.ps +++ b/Resource/Init/gs_lev2.ps @@ -660,7 +660,7 @@ currentuserparams /WaitTimeout known % Search for valid (iccprofiles) directory as a sibling to (Resource) % and set it as a default if found. LIBPATH { - (Resource) search { + (Resource) rsearch { exch pop exch pop (iccprofiles) concatstrings .file_name_separator concatstrings dup (default_gray.icc) concatstrings status { diff --git a/Resource/Init/gs_pdfwr.ps b/Resource/Init/gs_pdfwr.ps index 422e66e1..ed691b9d 100644 --- a/Resource/Init/gs_pdfwr.ps +++ b/Resource/Init/gs_pdfwr.ps @@ -86,7 +86,7 @@ languagelevel 2 .setlanguagelevel /MonoImageDownsampleThreshold 1.5 /MonoImageFilter /CCITTFaxEncode /OffOptimizations 0 - /OPM 1 + /OPM 0 /Optimize //true /ParseDSCComments //true /ParseDSCCommentsForDocInfo //true diff --git a/Resource/Init/gs_res.ps b/Resource/Init/gs_res.ps index 068514bf..5559e6a9 100644 --- a/Resource/Init/gs_res.ps +++ b/Resource/Init/gs_res.ps @@ -284,7 +284,7 @@ systemdict begin dup .file_name_current eq { pop } { - (Resource) search { + (Resource) rsearch { exch concatstrings exch pop .file_name_separator concatstrings exit diff --git a/Resource/Init/gs_ttf.ps b/Resource/Init/gs_ttf.ps index 74043d16..6be8fe99 100644 --- a/Resource/Init/gs_ttf.ps +++ b/Resource/Init/gs_ttf.ps @@ -1304,7 +1304,7 @@ currentdict /.pickcmap_with_no_xlatmap .undef TTFDEBUG { (\n1 setting alias: ) print dup ==only ( to be the same as ) print 2 index //== exec } if - 7 index 2 index 3 -1 roll exch .forceput + 7 index 2 index 3 -1 roll exch put } forall pop pop pop } @@ -1322,7 +1322,7 @@ currentdict /.pickcmap_with_no_xlatmap .undef exch pop TTFDEBUG { (\n2 setting alias: ) print 1 index ==only ( to use glyph index: ) print dup //== exec } if - 5 index 3 1 roll .forceput + 5 index 3 1 roll put //false } { @@ -1339,7 +1339,7 @@ currentdict /.pickcmap_with_no_xlatmap .undef { % CharStrings(dict) isunicode(boolean) cmap(dict) RAGL(dict) gname(name) codep(integer) gindex(integer) TTFDEBUG { (\3 nsetting alias: ) print 1 index ==only ( to be index: ) print dup //== exec } if - exch pop 5 index 3 1 roll .forceput + exch pop 5 index 3 1 roll put } { pop pop @@ -1369,7 +1369,7 @@ currentdict /.pickcmap_with_no_xlatmap .undef } ifelse ] TTFDEBUG { (Encoding: ) print dup === flush } if -} .bind executeonly odef % hides .forceput +} .bind odef % ---------------- CIDFontType 2 font loading ---------------- % diff --git a/Resource/Init/pdf_base.ps b/Resource/Init/pdf_base.ps index 02503eef..618e5e51 100644 --- a/Resource/Init/pdf_base.ps +++ b/Resource/Init/pdf_base.ps @@ -776,11 +776,123 @@ currentdict /token_nofail_dict .undef count 4 index add % Determine stack depth with objects 3 1 roll resolveobjstreamopdict .pdfrun % Get PDF objects - count counttomark 1 add index ne { % Check stack depth - ( **** Error: Incorrect object count in object stream.\n) pdfformaterror - ( Output may be incorrect.\n) pdfformaterror - /resolveobjectstream cvx /rangecheck signalerror + count counttomark 1 add index ne + { + count counttomark 1 add index gt { + ( **** Error: Incorrect object count in object stream (too many objects).\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + } if + + % Its possible for us to end up here with a valid file. The way we work is to read the + % stream and tokenise all the objects, but that assumes there will be delimiters or + % whitespace between each object in the stream. We can easily think of cases where + % that is not true; eg two consecutive numbers 123 456 would be tokenised as a + % single number with the value 123456. + % In this case we can use the approach below to read each object individually and + % that will define the correct number of objects. After we've collected all the + % objects we'll check the number of objects recovered again, and see if there + % are still too few. We should probably raise an error in that case, but lets wait + % until we see a case. + + % Having too many objects in an ObjStm is not illegal, dumb but not illegal. We can + % recover from this, but its complicated. The extra object could be any of the ones + % from the stream, the only way to find out is to process each object individually. + % Unfortunately, my attempts to come up with a version of .pdfrun which only tokenised + % one object got rapidly bogged down. So a new approach was needed. + % + % The idea is simple; turn the underlying file into a ReusableStream, then we can + % reposition it. Build an array of the object offsets, reposition the file to the + % start of each object in turn. For all except the last object, create a sub file + % using SubFileDeocde with an empty string, and an EODCount which is the difference + % between the offset of this object and the offset of the next. + % For the last object we just read from the offset to the end of the stream. + % + % Then call .pdfrun on that sub file, or the main stream, which will tokenise all the + % objects from that point onwards. Then discard all but the first object read. + % + % The complications arise from the fact that we need to end up with the objects on + % the stack, in the right order, preceded by a mark, a count, and an array containing + % all the object numbers. + + % First, discard everything we read up to now; we can reuse the mark which was placed + % by the preceding code to do this, as long as we remember to replace that mark. + % Handily this will leave the count and the array which contains the object numbers in place. + cleartomark + + % Replace the mark consumed by conttomark above, so that we match what the code following this error handling expects. + mark + + % copy the ObjStm dictionary and then copy the count of objects expected + 4 index 4 index + + % Copy the ObjStm dictionary, and create a file from it + 1 index //false resolvestream % Convert stream dict into a stream + + /ReusableStreamDecode filter % We need to be able to re-position the stream + + 1 index array % Create array for holding offsets + + % Get the object offsets, these are stored at teh start of the stream, interleaved + % between the object numbers. We know reading these can't fail, because we've already + % done this to create the array of object numbers, above. + 0 1 % starting index (0), increment (1) for loop + 4 index 1 sub % limit of loop is object count-1 (because we start at 0) + { + 1 index 1 index % copy array and index + 4 index % copy the file object + token pop pop % read a token (object number) and discard it + 4 index token % read another token (offset) + pop put pop % put the offset into the array at the new index + } for + + % We now have an array with all the object offsets in it + % So we need to reposition the file to the start of each object and read + % from that point. We use the difference between two offsets to setup + % a SubFileDecode filter to only read as many bytes as there are + % between the objects. Normally this should result in us reading one object, + % if there are extra objects then we'll discard the extras. By doing this + % we avoid tokenising the same data multiple times. + + % Set the loop to be from 0 to the number of objects minus 1 (starts from 0), step 1. + 2 index 1 sub 0 1 3 -1 roll + { + dup % copy the loop index + 2 index length 2 sub lt % Check if index + 1 exceeds array size (it will on last iteration) + + { % Not the last iteration + dup % copy the loop index + 2 index exch get 5 index /First get add % get the object offset, and add the value of First from the dictionary. + exch 1 add % add one to the loop index + 2 index exch get 5 index /First get add % and get the offset to the start of the next object + + 1 index sub % copy the first offset and subtract from the second to get the length + exch + 3 index dup 3 -1 roll setfileposition % copy the file and position it to the offset of the object + exch + << /EODCount 3 -1 roll /EODString () >> % Set up a dictionary for the filter + /SubFileDecode filter % and apply it to limit the number of bytes read. + } + { % On the last iteration, simly read from the file, we don't need another SubFileDecode. + 1 index exch get 4 index /First get add % get the offset, and add the value of First from the dictionary. + 2 index dup 3 -1 roll setfileposition % copy the stream, and position it at that point + }ifelse + + mark exch resolveobjstreamopdict .pdfrun % make a mark and then tokenise all the objects from there to the end of stream (or sub file) + counttomark 2 sub % Find out how many objects we created (less two, one for the count and one for the first object) + 0 1 3 -1 roll {pop pop} for % pop that many objects off the stack + 6 1 roll pop % roll the new object to be behind our working objects on the stack and pop the mark + } for + + % pop most of the working objects (array, file, and ObjStrm dictionary) + % but leave count of objects. Check that aginst the number of objects + % retrieved. If we got too few then issue a warning. + + pop pop exch pop counttomark 1 sub lt { + ( **** Error: Incorrect object count in object stream (too few objects).\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + } if } if + % We have the object data counttomark array astore % Put objects into an array exch pop exch pop % Remove mark and count @@ -1139,16 +1251,26 @@ currentdict /pdf_rules_dict undef dup /JBIG2Globals knownoget { % make global ctx PDFfile fileposition exch % resolvestream is not reentrant + mark exch //true resolvestream % stack after: PDFfileposition -file- % Read the data in a loop until EOF to so we can move the strings into a bytestring [ { counttomark 1 add index 60000 string readstring not { exit } if } loop ] exch pop 0 1 index { length add } forall % compute the total length % now copy the data from the array of strings into a bytestring .bytestring exch 0 exch { 3 copy putinterval length add } forall pop - .jbig2makeglobalctx - PDFfile 3 -1 roll setfileposition - 1 index exch - /.jbig2globalctx exch put + % If this fails we don't want to abort totally, there may be more content + % in the PDF file that we can render. So just run in a stopped context. + {.jbig2makeglobalctx} stopped + { + cleartomark + PDFfile exch setfileposition + } + { + exch pop + PDFfile 3 -1 roll setfileposition + 1 index exch + /.jbig2globalctx exch put + } ifelse } if } bind executeonly def diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps index a359a9c1..1deb0526 100644 --- a/Resource/Init/pdf_draw.ps +++ b/Resource/Init/pdf_draw.ps @@ -419,14 +419,43 @@ end % Some functions used to implement phases of HT and HTP /sethalftones { + % As is so often the case, if we get an error we need to clean up the stack, but we can't + % use mark/cleartomark, because the action which caused the error may have left a mark + % on the stack. So we need to define our own mark. On an error we'll clean up the stack + % until we reach this unique key on the stack + /SethalftonesMark exch + dup /Default eq { - pop .setdefaulthalftone - } { - resolvehalftone sethalftone + pop .setdefaulthalftone pop + } + { + {resolvehalftone} stopped + { + (\n **** Error resolving halftone. Ignoring the halftone, output may be incorrect.\n) + pdfformaterror + % Clean up the stack by checking every entry until we find our unique key + {/SethalftonesMark eq {exit} if} loop + } + { + {sethalftone} stopped + { + (\n **** Error setting halftone. Ignoring the halftone, output may be incorrect.\n) + pdfformaterror + % Clean up the stack by checking every entry until we find our unique key + {/SethalftonesMark eq {exit} if} loop + } + { + pop + }ifelse + }ifelse } ifelse } bind executeonly def /sethalftonephases { - aload pop -1 2 index 2 index .setscreenphase pop pop + {aload pop -1 2 index 2 index .setscreenphase pop pop} stopped + { + (\n **** Error setting halftone phase. Ignoring the phase, output may be incorrect.\n) + pdfformaterror + } if } bind executeonly def /HT { @@ -549,9 +578,25 @@ end cleartomark //null exit } if gsave //nodict begin - /CS knownoget { + dup /CS knownoget { + exch pop resolvecolorspace dup setgcolorspace csput - } if + } + { + % Group attributes dictionaries are supposed to contain a /CS + % entry, but Acrobat apparently also handles a /ColorSpace.... + /ColorSpace knownoget { + ( **** Error: A transparency group XObject has a /ColorSpace instead of /CS attribute.\n) + pdfformaterror + resolvecolorspace dup setgcolorspace csput + } + { + ( **** Error: Ignoring a transparency group XObject without /CS attribute.\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + cleartomark //null exit + }ifelse + } ifelse aload pop setcolor [ currentgray ] end grestore /GrayBackground exch 3 2 roll @@ -643,9 +688,19 @@ def resolvecolorspace dup setgcolorspace csput //true % use currentcolorspace } { - % inheriting the colorspace -- make sure Device* spaces are not CIEBased - forceDefaultCS currentcolorspace 0 get .knownget { exec } if - //false % no defined colorspace + % Group attributes dictionaries are supposed to contain a /CS + % entry, but Acrobat apparently also handles a /ColorSpace.... + dup /Group oget /ColorSpace knownoget { + ( **** Error: A transparency group attribute dictionary has a /ColorSpace instead of /CS attribute.\n) + pdfformaterror + resolvecolorspace dup setgcolorspace csput + //true % use currentcolorspace + } + { + % inheriting the colorspace -- make sure Device* spaces are not CIEBased + forceDefaultCS currentcolorspace 0 get .knownget { exec } if + //false % no defined colorspace + } ifelse } ifelse 3 -1 roll dup dup 4 1 roll /BBox get aload pop .begintransparencymaskgroup @@ -1066,6 +1121,8 @@ currentdict end readonly def //true } ifelse { dup dup type /arraytype eq { 0 get } if + dup type /packedarraytype eq {exch pop exec dup} if + //csrdict exch .knownget { exec dup type /nametype ne { dup length 1 eq { 0 get } if } if } { @@ -1423,8 +1480,12 @@ drawopdict begin } { clippath } ifelse - //null setup_trans + % If we get an error, just emit an empty box + { pathbbox } stopped { 0 0 0 0 } if + 4 array astore grestore + //null + setup_trans //do_shade exec teardown_trans } { @@ -2210,21 +2271,15 @@ currentdict /last-ditch-bpc-csp undef } bind executeonly def /doimagesmask { % <imagemask> doimagesmask - - PDFusingtransparency { - currentdict /SMask knownoget + PDFusingtransparency not + /PreserveSMask /GetDeviceParam .special_op { exch pop } { //false } ifelse + or { + % not using transparency OR the device supports SMask (e.g. pdfwrite) + doimage } { - //false - } ifelse - { % We are doing transparency and SMask is present in the image - % stack: <imagemask> <SMask> - /PreserveSMask /GetDeviceParam .special_op { - exch pop - }{ - //false - }ifelse - { - pop % pdfwrite will process SMask directly during 'doimage' - } { + currentdict /SMask knownoget { + % We are doing transparency and SMask is present in the image + % stack: <imagemask> <SMask> .begintransparencymaskimage PDFfile fileposition exch gsave //nodict begin @@ -2236,34 +2291,44 @@ currentdict /last-ditch-bpc-csp undef end grestore PDFfile exch setfileposition 0 .endtransparencymask - } ifelse - << /Subtype /Group /Isolated //true - /.image_with_SMask //true - % pdfwrite needs : see gs/src/ztrans.c, gs/src/gdevpdft.c - % Code to deal with a Matte in the SMask. We know the image dictionary must have an SMask - % entry if we get here, so we don't need to check its existence. Just pull it out and see if - % the SMask has a Matte entry. If it does, get the ColorSpace from the parent image and - % put a /CS key with that colour space in the Group that we manufacture. Bug #700686 - % We also need to actually set the current colour space to be the same as the group - % code only picks up the current colour space, not the space from the dictionary. - currentdict /SMask get /Matte known {/CS currentdict /ColorSpace get dup pdfopdict /cs get exec } if - >> 0 0 1 1 .begintransparencygroup - doimage - .endtransparencygroup - % tell the compositor we're done with the SMask. - % Note that any SMask in the ExtGState should be reapplied - % by the next call to setfill(stroke)state AND this relies - % on our lazy evaulation of SMask groups - //false << /Subtype /None >> 0 0 0 0 .begintransparencymaskgroup - } { - .currentSMask //null ne { - % the image doesn't have an SMask, but the ExtGState does, force a group. - << /Subtype /Group /Isolated //true >> 0 0 1 1 .begintransparencygroup + << /Subtype /Group /Isolated //true + /.image_with_SMask //true + % pdfwrite needs : see gs/src/ztrans.c, gs/src/gdevpdft.c + % Code to deal with a Matte in the SMask. We know the image dictionary must have an SMask + % entry if we get here, so we don't need to check its existence. Just pull it out and see if + % the SMask has a Matte entry. If it does, get the ColorSpace from the parent image and + % put a /CS key with that colour space in the Group that we manufacture. Bug #700686 + % We also need to actually set the current colour space to be the same as the group + % code only picks up the current colour space, not the space from the dictionary. + currentdict /SMask get /Matte known {/CS currentdict /ColorSpace get dup pdfopdict /cs get exec } if + >> 0 0 1 1 + .begintransparencygroup + .currentstrokeconstantalpha .currentfillconstantalpha .currentshapealpha .currentopacityalpha 5 -1 roll + 1 .setfillconstantalpha 1 .setstrokeconstantalpha + 1 .setopacityalpha 1 .setshapealpha doimage + .setopacityalpha .setshapealpha .setfillconstantalpha .setstrokeconstantalpha .endtransparencygroup - } - { doimage } - ifelse + % tell the compositor we're done with the SMask. + % Note that any SMask in the ExtGState should be reapplied + % by the next call to setfill(stroke)state AND this relies + % on our lazy evaulation of SMask groups + //false << /Subtype /None >> 0 0 0 0 .begintransparencymaskgroup + } { + % We don't have an SMask in the image but there might be an SMask in the ExtGState + .currentSMask //null ne { + % the image doesn't have an SMask, but the ExtGState does, force a group. + << /Subtype /Group /Isolated //true >> 0 0 1 1 + .begintransparencygroup + .currentstrokeconstantalpha .currentfillconstantalpha .currentshapealpha .currentopacityalpha 5 -1 roll + 1 .setopacityalpha 1 .setshapealpha + doimage + .setopacityalpha .setshapealpha .setfillconstantalpha .setstrokeconstantalpha + .endtransparencygroup + } { + doimage + } ifelse + } ifelse } ifelse } bind executeonly def @@ -2315,6 +2380,9 @@ currentdict /last-ditch-bpc-csp undef /doimage { % <imagemask> doimage - % imagedict is currentdict, gets popped from dstack + %% We must save the colour space, in case it gets changed. I did try doing this + %% at a higher level (/Do) but that caused numerous problems with pdfwrite. + currentcolorspace exch %% save the current rendering intent .currentrenderintent exch @@ -2336,7 +2404,12 @@ currentdict /last-ditch-bpc-csp undef makemaskimage } if % Stack: datasource imagemask - gsave 1 1 moveto 0 0 lineto /image setup_trans grestore + gsave 1 1 moveto 0 0 lineto + % If we get an error, just emit an empty box + { pathbbox } stopped { 0 0 0 0 } if + 4 array astore grestore + /image + setup_trans { currentdict end setfillstate //true ValidateDecode { imagemask } } { ColorSpace setgcolorspace currentdict end setfillblend //false ValidateDecode { image } } ifelse @@ -2361,6 +2434,13 @@ currentdict /last-ditch-bpc-csp undef %% restore the rendering intent .setrenderingintent + %% and restore the colour space. We need to do this in a stopped context because + %% if we are rendering a glyph, the cache device will throw an error if we try + %% to change colour space (even when the new space is the same as the old space) + %% We can't tell if we are rendering a bitmap for a glyph, and its hard to compare + %% colour spaces, so just ignore errors for now. + {setcolorspace} stopped {pop} if + teardown_trans } bind executeonly def @@ -3043,7 +3123,7 @@ end } ifelse } ifelse } - { 0 setgray //true} ifelse + { //false } ifelse } bind executeonly def % Draw the border. Currently, we ignore requests for beveling, and we @@ -3051,17 +3131,20 @@ end /strokeborder { % <annot> <width> <dash> strokeborder - 1 index 0 ne { % do not draw if border width is 0 gsave - 2 index annotsetcolor - { +% 2 index annotsetcolor +% { 0 setdash dup setlinewidth - exch annotrect + exch dup annotrect + 5 -1 roll /RD knownoget { + applyRD + } if 2 { 4 index sub 4 1 roll } repeat 2 { 4 index 0.5 mul add 4 1 roll } repeat rectstroke pop grestore - } { - pop pop pop - } ifelse +% } { +% pop pop pop +% } ifelse } { pop pop pop }ifelse @@ -3094,12 +3177,16 @@ end % Scaling due to -dPDFFitPage is not undone, to keep the correct border width % compared to the size of the surrounding marks. //systemdict /NoUserUnit .knownget not { //false } if not - //systemdict /PDFFitPage known not and { % UserUnit is ignored if -dPDFFitPage + //systemdict /PDFFitPage known not and + % Don't apply USerUnit if we are passing it to the device + /PassUserUnit /GetDeviceParam .special_op {exch pop} {//false} ifelse not and + { % UserUnit is ignored if -dPDFFitPage Page /UserUnit knownoget { div } if } if {} 2 index /S knownoget { /D eq { 2 index /D knownoget not { {3} } if exch pop } if - } if 3 -1 roll pop strokeborder + } if + 3 -1 roll pop strokeborder } { dup 2 get exch dup length 3 gt { 3 get } { pop {} } ifelse @@ -3138,23 +3225,39 @@ end % Scaling due to -dPDFFitPage is not undone, to keep the correct border width % compared to the size of the surrounding marks. //systemdict /NoUserUnit .knownget not { //false } if not - //systemdict /PDFFitPage known not and { % UserUnit is ignored if -dPDFFitPage + //systemdict /PDFFitPage known not and + % Don't apply USerUnit if we are passing it to the device + /PassUserUnit /GetDeviceParam .special_op {exch pop} {//false} ifelse not and + { % UserUnit is ignored if -dPDFFitPage Page /UserUnit knownoget { div } if } if {} 2 index /S knownoget { /D eq { 2 index /D knownoget not { {3} } if exch pop } if } if 3 index /CA knownoget {.setopacityalpha} if - 3 -1 roll pop 2 index annotsetcolor {0 setdash setlinewidth stroke} if + 3 -1 roll pop +% 2 index annotsetcolor { + 0 setdash setlinewidth stroke +% } if } { dup 2 get - exch dup length 3 gt { 3 get } { pop {} } ifelse - 3 index /CA knownoget {.setopacityalpha} if - 2 index annotsetcolor {0 setdash setlinewidth stroke} if + % If element 3 of the /Border array is 0, then don't draw the border + dup 0 ne { + exch dup length 3 gt { 3 get } { pop {} } ifelse + 3 index /CA knownoget {.setopacityalpha} if +% 2 index annotsetcolor { + 0 setdash setlinewidth stroke +% } if + }{ + pop pop + } ifelse } ifelse } { 3 index /CA knownoget {.setopacityalpha} if - 1 {} 2 index annotsetcolor {0 setdash setlinewidth stroke} if + 1 {} +% 2 index annotsetcolor { + 0 setdash setlinewidth stroke +% } if } ifelse pop grestore @@ -3241,12 +3344,24 @@ end 1 index /DA fget not { 1 index /V fget { <EFBBBF> anchorsearch { - pop /Helvetica findfont 12 scalefont setfont + pop /Helvetica findfont + 12 scalefont setfont } { <FEFF> anchorsearch { pop pop /FallBackFont /Identity-UTF16-H [/CIDFallBack] composefont 12 scalefont setfont } { - pop /Helvetica findfont 12 scalefont setfont + pop /Helvetica findfont + % re-encode the font to PDFDocEncoding + dup length dict begin + { + 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse + } forall + /Encoding /PDFDocEncoding /Encoding findresource def + /FontName /Helvetica-PDFDocEncoding def + currentdict + end + /Helvetica-PDFDocEncoding exch definefont + 12 scalefont setfont }ifelse }ifelse } if @@ -3318,109 +3433,151 @@ end % } if % } if - dup /AP knownoget { - dup /N known not { - ( **** Error: Appearance dictionary (AP) lacks the mandatory normal (N) appearance.\n) - pdfformaterror - ( Output may be incorrect.\n) pdfformaterror + % Acrobat doesn't draw Widget annotations unles they have both /FT + % (which is defined as required) and /T keys present. Annoyingly + % these can either be inherited from the Form Definition Field + % dictionary (via the AcroForm tree) or present directly in the + % annotation, so we need to check the annotation to make sure its + % a Widget, then follow any /Parent key up to the root node + % extracting and storing any FT or T keys as we go (we only care if + % these are present, their value is immaterial). If after all that + % both keys are not present, then we don't draw the annotation. + + dup /Subtype get /Widget eq { + dup /FT known 1 index /T known and not { + dup + { + dup /FT knownoget { + /FT exch 3 index 3 1 roll put + } if + dup /T knownoget { + /T exch 3 index 3 1 roll put + } if + /Parent knownoget not { + exit + } if + } loop } if - //false - [/N /R /D] { - % stack: scalex scaley annot appearance false key - 2 index exch knownogetdict { - exch not exit + dup /FT known 1 index /T known and { + //true + } { + ( **** Warning: A Widget annotation dictionary lacks either the FT or T key.\n) + pdfformaterror + ( Acrobat ignores such annotations, annotation will not be rendered.\n) + pdfformaterror + ( Output may not be as expected.\n) pdfformaterror + //false + } ifelse + } { + //true + }ifelse + + { + dup /AP knownoget { + dup /N known not { + ( **** Error: Appearance dictionary (AP) lacks the mandatory normal (N) appearance.\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror } if - } forall - % stack: scalex scaley annot appearance value true - % stack: scalex scaley annot appearance false - dup { - pop exch pop + //false + [/N /R /D] { + % stack: scalex scaley annot appearance false key + 2 index exch knownogetdict { + exch not exit + } if + } forall + % stack: scalex scaley annot appearance value true + % stack: scalex scaley annot appearance false + dup { + pop exch pop % Acrobat Distiller produces files in which this Form % XObject lacks Type and Subtype keys. This is illegal, % but Acrobat Reader accepts it. The only way we can % tell whether this is a Form or a set of sub-appearances % is by testing for the stream Length or File key. % If the stream lacks Length key, try File key. - dup /Length knownoget { type /integertype eq } { //false } ifelse - 1 index /File knownoget { type /filetype eq or } if { - % If this is a form then simply use it - //true - } { - 1 index /AS knownoget not { - % If we do not have AS then use any appearance - { exch pop oforce exit } forall //true + dup /Length knownoget { type /integertype eq } { //false } ifelse + 1 index /File knownoget { type /filetype eq or } if { + % If this is a form then simply use it + //true } { - % Stack: annot Ndict AS - % Get the specified appearance. If no appearance, then - % display nothing - set stack = false. - knownoget + 1 index /AS knownoget not { + % If we do not have AS then use any appearance + { exch pop oforce exit } forall //true + } { + % Stack: annot Ndict AS + % Get the specified appearance. If no appearance, then + % display nothing - set stack = false. + knownoget + } ifelse } ifelse + } { + exch pop % discard useless AP dictionary } ifelse - } { - exch pop % discard useless AP dictionary - } ifelse % Stack: scalex scaley annot appearance true % Stack: scalex scaley annot false - { - dup type /dicttype eq { + { + dup type /dicttype eq { % Draw appearance % Initialize graphic following "7.4.4 Appearance Streams" - q graphicsbeginpage textbeginpage - 1 index annotrect pop pop translate - 3 index 3 index scale % Apply scale factors - dup /BBox knownoget { - 1 index /Matrix knownoget not { {1 0 0 1 0 0} } if - .bbox_transform pop pop - % Compensate for non-zero origin of BBox - neg exch neg exch translate - } if - DoForm Q - } { - ( **** Error: Annotation's appearance is not a dictionary.\n) - pdfformaterror - ( Output may be incorrect.\n) pdfformaterror - } ifelse - } if - } { - dup /MK knownoget { % mk - dup /BG knownoget { % mk bg - dup length % mk bg len - //set_bc_color exch .knownget { - gsave - exec - 3 index 3 index scale - 1 index annotrect rectfill - grestore + q graphicsbeginpage textbeginpage + 1 index annotrect pop pop translate + 3 index 3 index scale % Apply scale factors + dup /BBox knownoget { + 1 index /Matrix knownoget not { {1 0 0 1 0 0} } if + .bbox_transform pop pop + % Compensate for non-zero origin of BBox + neg exch neg exch translate + } if + DoForm Q } { - pop + ( **** Error: Annotation's appearance is not a dictionary.\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror } ifelse } if - dup /BC knownoget { - dup length - //set_bc_color exch .knownget { - gsave - exec - 1 setlinewidth - 3 index 3 index scale - 1 index annotrect rectstroke - grestore - } { - pop - } ifelse + } { + dup /MK knownoget { % mk + dup /BG knownoget { % mk bg + dup length % mk bg len + //set_bc_color exch .knownget { + gsave + exec + 3 index 3 index scale + 1 index annotrect rectfill + grestore + } { + pop + } ifelse + } if + dup /BC knownoget { + dup length + //set_bc_color exch .knownget { + gsave + exec + 1 setlinewidth + 3 index 3 index scale + 1 index annotrect rectstroke + grestore + } { + pop + } ifelse + } if + pop } if - pop - } if - dup can-regenerate-ap { - make_tx_da - dup /UpdatedAP //true put - 3 copy drawwidget - } if - } ifelse + dup can-regenerate-ap { + make_tx_da + dup /UpdatedAP //true put + 3 copy drawwidget + } if + } ifelse + } if pop pop pop } bind executeonly def + currentdict /set_bc_color undef % For annotation object we have to determine the size of the output rectangle @@ -3471,6 +3628,23 @@ currentdict /set_bc_color undef } ifelse } bind executeonly def +/applyRD { + % x y w h [l t r b] + dup 0 get % x y w h [] l + 6 -1 roll add + 5 1 roll %x+l y w h [] + dup 1 get %x+l y w h [] b + 5 -1 roll add %x+l w h [] b+y + 4 1 roll %x+l y+b w h [] + aload pop %x+l y+b w h l t r b + exch %x+l y+b w h l t b r + 4 -1 roll add %x+l y+b w h t b r+l + 3 1 roll add %x+l y+b w h r+l t+b + 3 -1 roll exch sub %x+l y+b w r+l h-(t+b) + 3 1 roll sub %x+l y+b h-(t+b) w-(r+l) + exch +} bind executeonly def + % Draw an annotation. /drawannottypes 20 dict begin @@ -3569,16 +3743,30 @@ currentdict /set_bc_color undef { gsave dup /ca knownoget {.setopacityalpha} if - dup annotrect rectfill + dup annotrect + 5 index /RD knownoget { + applyRD + } if + rectfill grestore dup /CA knownoget {.setopacityalpha} if - drawborder + dup annotsetcolor { + drawborder + } if //false }{ - pop + dup annotrect + 5 index /RD knownoget { + applyRD + } if + drawopdict /re get exec + dup annotsetcolor { + strokeborderpath + } if } ifelse //endannottransparency exec grestore + //false }ifelse } bind executeonly def @@ -3608,11 +3796,17 @@ currentdict /set_bc_color undef } { gsave //startannottransparency exec - dup annotrect 4 2 roll exch 3 index 2 div add exch 2 index 2 div add + dup annotrect + 5 index /RD knownoget { + applyRD + } if + 4 2 roll exch 3 index 2 div add exch 2 index 2 div add translate //drawellipse exec dup fillborderpath - strokeborderpath + dup annotsetcolor { + strokeborderpath + } if //endannottransparency exec grestore //false @@ -3661,8 +3855,14 @@ currentdict /set_bc_color undef fill grestore dup /CA knownoget {.setopacityalpha} if - strokeborderpath - } if + dup annotsetcolor { + strokeborderpath + } if + } { + dup annotsetcolor { + strokeborderpath + } if + } ifelse //endannottransparency exec //false grestore @@ -3795,7 +3995,7 @@ currentdict /set_bc_color undef fillborderpath grestore } bind executeonly def - /None {} bind executeonly def + /None {pop} bind executeonly def /Butt { dup /BS knownoget { @@ -3880,36 +4080,50 @@ currentdict /set_bc_color undef } { gsave //startannottransparency exec - dup /L knownoget { - 1 index /LE knownoget { - gsave - 1 index aload pop % x1 y1 x2 y2 - 3 -1 roll sub % x1 x2 dy - 3 1 roll exch sub % dy dx - 2 copy translate - atan - rotate - dup 0 get dup //LineEnd_dict exch known not {pop /None} if //LineEnd_dict exch get 3 index exch exec - grestore - gsave - 1 index aload pop % x1 y1 x2 y2 - 3 -1 roll sub % x1 x2 dy - 3 1 roll exch sub % dy dx - 2 copy translate - atan 180 add - rotate - 1 get dup //LineEnd_dict exch known not {pop /None} if //LineEnd_dict exch get 3 index exch exec - grestore - }if - aload pop 4 2 roll - moveto lineto - strokeborderpath - }{ - ( **** Error: Invalid L array for Line, annotation has not been drawn.\n) - pdfformaterror - ( Output may be incorrect.\n) pdfformaterror - pop - } ifelse + dup annotsetcolor { + dup /L knownoget { + 1 index /LE knownoget { % <annot> [x1 y1 x2 y2] [LE1 LE2] + gsave + 1 index aload pop % <annot> [x1 y1 x2 y2] [LE1 LE2] x1 y1 x2 y2 + 3 -1 roll sub % <annot> [x1 y1 x2 y2] [LE1 LE2] x1 x2 dy + 3 1 roll exch sub % <annot> [x1 y1 x2 y2] [LE1 LE2] dy dx + 3 index aload pop 4 2 roll pop pop + translate + 0 0 moveto + atan % <annot> [x1 y1 x2 y2] [LE1 LE2] + rotate + dup 1 get % <annot> [x1 y1 x2 y2] [LE1 LE2] LE1 + dup //LineEnd_dict exch known not + { + pop /None + } if + //LineEnd_dict exch % <annot> [x1 y1 x2 y2] [LE1 LE2] <dict> LE1 + get % <annot> [x1 y1 x2 y2] [LE1 LE2] {} + 3 index exch % <annot> [x1 y1 x2 y2] [LE1 LE2] <annot> {} + exec + grestore + gsave + 1 index aload pop % x1 y1 x2 y2 + 3 -1 roll sub % x1 x2 dy + 3 1 roll exch sub % dy dx + 3 index aload pop pop pop + translate + 0 0 moveto + atan 180 add + rotate + 0 get dup //LineEnd_dict exch known not {pop /None} if //LineEnd_dict exch get 3 index exch exec + grestore + }if + aload pop 4 2 roll + moveto lineto + strokeborderpath + }{ + ( **** Error: Invalid L array for Line, annotation has not been drawn.\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + pop + } ifelse + } if //endannottransparency exec //false grestore @@ -3977,14 +4191,16 @@ currentdict /set_bc_color undef /Link { % <annot> -> <false> //startannottransparency exec - dup drawborder dup calc_annot_scale - 2 copy mul 0 ne - {3 -1 roll drawwidget //false} - { - pop pop - ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror - ( Output may be incorrect.\n) pdfformaterror - }ifelse + dup annotsetcolor { + dup drawborder dup calc_annot_scale + 2 copy mul 0 ne + {3 -1 roll drawwidget //false} + { + pop pop + ( **** Error: ignoring annotation with scale factor of 0\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + }ifelse + } if //endannottransparency exec } bind executeonly def @@ -3998,7 +4214,8 @@ currentdict /set_bc_color undef 1 setlinewidth 1 setlinecap 1 setlinejoin - dup annotsetcolor { + dup annotsetcolor + { dup calc_annot_scale 2 copy mul 0 ne { @@ -4047,7 +4264,8 @@ currentdict /set_bc_color undef //true } { 0 setlinecap - dup annotsetcolor { + dup annotsetcolor + { dup calc_annot_scale 2 copy mul 0 ne { @@ -4087,7 +4305,8 @@ currentdict /set_bc_color undef //true } { 0 setlinecap - dup annotsetcolor { + dup annotsetcolor + { dup calc_annot_scale 2 copy mul 0 ne { @@ -4149,7 +4368,8 @@ currentdict /set_bc_color undef //true } { 0 setlinecap - dup annotsetcolor { + dup annotsetcolor + { /QuadPoints knownoget { aload length 8 idiv { 6 -2 roll @@ -4161,7 +4381,9 @@ currentdict /set_bc_color undef } repeat PDFusingtransparency { //emptydict - pathbbox 2 index add exch 3 index add exch .begintransparencygroup + % If we get an error, just emit an empty box + { pathbbox } stopped { 0 0 0 0 } if + 2 index add exch 3 index add exch .begintransparencygroup /Multiply .setblendmode fill .endtransparencygroup @@ -4182,7 +4404,8 @@ currentdict /set_bc_color undef //true } { //startannottransparency exec - dup annotsetcolor { + dup annotsetcolor + { dup calc_annot_scale 2 copy mul 0 ne { @@ -4323,18 +4546,37 @@ currentdict /set_bc_color undef }{ //false } ifelse - {dup annotrect - %% Somewhat horrifyingly, rectfill maps directly to the device fill_rectangle - %% method, which bypasses transparency (!!) So we construct the rectangle, - %% and fill it, manually instead.... - gsave 4 2 roll moveto 1 index 0 rlineto - 0 exch rlineto neg 0 rlineto closepath fill grestore + { + dup annotrect + 5 index /RD knownoget { + applyRD + } if + rectfill } if %% get and process the default appearance string, if we don't have one, use a default /DA_Action_Dict << - /Tf {exch dup /Helv eq {pop /Helvetica findfont exch scalefont setfont}{findfont exch scalefont setfont}ifelse} + /Tf + { + exch dup /Helv eq + { + pop /Helvetica dup findfont + } + {dup findfont}ifelse + + % re-encode the font to PDFDocEncoding + dup length dict begin + { + 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse + } forall + /Encoding /PDFDocEncoding /Encoding findresource def + /FontName /Helvetica-PDFDocEncoding def + currentdict + end + definefont + exch scalefont setfont + } /r {aload pop setrgbcolor} % Can't find this actually defined anywhere, but Acrobat seems to honour it :-( /rg {setrgbcolor} /RG {setrgbcolor} @@ -4380,27 +4622,108 @@ currentdict /set_bc_color undef {cleartomark pop} ifelse } { 0 setgray - /Helvetica findfont 12 scalefont setfont + /Helvetica findfont + % re-encode the font to PDFDocEncoding + dup length dict begin + { + 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse + } forall + /Encoding /PDFDocEncoding /Encoding findresource def + /FontName /Helvetica-PDFDocEncoding def + currentdict + end + /Helvetica-PDFDocEncoding exch definefont + 12 scalefont setfont }ifelse %% draw the border, if we don't have a border style dictionary, draw a default one. - dup /BS knownoget { + dup /BS knownoget + { pop dup drawborder }{ newpath 0 setgray 1 setlinewidth - dup annotrect 4 -1 roll 1 add 4 -1 roll 1 add 4 -1 roll 2 sub 4 -1 roll 2 sub - 4 2 roll moveto - currentpoint exch 3 index add exch lineto - currentpoint 2 index add lineto - exch currentpoint 3 1 roll exch sub exch lineto - currentpoint 3 -1 roll sub lineto stroke + dup annotrect + 5 index /RD knownoget { + applyRD + 4 -1 roll 4 -1 roll 4 -1 roll 4 -1 roll + 4 2 roll + } { + 4 -1 roll 1 add 4 -1 roll 1 add 4 -1 roll 2 sub 4 -1 roll 2 sub + 4 2 roll + }ifelse + moveto + currentpoint exch 3 index add exch + lineto + currentpoint 2 index add + lineto + exch currentpoint 3 1 roll exch sub exch + lineto + currentpoint 3 -1 roll sub + lineto stroke }ifelse + gsave % in case we rotate the contents %% Start the current point at the top left of the annotation Rect %% - dup annotrect 4 -1 roll 2 add 4 -1 roll 2 add 4 -1 roll 4 sub 4 -1 roll 4 sub - 3 -1 roll add 2 index exch moveto 1 index add + dup /Rotate knownoget + % x y w h - x' w' x' y' + { + dup 90 eq { + pop + dup annotrect + 5 index /RD knownoget { + applyRD + } if + exch pop 3 -1 roll 2 index + moveto 90 rotate + 1 index add + } { + dup 180 eq { + pop + dup annotrect + 5 index /RD knownoget { + applyRD + } if + pop 3 -1 roll 1 index add -1 mul exch 1 index -1 mul 4 -1 roll + moveto 180 rotate + 1 index add + }{ + 270 eq { + dup annotrect + 5 index /RD knownoget { + applyRD + } if + dup 4 -1 roll add 3 -1 roll 3 index add exch + moveto 270 rotate + exch pop currentpoint + pop dup 3 -1 roll add + }{ + dup annotrect + 5 index /RD knownoget { + applyRD + 3 -1 roll add 2 index exch + moveto 1 index add + }{ + 4 -1 roll 2 add 4 -1 roll 2 add 4 -1 roll 4 sub 4 -1 roll 4 sub + 3 -1 roll add 2 index exch + moveto 1 index add + } ifelse + } ifelse + } ifelse + } ifelse + }{ + dup annotrect + 5 index /RD knownoget { + applyRD + 3 -1 roll add 2 index exch + moveto 1 index add + }{ + 4 -1 roll 2 add 4 -1 roll 2 add 4 -1 roll 4 sub 4 -1 roll 4 sub + 3 -1 roll add 2 index exch + moveto 1 index add + } ifelse + } ifelse %% Get the Contents string, if we don't have one, we're done %% @@ -4439,7 +4762,6 @@ currentdict /set_bc_color undef %% and use it immediatley to start the text one line down %% currentpoint ..TextHeight sub moveto - %% Now we process each character code in the string. If we find %% a /r/ or /n then we drop a line. If the character would end up %% outside the Annot Rect, then we drop a line before showing it. @@ -4453,7 +4775,8 @@ currentdict /set_bc_color undef } { 1 string dup 0 4 -1 roll put dup %% llx urx (string) (int) (int) - stringwidth pop currentpoint pop add 3 index gt { + stringwidth pop currentpoint pop add 3 index + gt { currentpoint exch pop 4 index exch ..TextHeight sub moveto } if show @@ -4470,6 +4793,34 @@ currentdict /set_bc_color undef } ifelse } if pop pop + + grestore % in case the contents were rotated + dup /CL knownoget { + dup length 6 eq { + dup aload pop pop pop + } { + dup length 4 eq { + dup aload pop + } { + pop 0 + } ifelse + } ifelse + 4 2 roll + exch 4 -1 roll sub + 3 1 roll exch sub + atan exch + aload pop moveto lineto lineto + currentpoint +% stroke +% 0 1 0 setrgbcolor + moveto currentpoint translate 0 0 moveto + 360 exch sub rotate + currentpoint + -5 -8 rlineto + moveto + 5 -8 rlineto + stroke + } if //endannottransparency exec //false grestore @@ -4505,7 +4856,18 @@ currentdict /set_bc_color undef PDFusingtransparency { .begintransparencytextgroup } if - /Times-Bold findfont exch scalefont setfont % (text) y + /Times-Bold findfont + % re-encode the font to PDFDocEncoding + dup length dict begin + { + 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse + } forall + /Encoding /PDFDocEncoding /Encoding findresource def + /FontName /Times-Bold-PDFDocEncoding def + currentdict + end + /Times-Bold-PDFDocEncoding exch definefont + exch scalefont setfont % (text) y gsave 0 0 moveto 1 index //false charpath flattenpath pathbbox @@ -4668,7 +5030,18 @@ currentdict /set_bc_color undef .begintransparencytextgroup } if 0 setgray - /Helvetica findfont 9 scalefont setfont + /Helvetica findfont + % re-encode the font to PDFDocEncoding + dup length dict begin + { + 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse + } forall + /Encoding /PDFDocEncoding /Encoding findresource def + /FontName /Helvetica-PDFDocEncoding def + currentdict + end + /Helvetica-PDFDocEncoding exch definefont + 9 scalefont setfont 2 index aload pop 3 1 roll pop pop 30 sub exch 5 add exch moveto show PDFusingtransparency { @@ -4687,7 +5060,18 @@ currentdict /set_bc_color undef .begintransparencytextgroup } if 0 setgray - /Helvetica findfont 9 scalefont setfont + /Helvetica findfont + % re-encode the font to PDFDocEncoding + dup length dict begin + { + 1 index /FID ne 2 index /UniqueID ne and { def } { pop pop } ifelse + } forall + /Encoding /PDFDocEncoding /Encoding findresource def + /FontName /Helvetica-PDFDocEncoding def + currentdict + end + /Helvetica-PDFDocEncoding exch definefont + 9 scalefont setfont dup stringwidth pop 2 index aload pop pop exch pop exch sub exch sub 2 div 2 index aload pop 3 1 roll pop pop 11 sub 3 1 roll add exch moveto @@ -4748,6 +5132,25 @@ currentdict end readonly def ifelse } bind executeonly def +/.PDFPreserveAnnotType? +{ + //false exch + /PreserveAnnotTypes where + { + /PreserveAnnotTypes get + { + dup /* eq exch 2 index eq or + { + pop //true exch + exit + } if + } forall + pop + } + {pop pop //true} + ifelse +} bind executeonly def + /drawannot { % <annot> drawannot - dup annotvisible { gsave @@ -5050,7 +5453,7 @@ currentdict end readonly def gsave dup dup /Subtype knownoget { - dup //.PDFDrawAnnotType? exec + dup //.PDFPreserveAnnotType? exec { //preserveannottypes exch .knownget { exec } { //true } ifelse { @@ -5068,7 +5471,13 @@ currentdict end readonly def }ifelse } if } - {pop} ifelse + { + % Not preserving this type of annotation + % discard teh Subtype + pop + % copy the Annot dictionary and try drawing it instead + dup drawannot + } ifelse % type known } { pop diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps index 81b7af13..60deb64e 100644 --- a/Resource/Init/pdf_font.ps +++ b/Resource/Init/pdf_font.ps @@ -857,176 +857,222 @@ setglobal /.pdfdfndict mark /defaultfontname /Helvetica .dicttomark readonly def -/pdffindfont { % <font-resource> <fontname> pdffindfont <font> - % If the font isn't available, synthesize one based on - % its descriptor. - dup /Font resourcestatus { - pop pop pdffindcachedfont - } { - 1 index /FontDescriptor knownoget { - % 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 +% 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 - % Some non-compliant files are missing FirstChar/LastChar, - % despite referencing a non-base14 font - 3 index /FirstChar knownoget + % 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 { - 0 % push an initial value for accumating the Widths - 0 string % and an empty string to interrogate the font - 7 index /Widths knownoget + 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 { - 0 1 2 index length 1 sub + 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 { - 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 + 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 } { - % no suitable Widths entries - carry on and hope for the best...... - pop pop 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 + 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 } { - ( **** Warning: FirstChar value missing in FontDescriptor for non-base14 font\n) - pdfformatwarning + % no suitable Widths entries - carry on and hope for the best...... + pop pop pop } 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 - } { - % No descriptor available, use the default algorithm. + } + { + % 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 { % <font-resource> <fontname> pdffindfont <font> + % 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 @@ -2473,23 +2519,22 @@ currentdict /bndef undef % if the font was defined in-line, we won't have a object number dup /.gs.pdfobj# .knownget not { //null } if } { - dup /FontDescriptor knownoget { % if the font was defined in-line, we won't have a object number - dup /.gs.pdfobj# .knownget not { //null }if - dup //null eq { - exch pop - }{ - exch dup /FontFile knownoget not { - dup /FontFile2 knownoget not { - dup /FontFile3 knownoget not { - pop pop //null - } {pop pop}ifelse + 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 - }ifelse - }{ - //null - } ifelse + } {pop pop}ifelse + }{pop pop}ifelse + } + { + pop //null + } ifelse + }if } ifelse 3 1 roll diff --git a/Resource/Init/pdf_main.ps b/Resource/Init/pdf_main.ps index 7690bae0..5cd90556 100644 --- a/Resource/Init/pdf_main.ps +++ b/Resource/Init/pdf_main.ps @@ -47,7 +47,7 @@ userdict /GS_PDF_ProcSet undef % PDF 1.1 operators /BX { /BXlevel BXlevel 1 add store } bind executeonly /EX { /BXlevel BXlevel 1 sub store } bind executeonly - /PS { cvx exec } bind executeonly + /PS { DOPS { cvx exec } { pop } ifelse } bind executeonly % PS disabled by default, as in pdf_draw.ps DoPS % PDF 1.2 operators /BMC { /BMClevel BMClevel 1 add store @@ -2339,8 +2339,20 @@ end readonly def /get_media_box { % <pagedict> get_media_box <box> <bool> /MediaBox pget { - oforce_array //true - } { + oforce_array + dup length 4 eq { + //true + } + { + pop + ( **** Error: Page has an invalid /MediaBox attribute. Using the current page size.\n) + pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + [ 0 0 currentpagedevice /PageSize get aload pop ] + //false + }ifelse + } + { ( **** Error: Page has no /MediaBox attribute. Using the current page size.\n) pdfformaterror ( Output may be incorrect.\n) pdfformaterror @@ -2493,9 +2505,26 @@ end readonly def 1 } { 1 index /UserUnit knownoget { - PDFDEBUG { (Scaling due to UserUnit by ) print dup = flush } if + /PassUserUnit /GetDeviceParam .special_op { + exch pop dup { + [ /UserUnit 4 -1 roll .pdfputparams pop pop 1 exch + } if + }{ + //false + }ifelse + + not { + PDFDEBUG { (Scaling due to UserUnit by ) print dup = flush } if + } if } { - 1 + /PassUserUnit /GetDeviceParam .special_op { + exch pop { + [ /UserUnit 1 .pdfputparams pop pop + } if + 1 + }{ + 1 + } ifelse } ifelse } ifelse } ifelse @@ -2573,8 +2602,23 @@ currentdict /PDF2PS_matrix_key undef % Set the page size. //systemdict /NoUserUnit .knownget not { //false } if not { 3 index /UserUnit knownoget { - dup 4 -1 roll mul 3 1 roll mul - } if + /PassUserUnit /GetDeviceParam .special_op { + exch pop dup { + [ /UserUnit 4 -1 roll .pdfputparams pop pop + } if + }{ + //false + }ifelse + not { + dup 4 -1 roll mul 3 1 roll mul + } if + } { + /PassUserUnit /GetDeviceParam .special_op { + exch pop { + [ /UserUnit 1 .pdfputparams pop pop + } if + }if + } ifelse } if } ifelse 2 array astore /PageSize exch def @@ -2740,7 +2784,7 @@ currentdict /PDF2PS_matrix_key undef .poppdf14devicefilter % NB: reset to DefaultQstate will also restore transfer function /DefaultQstate qstate store % device has changed -- reset DefaultQstate } { - /setup_trans { pop } def % no-op this if the page doesn't use transparency + /setup_trans { pop pop } def % no-op this if the page doesn't use transparency % NB: original will be restored from PDFsave showpagecontents } ifelse @@ -2856,7 +2900,19 @@ currentdict /PDF2PS_matrix_key undef % Draw the annotations //systemdict /ShowAnnots .knownget not { //true } if { /Annots knownoget { - { oforce + { + /AnnotDrawCheck exch % marker to clean up stack on error + {oforce} stopped + { + ( **** Error: Unable to draw an annotation.\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + count -1 0 { % make sure we don't go past the top of the stack + pop % remove the counter + /AnnotDrawCheck eq {exit} if % remove object and check if its the marker, exit if it is + } for + } + { + exch pop dup //null ne { .writepdfmarks %% @@ -2878,6 +2934,7 @@ currentdict /PDF2PS_matrix_key undef } { pop } ifelse + } ifelse } forall } if } if @@ -3063,33 +3120,45 @@ currentdict /PDF2PS_matrix_key undef //false exch % Assume no transparency /Annots knownoget { % Get Annots array { - oforce - dup //null ne { - dup /Subtype knownoget { - /Highlight eq { % Highlight annotation is always implemented - pop pop //true exit % as transparency. + /AnnotTransparencyCheck exch % marker to clean up stack on error + {oforce} stopped + { + ( **** Error: Unable to check an annotation for use of transparency.\n) pdfformaterror + ( Output may be incorrect.\n) pdfformaterror + count -1 0 { % make sure we don't go past the top of the stack + pop % remove the counter + /AnnotTransparencyCheck eq {exit} if % remove object and check if its the marker, exit if it is + } for + } + { + exch pop % remove the 'on error' marker + dup //null ne { + dup /Subtype knownoget { + /Highlight eq { % Highlight annotation is always implemented + pop pop //true exit % as transparency. + } if } if - } if - dup /AP knownoget { % Get appearance dict for the annoation - /N knownogetdict { % Get the /N (i.e. normal) appearance stream - 4 dict exch resourceusestransparency { pop pop //true exit } if + dup /AP knownoget { % Get appearance dict for the annoation + /N knownogetdict { % Get the /N (i.e. normal) appearance stream + 4 dict exch resourceusestransparency { pop pop //true exit } if + } if + } if % If AP dict known + dup /BM knownoget { + //true exit } if - } if % If AP dict known - dup /BM knownoget { - //true exit - } if - dup /CA knownoget { - 1 le { - pop pop //true exit + dup /CA knownoget { + 1 le { + pop pop //true exit + } if } if - } if - /ca knownoget { - 1 le { - pop //true exit + /ca knownoget { + 1 le { + pop //true exit + } if } if - } if - } { - pop + } { + pop + } ifelse } ifelse } forall % For all annots on the page } if @@ -3545,24 +3614,33 @@ end % pdfdict /.setfillcolor /.setfillcolorspace /.setstrokecolor /.setstrokecolorspace /.currentrenderingintent /.setrenderingintent /.currenttextrenderingmode /.settextspacing /.currenttextspacing /.settextleading /.currenttextleading /.settextrise /.currenttextrise /.setwordspacing /.currentwordspacing /.settexthscaling /.currenttexthscaling -/.settextlinematrix /.currenttextlinematrix /.currenttextmatrix /.settextmatrix /.currentblendmode -/.currentopacityalpha /.currentshapealpha /.currenttextknockout -/.pushextendedgstate /.popextendedgstate /.begintransparencytextgroup -/.endtransparencytextgroup /.begintransparencymaskgroup /.begintransparencymaskimage /.endtransparencymask /.image3x -/.abortpdf14devicefilter /.pdfinkpath /.pdfFormName /.setstrokeconstantalpha -/.setfillconstantalpha /.setalphaisshape /.currentalphaisshape -/.settextspacing /.currenttextspacing /.settextleading /.currenttextleading /.settextrise /.currenttextrise -/.setwordspacing /.currentwordspacing /.settexthscaling /.currenttexthscaling /.setPDFfontsize /.currentPDFfontsize -/.setdistillerparams - -% Used by our own test suite files -%/.pushpdf14devicefilter % transparency-example.ps -%/.poppdf14devicefilter % transparency-example.ps -%/.setopacityalpha % transparency-example.ps -%/.setshapealpha % transparency-example.ps -%/.endtransparencygroup % transparency-example.ps +/.settextlinematrix /.currenttextlinematrix /.currenttextmatrix /.settextmatrix /.pushextendedgstate +/.popextendedgstate + +/.pdfinkpath /.pdfFormName /.settextspacing /.currenttextspacing /.settextleading /.currenttextleading +/.settextrise /.currenttextrise /.setwordspacing /.currentwordspacing /.settexthscaling /.currenttexthscaling +/.setPDFfontsize /.currentPDFfontsize /.setdistillerparams % undefining these causes errors/incorrect output -%/.settextrenderingmode /.setblendmode /.begintransparencygroup /.settextknockout /.setstrokeoverprint /.setfilloverprint -%/.currentstrokeoverprint /.currentfilloverprint /.currentfillconstantalpha /.currentstrokeconstantalpha +%/.settextrenderingmode ] systemdict .undefinternalnames + +% The following are split out allowing control via ALLOWPSTRANSPARENCY command line param +[ + /.currentblendmode /.currentopacityalpha /.currentshapealpha /.currenttextknockout /.begintransparencytextgroup + /.endtransparencytextgroup /.begintransparencymaskgroup /.begintransparencymaskimage /.begintransparencypagegroup + /.endtransparencymask /.image3x /.abortpdf14devicefilter /.setfillconstantalpha /.setalphaisshape /.currentalphaisshape + + % Used by our own test suite files + %/.pushpdf14devicefilter % transparency-example.ps + %/.poppdf14devicefilter % transparency-example.ps + %/.setopacityalpha % transparency-example.ps + %/.setshapealpha % transparency-example.ps + %/.endtransparencygroup % transparency-example.ps + + % undefining these causes errors/incorrect output + %/.setblendmode /.begintransparencygroup /.settextknockout /.setstrokeoverprint /.setfilloverprint + %/.currentstrokeoverprint /.currentfilloverprint /.currentfillconstantalpha /.currentstrokeconstantalpha + %/.setstrokeconstantalpha /.setfillconstantalpha /.setSMask /.currentSMask + +] systemdict dup /ALLOWPSTRANSPARENCY get {pop pop}{.undefinternalnames}ifelse diff --git a/Resource/Init/pdf_ops.ps b/Resource/Init/pdf_ops.ps index d594035c..eb2168a5 100644 --- a/Resource/Init/pdf_ops.ps +++ b/Resource/Init/pdf_ops.ps @@ -279,8 +279,8 @@ currentdict /gput_always_allow .undef /DeviceCMYK { [0 0 0 1] cvx } bind executeonly /CIEBasedA { 0 } bind executeonly /CIEBasedABC { [0 0 0] cvx } bind executeonly - /CalGray { pop /DeviceGray 0 } bind executeonly - /CalRGB { pop /DeviceRGB [0 0 0] cvx } bind executeonly + /CalGray { 0 } bind executeonly + /CalRGB { [0 0 0] cvx } bind executeonly /Lab {[0 0 0] cvx } bind executeonly /ICCBased { [ 1 index 1 oget /N get { 0 } repeat ] cvx } bind executeonly /Separation { 1 } bind executeonly @@ -701,7 +701,7 @@ end % NB: setup_trans is defined as either setupOPtrans (for devices that can support % overprint, or as setupSMtrans which pushes a group for SMask. % Also see 'teardown_trans' that pops the group and resets the changed values. -/setupOPtrans % <fillop|strokeop> setup_trans +/setupOPtrans % [ pathbbox ] <fillop|strokeop> setup_trans { % Check OP and BM in case we need to push a group //OPsaveDstack begin //Dpush exec % push the current OPsaveDstack values into 'previous' @@ -719,41 +719,34 @@ end } ifelse .currentSMask //null ne or { % push a group for OP or SMask mark /Subtype /Group /Isolated .currentSMask //null ne .dicttomark - 1 index /stroke eq { - % BBox needs to include line width / line join expansion. - gsave strokepath pathbbox grestore - } { - pathbbox % fill/eofill cases - } ifelse + 2 index aload pop % pathbbox .begintransparencygroup % After group pushed, set opacityalpha, shapealpha and blendmode /saveOA .currentopacityalpha def /saveSA .currentshapealpha def 1 .setopacityalpha 1 .setshapealpha /GroupPushed //true def - } if + } { + /GroupPushed //false def + } ifelse % we may change to CompatibleOverprint even if we didn't push a group. ChangeBM { /saveBM .currentblendmode def /CompatibleOverprint .setblendmode } if pop % fillop/strokeop + pop % pathbbox array end % OPsaveDstack } bind executeonly def % Also see 'teardown_trans' that pops the group and resets the changed values. -/setupSMtrans % <fillop|strokeop> setup_trans +/setupSMtrans % [ pathbbox ] <fillop|strokeop> setup_trans { //OPsaveDstack begin //Dpush exec % push the current OPsaveDstack values into 'previous' .currentSMask //null ne 1 index /image ne and % only push for SMask if not from image { mark /Subtype /Group /Isolated //true .dicttomark - exch /stroke eq { - % BBox needs to include line width / line join expansion. - gsave strokepath pathbbox grestore - } { - pathbbox % fill/eofill cases - } ifelse + 2 index aload pop % pathbbox .begintransparencygroup % After group pushed, set opacityalpha, shapealpha and blendmode /saveOA .currentopacityalpha def @@ -762,9 +755,10 @@ end /GroupPushed //true def } { /GroupPushed //false def - pop % fillop/strokeop } ifelse end % OPsaveDstack + pop % fillop/strokeop + pop % pathbbox array } bind executeonly def % If a transparency group was pushed, pop it, and reset the settings. @@ -791,9 +785,23 @@ currentdict dup /Dpush .undef /Dpop .undef /fsexec % <fillop|strokeop> fsexec - { PDFusingtransparency { - dup setup_trans - cvx exec - teardown_trans + dup /stroke eq 1 index /.fillstroke eq or 1 index /.eofillstroke eq or { + % BBox needs to include line width / line join expansion. + % strokepath will return empty path (no currentpoint) if nothing is stroked + { gsave strokepath pathbbox } stopped grestore { + % If we get an error, just emit an empty box + 0 0 0 0 + } if + } { + % If we get an error, just emit an empty box + { pathbbox } stopped { 0 0 0 0 } if + } ifelse + % pathbbox valid -- proceed with drawing + 4 array astore % pathbbox + 1 index + setup_trans + cvx exec + teardown_trans } { cvx exec } ifelse @@ -924,23 +932,7 @@ currentdict dup /Dpush .undef /Dpop .undef /B { OFFlevels length 0 eq { - PDFusingtransparency { - % knockout trans group around the filled and stroked object - mark - /Isolated //true /Knockout //true - .dicttomark - % strokepath will return empty path (no currentpoint) if nothing is stroked - gsave { strokepath pathbbox } stopped grestore not { - 1 .setopacityalpha - .begintransparencygroup - gsave setfillstate fill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - .endtransparencygroup - } { newpath pop } ifelse - } { - gsave setfillstate fill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - } ifelse + setstrokestate setfillstate /.fillstroke fsexec } { newpath } ifelse @@ -950,23 +942,7 @@ currentdict dup /Dpush .undef /Dpop .undef /B* { OFFlevels length 0 eq { - PDFusingtransparency { - % knockout trans group around the filled and stroked object - mark - /Isolated //true /Knockout //true - .dicttomark - % strokepath will return empty path (no currentpoint) if nothing is stroked - gsave { strokepath pathbbox } stopped grestore not { - 1 .setopacityalpha - .begintransparencygroup - gsave setfillstate eofill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - .endtransparencygroup - } { newpath pop } ifelse - } { - gsave setfillstate eofill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - } ifelse + setstrokestate setfillstate /.eofillstroke fsexec } { newpath } ifelse @@ -982,49 +958,14 @@ currentdict dup /Dpush .undef /Dpop .undef /f* { OFFlevels length 0 eq { gsave setfillstate eofill grestore } if n } bind executeonly def /B { OFFlevels length 0 eq { - PDFusingtransparency { - % knockout trans group around the filled and stroked object - mark - /Isolated //true /Knockout //true - .dicttomark - % strokepath will return empty path (no currentpoint) if nothing is stroked - gsave {strokepath pathbbox } stopped grestore not - { - 1 .setopacityalpha - .begintransparencygroup - gsave setfillstate fill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - .endtransparencygroup - } { - newpath pop - } ifelse - } { - gsave setfillstate fill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - } ifelse + .fillstroke } if n } bind executeonly def /b { closepath B } bind executeonly def /B* { OFFlevels length 0 eq { - PDFusingtransparency { - % knockout trans group around the filled and stroked object - mark - /Isolated //true /Knockout //true - .dicttomark - % strokepath will return empty path (no currentpoint) if nothing is stroked - gsave {strokepath pathbbox} stopped grestore not { - 1 .setopacityalpha - .begintransparencygroup - gsave setfillstate eofill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - .endtransparencygroup - } { newpath pop } ifelse - } { - gsave setfillstate eofill grestore - setstrokestate .swapcolors /stroke fsexec .swapcolors - } ifelse + .eofillstroke } if n } bind executeonly def @@ -1219,9 +1160,19 @@ end readonly def } bind executeonly def +/clip_if_required { + .currenttextrenderingmode 4 ge + {currentpoint} //.internalstopped exec + {//false} + {pop pop //true} + ifelse and + { .currentfilladjust2 0 dup .setfilladjust2 clip .setfilladjust2} if + newpath +} bind def + /ET_NO_TXT_KO { currentdict /TextSaveMatrix known { - .currenttextrenderingmode 4 ge { .currentfilladjust2 0 dup .setfilladjust2 clip .setfilladjust2 newpath} if + //clip_if_required exec TextSaveMatrix setmatrix currentdict /TextSaveMatrix undef @@ -1244,6 +1195,8 @@ end readonly def } if } bind executeonly def +currentdict /clip_if_required .undef + /ET { //ET_NO_TXT_KO exec % Group push occurred in pdf14_text_begin. @@ -1642,8 +1595,19 @@ end readonly def % If current path is not known to be valid, use the clip path /TextTransSetup { % showarg path_valid TextTransSetup showarg % showarg path_valid false TextTransSetup showarg + gsave % NB: if 'show' is used, then we use the clippath, but a smaller bbox is preferred - not dup { gsave clippath } if //null setup_trans { grestore } if + { + % path was (probably) valid (CTM may not be invertable) + % Since TR mode may include stroking, expand for stroke + % If we get an error, just emit an empty box + { strokepath pathbbox } stopped { 0 0 0 0 } if + } { + clippath pathbbox stopped { 0 0 0 0 } if + } ifelse + grestore + 4 array astore //null + setup_trans } bind executeonly def /TextTransTeardown { @@ -1678,25 +1642,35 @@ end readonly def % operations when the CTM is singular. % Work around this here. { - matrix currentmatrix dup dup - dup 0 get 0 eq 1 index 1 get 0 eq and { - dup dup 2 get 0 eq { 0 }{ 1 } ifelse 1 put - } if - dup 2 get 0 eq 1 index 3 get 0 eq and { - dup dup 1 get 0 eq { 3 }{ 2 } ifelse 1 put - } if - setmatrix - currentpoint - % don't worry about transparency for invisible text - 4 index settextfillstate show % Tr was set to graphic state. - moveto - setmatrix - % now set the currentpoint using the original matrix - gsave - setmatrix - //false charpath currentpoint newpath - grestore - moveto + matrix currentmatrix + % Previously we tested specifically for a scale factor of 0, + % but bug #701875 has a CTM which is minute, but not zero. If + % we try to use that at anything except low resolution FreeType + % ends up trying to deal with glyph metrics where one dimension is 0 + % and it throws an error. So instead of looking for zero, we'll look + % for a really tiny CTM. + % We also used to patch up the CTM, and still use it, but frankly + % this is too much trouble. If the CTM is tiny then the displacement + % due to drawing the text will also be tiny. Negligible in fact. + % So if its that small then lets just ignore it. + dup 0 get abs 0.00001 lt 1 index 1 get 0.00001 abs lt and not { + dup 2 get abs 0.00001 lt 1 index 3 get abs 0.00001 lt and not { + pop + currentpoint + % don't worry about transparency for invisible text + 2 index settextfillstate show % Tr was set to graphic state. + moveto + % now set the currentpoint using the original matrix + gsave + //false charpath currentpoint newpath + grestore + moveto + } { + pop pop + }ifelse + } { + pop pop + }ifelse } } { { //false charpath textrenderingprocs .currenttextrenderingmode get exec } @@ -1919,7 +1893,9 @@ end readonly def 1 .setopacityalpha % While text will always have a currentpoint, strokepath seems to mess with it. % we get the currentpoint, then use moveto to restore it for pathbbox - gsave currentpoint strokepath moveto pathbbox grestore + { gsave currentpoint strokepath moveto pathbbox } stopped grestore { + /tB cvx /undefinedresult signalerror + } if .begintransparencygroup gsave tf grestore tS .endtransparencygroup |