]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/pdf_ops.ps
merge
[plan9front.git] / sys / lib / ghostscript / pdf_ops.ps
1 %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
2
3 % This software is provided AS-IS with no warranty, either express or
4 % implied.
5
6 % This software is distributed under license and may not be copied,
7 % modified or distributed except as expressly authorized under the terms
8 % of the license contained in the file LICENSE in this distribution.
9
10 % For more information about licensing, please refer to
11 % http://www.ghostscript.com/licensing/. For information on
12 % commercial licensing, go to http://www.artifex.com/licensing/ or
13 % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
16 % $Id: pdf_ops.ps,v 1.41 2005/09/28 04:33:27 dan Exp $
17 % Definitions for most of the PDF operators.
18
19 .currentglobal true .setglobal
20
21 % Define pdfmark.  Don't allow it to be bound in.
22 % Also don't define it in systemdict, because this leads some Adobe code
23 % to think this interpreter is a distiller.
24 % (If this interpreter really is a distiller, don't do this.)
25 systemdict /pdfmark known not
26  { userdict /pdfmark { cleartomark } bind put } if
27
28 userdict /GS_PDF_ProcSet 127 dict dup begin
29
30 % ---------------- Abbreviations ---------------- %
31
32 /bdef { bind def } bind def
33
34 % ---------------- Graphics state stack ---------------- %
35
36 % PDF adds a number of parameters to the graphics state.
37 % We implement this by pushing and popping a dictionary
38 % each time we do a PDF gsave or grestore.
39 % The keys in this dictionary are as follows:
40 %       self                    % identifies the dictionary as one of ours
41 %       ClipRect                % (optional)
42 %       Show
43 %       TextSaveMatrix          % matrix at time of BT (iff within BT/ET)
44 % (The following correspond directly to PDF state parameters.)
45 %       AlphaIsShape
46 %       FillConstantAlpha
47 %       FillColor
48 %       FillColorSpace
49 %       FillOverprint
50 %       SoftMask
51 %       StrokeConstantAlpha
52 %       StrokeColor
53 %       StrokeColorSpace
54 %       StrokeOverprint
55 %       TextSpacing
56 %       TextHScaling
57 %       Leading
58 %       TextFont
59 %       TextLineMatrix
60 %       TextMatrix
61 %       TextRise
62 %       TextRenderingMode
63 %       WordSpacing
64
65 /nodict 1 dict def
66 nodict /self { //nodict } executeonly put
67 nodict readonly pop
68
69 /dictbeginpage {        % <initialdict> dictbeginpage -
70   //nodict 20 dict .copydict begin { def } forall
71   graphicsbeginpage textbeginpage
72 } bdef
73 /endpage {      % - endpage -
74   showpage end
75 } bdef
76
77 /graphicsbeginpage {
78   initgraphics
79   currentdict /ClipRect knownoget { aload pop rectclip } if
80   0 g  0 G  false op  false OP  0 OPM
81   1 ca  1 CA  null SMask  false AIS  /Compatible BM  true TK
82 } bdef
83
84 /gput           % <value> <key> gput -
85  { exch currentdict //nodict eq { /self dup load end 5 dict begin def } if
86                 % If we're in a Level 1 system, we need to grow the
87                 % dictionary explicitly.
88    currentdict length currentdict maxlength ge %eq
89     { currentdict dup length 3 mul 2 idiv 1 add dict .copydict end begin 
90     }
91    if def
92  } bdef
93
94 % Restore graphics state, but do not modify path. Paths are not part
95 % of the PDF graphics state; see 4.4.1 of PDF reference 3rd ed.
96 /grestore_nopath {
97   % Collect the upath with an identity CTM
98   { matrix setmatrix //false upath } stopped {
99     pop grestore newpath
100   } {
101     % Save the CTM, set identity during the uappend, then set the CTM
102     grestore matrix currentmatrix matrix setmatrix
103     exch newpath uappend setmatrix
104   } ifelse
105 } bdef
106
107 /q {
108   gsave //nodict begin
109 } bdef
110 % Some PDF files have excess Q operators!
111 /Q {
112   currentdict /self .knownget {
113     exec //nodict eq { end grestore_nopath false } { true } ifelse
114   } {
115     true        % formaterror -- not a gsave dict
116   } ifelse
117   { (\n   **** File has imbalanced q/Q operators \(too many Q's\) ****\n)
118     pdfformaterror
119   } if
120 } bdef
121
122 % Save PDF gstate
123 /qstate {       % - qstate <qstate>
124   gstate
125 } bdef
126
127 % Set PDF gstate
128 /setqstate {    % <qstate> setqstate -
129   { matrix setmatrix //false upath } stopped {
130     pop setgstate newpath
131   } {
132     % Save the CTM, set identity during the uappend, then set the CTM
133     exch setgstate matrix currentmatrix matrix setmatrix
134     exch newpath uappend setmatrix
135   } ifelse
136 } bdef
137
138 % ---------------- Color setting ---------------- %
139
140 /fcput          % <color> <colorspace> fcput -
141  { /FillColorSpace gput /FillColor gput
142  } bdef
143 /scput          % <color> <colorspace> scput -
144  { /StrokeColorSpace gput /StrokeColor gput
145  } bdef
146 /csput          % <colorspace> csput -
147  { csset 2 copy fcput scput
148  } bdef
149
150 /csdevgray [/DeviceGray] readonly def
151 /csdevrgb [/DeviceRGB] readonly def
152 /csdevcmyk [/DeviceCMYK] readonly def
153 /cspattern [/Pattern] readonly def
154 /nullpattern1 mark
155    /PatternType 1 /PaintType 1 /TilingType 3 /BBox [0 0 0 0]
156    /XStep 1 /YStep 1 /PaintProc { }
157 .dicttomark readonly def
158 /nullpattern2 nullpattern1 dup length dict copy readonly def
159
160 % Each entry in the color space dictionary is a procedure of the form
161 %       <cspace> -proc- <cspace> <initial-color>
162 /CSdict mark
163   /DeviceGray { pop //csdevgray 0 } bind
164   /DeviceRGB { pop //csdevrgb [0 0 0] cvx } bind
165   /DeviceCMYK { pop //csdevcmyk [0 0 0 1] cvx } bind
166   /CIEBasedA { 0 } bind
167   /CIEBasedABC { [0 0 0] cvx } bind
168   /ICCBased { [ 1 index 1 oget /N get { 0 } repeat ] cvx } bind
169   /Separation { 1 } bind
170   /DeviceN {    % What is the correct value??
171     [ 1 index 1 get length { 1 } repeat ] cvx
172   } bind
173   /Indexed { 0 } bind
174   /Pattern {
175     dup type /nametype eq 1 index length 1 eq or {
176       pop //cspattern //nullpattern1 matrix makepattern
177     } {
178       //nullpattern2 matrix makepattern 1 index 1 get csset
179                 % Stack: patternspace nullpattern basecolor basespace
180       pop [ 3 1 roll dup type /arraytype eq { aload pop } if
181       counttomark -1 roll ] cvx
182     } ifelse
183   } bind
184 .dicttomark readonly def
185 /csset                  % <cspace> csset <color> <cspace>
186  { dup dup type /nametype ne { 0 get } if //CSdict exch get exec exch
187  } bdef
188
189 /g { //csdevgray fcput } bdef
190 /G { //csdevgray scput } bdef
191 /rg { 3 array astore cvx //csdevrgb fcput } bdef
192 /RG { 3 array astore cvx //csdevrgb scput } bdef
193 /k { 4 array astore cvx //csdevcmyk fcput } bdef
194 /K { 4 array astore cvx //csdevcmyk scput } bdef
195 /cs { csset fcput } bdef
196 /CS { csset scput } bdef
197 /ri { pop } bdef
198 % We have to break up sc according to the number of operands.
199 /sc1 { /FillColor gput } bdef
200 /SC1 { /StrokeColor gput } bdef
201 % We have to avoid storing into a color array associated with an outer
202 % gsave level, so we do a kind of "copy on write".
203 /sc* {
204   currentdict /FillColor .knownget {
205     astore pop
206   } {
207     /FillColor load
208     % FillColor may contain either a single value or an array.
209     dup type /arraytype eq { length }{ pop 1 } ifelse
210     array astore cvx /FillColor gput
211   } ifelse
212 } bdef
213 /SC* {
214   currentdict /StrokeColor .knownget {
215     astore pop
216   } {
217     /StrokeColor load
218     % StrokeColor may contain either a single value or an array.
219     dup type /arraytype eq { length }{ pop 1 } ifelse
220     array astore cvx /StrokeColor gput
221   } ifelse
222 } bdef
223
224 % ---------------- Overprint/transparency setting ---------------- %
225
226 /op { /FillOverprint gput } bdef
227 /OP { /StrokeOverprint gput } bdef
228 /OPM {
229   /.setoverprintmode where { pop .setoverprintmode } { pop } ifelse
230 } bdef
231 /ca { /FillConstantAlpha gput } bdef
232 /CA { /StrokeConstantAlpha gput } bdef
233 /SMask { /SoftMask gput } bdef
234 /AIS { /AlphaIsShape gput } bdef
235 /BM {
236   /.setblendmode where {
237     pop [ exch dup type /nametype ne { aload pop } if /Normal ] {
238       { .setblendmode } .internalstopped not { exit } if pop
239     } forall
240   } {
241     pop
242   } ifelse
243 } bdef
244 /TK {
245   /.settextknockout where { pop .settextknockout } { pop } ifelse
246 } bdef
247
248 % ---------------- Color installation ---------------- %
249
250 % Establish a given color (and color space) as current.
251 /.settransparencyparams {       % <alpha> <smask> .settransparencyparams -
252   /.inittransparencymask where {
253     pop AlphaIsShape {
254       1 .setopacityalpha 0 .inittransparencymask exch .setshapealpha 1
255     } {
256       1 .setshapealpha 1 .inittransparencymask exch .setopacityalpha 0
257     } ifelse
258         % Set the soft mask by rendering the XObject.  Doing this every time
259         % is obviously very inefficient; we'll improve it later.
260     .settransparencymask    
261   } {
262     pop pop
263   } ifelse
264 } bdef
265 /.settransparencymask {         % <paramdict> <masknum> .settransparencymask -
266   exch dup null eq {
267     pop .inittransparencymask
268   } {
269     dup /Draw get exec
270   } ifelse
271 } bdef
272 % (Non-mask) images must execute setfillblend.
273 /setfillblend {
274   FillOverprint setoverprint
275   FillConstantAlpha SoftMask .settransparencyparams
276 } def
277 /setfillstate {
278   FillColor FillColorSpace setgcolor setfillblend
279 } def
280 /setstrokestate {
281   StrokeColor StrokeColorSpace setgcolor StrokeOverprint setoverprint
282   StrokeConstantAlpha SoftMask .settransparencyparams
283 } def
284 /Cdict 15 dict dup begin        % <color...> <colorspace> -proc- -
285   /DeviceGray { pop setgray } bdef
286   /DeviceRGB { pop setrgbcolor } bdef
287   /DeviceCMYK { pop setcmykcolor } bdef
288   /CIEBasedA { setgcolorspace setcolor } bdef
289   /CIEBasedABC /CIEBasedA load def
290   /CIEBasedDEF /CIEBasedA load def
291   /CIEBasedDEFG /CIEBasedA load def
292   /ICCBased /CIEBasedA load def
293   /Separation /CIEBasedA load def
294   /DeviceN /CIEBasedA load def
295   /Indexed /CIEBasedA load def
296   /Pattern
297    { setgcolorspace
298
299      % Since multiple patterns may share
300      % same data stream, we need to ensure
301      % that the stream is at 0 position.
302      % Making this consistently with resolveshading,
303      % which applies ReusableStreamDecode filter
304      % to the PS stream, which represents the
305      % PDF stream in dynamics.
306
307      dup /Shading knownoget {
308        dup /ShadingType oget 4 ge {
309          /DataSource knownoget {
310            dup type /filetype eq {
311              0 setfileposition
312            } {
313              pop
314            } ifelse
315          } if
316        } {
317         pop
318        } ifelse
319      } if
320
321      dup /Matrix knownoget not { matrix } if
322      gsave DefaultQstate setqstate makepattern grestore setcolor
323    } bdef
324 end def
325 /setgcolor      % (null | <color...>) <colorspace> setgcolor -
326  { 1 index null eq
327     { pop pop }
328     { dup 0 get //Cdict exch get exec }
329    ifelse
330  } bdef
331 % Compare the old and new color spaces in an attempt to avoid expensive
332 % reloads of CIEBased color spaces.
333 /PCSdict 15 dict dup begin      % <colorspace> -proc- <colorspace|pdfcspace>
334   /CIEBasedA { dup 1 get /PDFColorSpace .knownget { exch pop } if } bdef
335   /CIEBasedABC /CIEBasedA load def
336   /CIEBasedDEF /CIEBasedA load def
337   /CIEBasedDEFG /CIEBasedA load def
338   /Indexed {
339     dup 1 get dup pdfcolorspace 2 copy ne { 3 1 roll } if pop pop
340   } bdef
341 end def
342 /pdfcolorspace {        % <colorspace> pdfcolorspace <colorspace|pdfcspace>
343   dup type /arraytype eq {
344     //PCSdict 1 index 0 get .knownget { exec } if
345   } if
346 } bdef
347 /setgcolorspace {       % <colorspace> setgcolorspace -
348   dup pdfcolorspace currentcolorspace pdfcolorspace eq {
349     pop
350   } {
351     setcolorspace
352   } ifelse
353 } bdef
354 /fsexec         % <fillop|strokeop> fsexec -
355  {              % Preserve the current point, if any.
356     { currentpoint } stopped
357     { $error /newerror false put   cvx exec }
358     { 3 -1 roll cvx exec moveto }
359    ifelse
360  } bdef
361
362 % ---------------- Path painting and clipping ---------------- %
363
364 /S { setstrokestate /stroke fsexec } bdef
365 /f { setfillstate /fill fsexec } bdef
366 /f* { setfillstate /eofill fsexec } bdef
367 /n { newpath } bdef             % don't allow n to get bound in
368 /s { closepath S } bdef
369 /B { gsave setfillstate fill grestore S } bdef
370 /b { closepath B } bdef
371 /B* { gsave setfillstate eofill grestore S } bdef
372 /b* { closepath B* } bdef
373
374 % Clipping:
375
376 /Wdict 4 dict dup begin
377 /S { gsave setstrokestate stroke grestore n } bdef
378 /f { gsave setfillstate fill grestore n } bdef
379 /f* { gsave setfillstate eofill grestore n } bdef
380 /n { end clip newpath } bdef
381 end readonly def
382 /W { //Wdict begin } bdef
383 /W*dict 4 dict dup begin
384 Wdict { def } forall
385 /n { end eoclip newpath } bdef
386 end readonly def
387 /W* { //W*dict begin } bdef
388
389 % ---------------- Text control ---------------- %
390
391 /textbeginpage
392  { /TextSpacing 0 def           % 0 Tc
393    /TextLeading 0 def           % 0 TL
394    /TextRenderingMode 0 def     % 0 Tr
395    /TextRise 0 def              % 0 Ts
396    /WordSpacing 0 def           % 0 Tw
397    /TextHScaling 1.0 def        % 100 Tz
398    /TextFont null def
399    /Show { showfirst } def
400  } bdef
401
402 % Contrary to the statement in the PDF manual, BT and ET *can* be nested,
403 % if the CharProc for a Type 3 font does a BT/ET itself.
404 % Since we always call the CharProc inside a q/Q, we simply ensure that
405 % the text state is saved and restored like the rest of the extended
406 % graphics state.
407
408 /settextmatrix {
409   TextMatrix concat
410   TextHScaling 1 ne { TextHScaling 1 scale } if
411   TextRise 0 ne { 0 TextRise translate } if
412   TextFont dup null eq { pop } { setfont } ifelse
413 } bdef
414 /settextstate {
415         % The text state can be set even outside BT/ET.
416   currentdict /TextSaveMatrix known {
417     TextSaveMatrix setmatrix settextmatrix
418   } if
419 } bdef
420 /settextposition {
421                 % Update the TextMatrix translation.
422   gsave TextSaveMatrix setmatrix
423   currentpoint TextRise sub TextMatrix 4 2 getinterval astore pop
424                 % We would like to do "grestore currentpoint translate"
425                 % here, but some PDF files set a singular text matrix
426                 % (0 0 0 0 <x> <y> Tm), so we can't do this.
427   TextTempMatrix identmatrix setmatrix currentpoint
428   grestore
429   TextTempMatrix currentmatrix 4 2 getinterval astore pop
430   TextTempMatrix setmatrix
431 } bdef
432
433 /BT {
434   currentdict /TextLineMatrix .knownget
435     { identmatrix pop TextMatrix identmatrix pop }
436     { matrix /TextLineMatrix gput matrix /TextMatrix gput }
437   ifelse
438   { showfirst } /Show gput
439   currentdict /TextSaveMatrix .knownget not {
440     matrix dup /TextSaveMatrix gput
441   } if currentmatrix pop settextmatrix
442   matrix /TextTempMatrix gput           % see settextposition
443 } bdef
444 /ET {
445   TextRenderingMode 4 ge { clip newpath } if
446   TextSaveMatrix setmatrix
447   currentdict /TextSaveMatrix undef
448 } bdef
449 /Tc { /TextSpacing gput { showfirst } /Show gput } bdef
450 /TL { /TextLeading gput } bdef
451 /Tr { dup .settextrenderingmode /TextRenderingMode gput { showfirst } /Show gput } bdef
452 /Ts { /TextRise gput settextstate } bdef
453 /Tw { /WordSpacing gput { showfirst } /Show gput } bdef
454 /Tz { 100 div /TextHScaling gput settextstate} bdef
455
456 % ---------------- Font control ---------------- %
457
458 /Tf {           % <font> <scale> Tf -
459   dup 0 eq {
460     (\n   **** Warning: Invalid 0.0 font scale given for Tf ****\n)
461     pdfformaterror
462     pop 0.00000001      % handle invalid scale by using a really small value
463   } if
464   dup 1 eq { pop } { scalefont } ifelse
465   /TextFont gput settextstate
466 } bdef
467
468 % Read a CFF font.
469 /FRD            % <resname> <file> FRD -
470  { /FontSetInit /ProcSet findresource begin //true ReadData
471  } bdef
472
473 % Copy a font, removing its FID.  If changed is true, also remove
474 % the UniqueID and XUID, if any.  If the original dictionary doesn't have
475 % the keys being removed, don't copy it.
476 /.copyfontdict          % <font> <changed> .copyfontdict <dict>
477  { 1 index /FID known
478    1 index { 2 index /UniqueID known or 2 index /XUID known or } if
479     {           % We add 1 to the length just in case the original
480                 % didn't have a FID.
481       exch dup length 1 add dict exch
482        {                % Stack: changed newfont key value
483          1 index /FID eq 4 index
484           { 2 index /UniqueID eq or 2 index /XUID eq or }
485          if not { 3 copy put } if pop pop
486        }
487       forall exch
488     }
489    if pop
490  } bdef
491
492 % Insert a new Encoding or Metrics into a font if necessary.
493 % Return a possibly updated font, and a flag to indicate whether
494 % the font was actually copied.
495 /.updatefontmetrics {   % <font> <Metrics|null> .updatefontmetrics
496                         %   <font'> <copied>
497   dup //null ne {
498     exch //true .copyfontdict dup /Metrics 4 -1 roll put //true
499   } {
500     pop //false
501   } ifelse
502 } bdef
503
504 /.updatefontencoding {  % <font> <Encoding|null> .updatefontencoding
505                         %   <font'> <copied>
506   dup //null ne { dup 2 index /Encoding get ne } { //false } ifelse {
507     exch //false .copyfontdict dup /Encoding 4 -1 roll put //true
508   } {
509     pop //false
510   } ifelse
511 } bdef
512
513 % Duplicate keys in CharString dictionary according to GlyphMap: <</new_glyph /old_glyph>>
514 % We have to do this because PDF fonts can associate multiple widths with the same glyph
515 % but Metrics dictionary works by the glyph name.
516 /.update_charstring {   % <font> <GlyphMap> .update_charstring  <font'> <copied>
517   dup //null ne {
518     exch //true .copyfontdict       % map font
519     dup dup /CharStrings get        % map font font cstr
520     dup length                      % map font font cstr len
521     4 index length add              % map font font cstr len+map_len
522     dict copy dup begin             % map font font cstr'
523     /CharStrings exch put           % map font
524     exch {                          % font /new /old
525       currentdict exch .knownget {
526         def
527       } {
528         currentdict /.notdef .knownget {
529           def
530         } {
531           pop
532           % The font has no .notdef.
533           % Could not resolve the conflict,
534           % but either the font is invalid or the glyph name is never used.
535         } ifelse
536       } ifelse
537     } forall
538     end //true
539   } {
540     pop //false
541   } ifelse
542 } bdef
543
544 /.updatefont {        % <font> <Encoding|null> <Metrics|null> <GlyphMap|null>
545                       %        .updatefont <font'> <copied>
546   4 2 roll            % <Metrics|null> <GlyphMap> <font> <Encoding|null>
547   .updatefontencoding % <Metrics|null> <GlyphMap> <font> bool
548   4 1 roll exch       % bool <Metrics|null> <font> <GlyphMap>
549   .update_charstring  % bool <Metrics|null> <font> bool
550   3 1 roll exch       % bool bool <font> <Metrics|null>
551   .updatefontmetrics  % bool bool <font> bool
552   4 2 roll or or      % <font> is_copied
553 } bdef
554
555 % ---------------- Text positioning ---------------- %
556
557 /Td {
558   TextLineMatrix transform TextLineMatrix 4 2 getinterval astore pop
559   TextLineMatrix TextMatrix copy pop settextstate
560 } bdef
561 /TD { dup neg /TextLeading gput Td } bdef
562 /T* { 0 TextLeading neg Td } bdef
563 /Tm {
564   TextLineMatrix astore TextMatrix copy pop settextstate
565 } bdef
566
567 % ---------------- Text painting ---------------- %
568
569 /Vexch {
570   rootfont /WMode knownoget { 1 eq { exch } if } if
571 } bind def
572
573 /textrenderingprocs [           % (0 is handled specially)
574         % Painting-only modes
575    { tf } { tS } { tB } { tn }
576         % Clipping modes
577    { gsave tf grestore tW }
578    { gsave tS grestore tW }
579    { gsave tB grestore tW }
580    { tW }
581 ] readonly def
582 /setshowstate
583  { WordSpacing 0 eq TextSpacing 0 eq and
584     { TextRenderingMode 0 eq {
585         { setfillstate show }
586       } {
587         TextRenderingMode 3 eq {
588                 % Some PDF files execute 'tm' with a singular matrix,
589                 % and then use the text rendering mode 3.
590                 % The graphics library currently cannot handle text
591                 % operations when the CTM is singular.
592                 % Work around this here.
593           {     
594             matrix currentmatrix dup
595             dup 0 get 0 eq 1 index 1 get 0 eq and {
596               dup dup 2 get 0 eq { 0 }{ 1 } ifelse 1 put
597             } if
598             dup 2 get 0 eq 1 index 3 get 0 eq and {
599               dup dup 1 get 0 eq { 3 }{ 2 } ifelse 1 put
600             } if
601             setmatrix
602             1 index setfillstate show % Tr was set to graphic state.
603             setmatrix 
604             % now set the currentpoint using the original matrix
605             false charpath currentpoint newpath moveto
606           }
607         } {
608           { false charpath textrenderingprocs TextRenderingMode get exec }
609         } ifelse
610       } ifelse
611     }
612     { TextRenderingMode 0 eq TextRenderingMode 3 eq or
613        % Tr was set to graphic state.
614        { WordSpacing 0 eq
615           { { setfillstate TextSpacing 0 Vexch 3 -1 roll ashow } }
616           { TextSpacing 0 eq
617             { { setfillstate WordSpacing 0 Vexch 32 4 -1 roll widthshow } }
618             { { setfillstate WordSpacing 0 Vexch 32
619                  TextSpacing 0 Vexch 6 -1 roll awidthshow } }
620             ifelse
621           }
622          ifelse
623        }
624        { { WordSpacing TextSpacing
625                         % Implement the combination of t3 and false charpath.
626                         % Note that we must use cshow for this, because we
627                         % can't parse multi-byte strings any other way.
628                         % Stack: string xword xchar
629             { pop pop (x) dup 0 3 index put false charpath
630                         % Stack: xword xchar ccode
631              3 copy 32 eq { add } { exch pop } ifelse 0 Vexch rmoveto pop
632             }
633            4 -1 roll cshow pop pop
634            textrenderingprocs TextRenderingMode get exec
635          }
636        }
637       ifelse
638     }
639    ifelse /Show gput
640  } bdef
641 /showfirst { setshowstate Show } def
642
643 /Tj {
644   0 0 moveto Show settextposition
645 } bdef
646 /' { T* Tj } bdef
647 /" { exch Tc exch Tw T* Tj } bdef
648 /TJ {
649   0 0 moveto {
650     dup type /stringtype eq {
651       Show
652     } { -1000 div
653       currentfont /ScaleMatrix .knownget { 0 get mul } if
654       0 Vexch rmoveto
655     } ifelse
656   } forall settextposition
657 } bdef
658
659 /tf { setfillstate currentpoint fill moveto } bdef
660 /tn { currentpoint newpath moveto } bdef % Obsolete, never used.
661 % For stroking characters, temporarily restore the graphics CTM so that
662 % the line width will be transformed properly.
663 /Tmatrix matrix def
664 /tS
665  { setstrokestate
666    currentpoint //Tmatrix currentmatrix TextSaveMatrix setmatrix stroke
667    setmatrix moveto
668  } bdef
669 /tB { gsave tf grestore tS } bdef
670 % This does the wrong thing if there have been multiple text operations
671 % within a single BT/ET pair, but it's a start.
672 /tW { } bdef
673
674 end readonly put                % GS_PDF_ProcSet
675
676 .setglobal