summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlgs/lib/pdf_ops.ps
blob: 6f286041a98c25a1d84dc52e13e048fc2469bc50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
%    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
% 
% This software is provided AS-IS with no warranty, either express or
% implied.
% 
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
% 
% For more information about licensing, please refer to
% http://www.ghostscript.com/licensing/. For information on
% commercial licensing, go to http://www.artifex.com/licensing/ or
% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
% San Rafael, CA  94903, U.S.A., +1(415)492-9861.

% $Id: pdf_ops.ps 8554 2008-02-27 19:36:18Z leonardo $
% Definitions for most of the PDF operators.

.currentglobal true .setglobal

% Define pdfmark.  Don't allow it to be bound in.
% Also don't define it in systemdict, because this leads some Adobe code
% to think this interpreter is a distiller.
% (If this interpreter really is a distiller, don't do this.)
systemdict /pdfmark known not
 { userdict /pdfmark { cleartomark } bind put } if

userdict /GS_PDF_ProcSet 127 dict dup begin

% ---------------- Abbreviations ---------------- %

/bdef { bind def } bind def

% ---------------- Graphics state stack ---------------- %

% PDF adds a number of parameters to the graphics state.
% We implement this by pushing and popping a dictionary
% each time we do a PDF gsave or grestore.
% The keys in this dictionary are as follows:
%	self			% identifies the dictionary as one of ours
%	ClipRect		% (optional)
%	Show
%	TextSaveMatrix		% matrix at time of BT (iff within BT/ET)
% (The following correspond directly to PDF state parameters.)
%	AlphaIsShape
%	FillConstantAlpha
%	FillColor
%	FillColorSpace
%	FillOverprint
%	SoftMask
%	StrokeConstantAlpha
%	StrokeColor
%	StrokeColorSpace
%	StrokeOverprint
%	TextSpacing
%	TextHScaling
%	Leading
%	TextFont
%	TextLineMatrix
%	TextMatrix
%	TextRise
%	TextRenderingMode
%	WordSpacing
% (The following is cached information derived from other graphics state params)
%	FontMatrixNonHV % TextFont.FontMatrix alters horz/vert glyph advance vector direction

/nodict 1 dict def
nodict /self { //nodict } executeonly put
nodict readonly pop

/dictbeginpage {	% <initialdict> dictbeginpage -
  //nodict 20 dict .copydict begin { def } forall
  graphicsbeginpage textbeginpage
} bdef
/endpage {	% - endpage -
  showpage end
} bdef

/graphicsbeginpage {
  initgraphics
  //true .setaccuratecurves
  currentdict /ClipRect knownoget { aload pop rectclip } if
  0 g  0 G  false op  false OP  0 OPM
  1 ca  1 CA  null SMask  false AIS  /Compatible BM  true TK
} bdef

/gput		% <value> <key> gput -
 { exch currentdict //nodict eq { /self dup load end 5 dict begin def } if
		% If we're in a Level 1 system, we need to grow the
		% dictionary explicitly.
   currentdict length currentdict maxlength ge %eq
    { currentdict dup length 3 mul 2 idiv 1 add dict .copydict end begin 
    }
   if def
 } bdef

% Restore graphics state, but do not modify path. Paths are not part
% of the PDF graphics state; see 4.4.1 of PDF reference 3rd ed.
/grestore_nopath {
  % Collect the upath with an identity CTM
    matrix setmatrix .getpath
    % Save the CTM, set identity during the uappend, then set the CTM
    grestore matrix currentmatrix matrix setmatrix
    exch newpath { exec } forall setmatrix
} bdef

/q {
  gsave //nodict begin
} bdef
% Some PDF files have excess Q operators!
/Q {
  currentdict /self .knownget {
    exec //nodict eq { end grestore_nopath false } { true } ifelse
  } {
    true	% formaterror -- not a gsave dict
  } ifelse
  { (\n   **** File has imbalanced q/Q operators \(too many Q's\) ****\n)
    pdfformaterror
  } if
} bdef

% Save PDF gstate
/qstate {       % - qstate <qstate>
  gstate
} bdef

% Set PDF gstate
/setqstate {    % <qstate> setqstate -
  { matrix setmatrix //false upath } stopped {
    pop setgstate newpath
  } {
    % Save the CTM, set identity during the uappend, then set the CTM
    exch setgstate matrix currentmatrix matrix setmatrix
    exch newpath uappend setmatrix
  } ifelse
} bdef

% ---------------- Color setting ---------------- %

/fcput		% <color> <colorspace> fcput -
 { /FillColorSpace gput /FillColor gput
 } bdef
/scput		% <color> <colorspace> scput -
 { /StrokeColorSpace gput /StrokeColor gput
 } bdef
/csput		% <colorspace> csput -
 { csset 2 copy fcput scput
 } bdef

/csdevgray [/DeviceGray] readonly def
/csdevrgb [/DeviceRGB] readonly def
/csdevcmyk [/DeviceCMYK] readonly def
/cspattern [/Pattern] readonly def
/nullpattern1 mark
   /PatternType 1 /PaintType 1 /TilingType 3 /BBox [0 0 1 1]
   /XStep 1 /YStep 1 /PaintProc { pop } bind
.dicttomark readonly def
/nullpattern2 nullpattern1 dup length dict copy readonly def

% Each entry in the color space dictionary is a procedure of the form
%	<cspace> -proc- <cspace> <initial-color>
/CSdict mark
  /DeviceGray { pop //csdevgray 0 } bind
  /DeviceRGB { pop //csdevrgb [0 0 0] cvx } bind
  /DeviceCMYK { pop //csdevcmyk [0 0 0 1] cvx } bind
  /CIEBasedA { 0 } bind
  /CIEBasedABC { [0 0 0] cvx } bind
  /ICCBased { [ 1 index 1 oget /N get { 0 } repeat ] cvx } bind
  /Separation { 1 } bind
  /DeviceN {	% What is the correct value??
    [ 1 index 1 get length { 1 } repeat ] cvx
  } bind
  /Indexed { 0 } bind
  /Pattern {
    dup type /nametype eq 1 index length 1 eq or {
      pop //cspattern //nullpattern1 matrix makepattern
    } {
      //nullpattern2 matrix makepattern 1 index 1 get csset
		% Stack: patternspace nullpattern basecolor basespace
      pop [ 3 1 roll dup type /arraytype eq { aload pop } if
      counttomark -1 roll ] cvx
    } ifelse
  } bind
.dicttomark readonly def
/csset			% <cspace> csset <color> <cspace>
 { dup dup type /nametype ne { 0 get } if //CSdict exch get exec exch
 } bdef

/g { //csdevgray fcput } bdef
/G { //csdevgray scput } bdef
/rg { 3 array astore cvx //csdevrgb fcput } bdef
/RG { 3 array astore cvx //csdevrgb scput } bdef
/k { 4 array astore cvx //csdevcmyk fcput } bdef
/K { 4 array astore cvx //csdevcmyk scput } bdef
/cs { csset fcput } bdef
/CS { csset scput } bdef
/ri { //.renderingintentdict exch .knownget { .setrenderingintent } if } bdef
% We have to break up sc according to the number of operands.
/sc1 { /FillColor gput } bdef
/SC1 { /StrokeColor gput } bdef
% We have to avoid storing into a color array associated with an outer
% gsave level, so we do a kind of "copy on write".
/sc* {
  currentdict /FillColor .knownget {
    astore pop
  } {
    /FillColor load
    % FillColor may contain either a single value or an array.
    dup type /arraytype eq { length }{ pop 1 } ifelse
    array astore cvx /FillColor gput
  } ifelse
} bdef
/SC* {
  currentdict /StrokeColor .knownget {
    astore pop
  } {
    /StrokeColor load
    % StrokeColor may contain either a single value or an array.
    dup type /arraytype eq { length }{ pop 1 } ifelse
    array astore cvx /StrokeColor gput
  } ifelse
} bdef

% ---------------- Overprint/transparency setting ---------------- %

/op { /FillOverprint gput } bdef
/OP { /StrokeOverprint gput } bdef
/OPM {
  /.setoverprintmode where { pop .setoverprintmode } { pop } ifelse
} bdef
/ca { /FillConstantAlpha gput } bdef
/CA { /StrokeConstantAlpha gput } bdef
/SMask { /SoftMask gput } bdef
/AIS { /AlphaIsShape gput } bdef
/BM {
  /.setblendmode where {
    pop [ exch dup type /nametype ne { aload pop } if /Normal ] {
      { .setblendmode } .internalstopped not { exit } if pop
    } forall
  } {
    pop
  } ifelse
} bdef
/TK {
  /.settextknockout where { pop .settextknockout } { pop } ifelse
} bdef

% ---------------- Color installation ---------------- %

% Establish a given color (and color space) as current.
/.settransparencyparams {	% <alpha> <smask> .settransparencyparams -
  PDFusingtransparency {
    /.begintransparencygroup where {
      pop AlphaIsShape {
        1 .setopacityalpha  exch .setshapealpha 1
      } {
        1 .setshapealpha  exch .setopacityalpha 0
      } ifelse
	% Set the soft mask by rendering the XObject.  Doing this every time
	% is obviously very inefficient; we'll improve it later.
      .settransparencymask    
    } {
      pop pop
    } ifelse
  } {
    pop pop
  } ifelse
} bdef
/.settransparencymask {		% <paramdict> <masknum> .settransparencymask -
  exch dup null eq {
    PDFusingtransparency {
      pop pop
    } {
      dup /Draw get exec
    } ifelse
  } {
    dup /Draw get exec
  } ifelse
} bdef
% (Non-mask) images must execute setfillblend.
/setfillblend {
  FillOverprint setoverprint
  FillConstantAlpha SoftMask .settransparencyparams
} def
/setfillstate {
  FillColor FillColorSpace setgcolor setfillblend
} def
/setstrokestate {
  StrokeColor StrokeColorSpace setgcolor StrokeOverprint setoverprint
  StrokeConstantAlpha SoftMask .settransparencyparams
} def
/Cdict 15 dict dup begin	% <color...> <colorspace> -proc- -
  /DeviceGray { pop setgray } bdef
  /DeviceRGB { pop setrgbcolor } bdef
  /DeviceCMYK { pop setcmykcolor } bdef
  /CIEBasedA { setgcolorspace setcolor } bdef
  /CIEBasedABC /CIEBasedA load def
  /CIEBasedDEF /CIEBasedA load def
  /CIEBasedDEFG /CIEBasedA load def
  /ICCBased /CIEBasedA load def
  /Separation /CIEBasedA load def
  /DeviceN /CIEBasedA load def
  /Indexed /CIEBasedA load def
  /Pattern
   { setgcolorspace

     % Since multiple patterns may share
     % same data stream, we need to ensure
     % that the stream is at 0 position.
     % Making this consistently with resolveshading,
     % which applies ReusableStreamDecode filter
     % to the PS stream, which represents the
     % PDF stream in dynamics.

     dup /Shading knownoget {
       dup /ShadingType oget 4 ge {
         /DataSource knownoget {
           dup type /filetype eq {
             0 setfileposition
           } {
             pop
           } ifelse
         } if
       } {
        pop
       } ifelse
     } if

     dup /Matrix knownoget not { matrix } if
     gsave DefaultQstate setqstate makepattern grestore setcolor
   } bdef
end def
/setgcolor	% (null | <color...>) <colorspace> setgcolor -
 { 1 index null eq
    { pop pop }
    { dup 0 get //Cdict exch get exec }
   ifelse
 } bdef
% Compare the old and new color spaces in an attempt to avoid expensive
% reloads of CIEBased color spaces.
/PCSdict 15 dict dup begin	% <colorspace> -proc- <colorspace|pdfcspace>
  /CIEBasedA { dup 1 get /PDFColorSpace .knownget { exch pop } if } bdef
  /CIEBasedABC /CIEBasedA load def
  /CIEBasedDEF /CIEBasedA load def
  /CIEBasedDEFG /CIEBasedA load def
  /Indexed {
    dup 1 get dup pdfcolorspace 2 copy ne { 3 1 roll } if pop pop
  } bdef
end def
/pdfcolorspace {	% <colorspace> pdfcolorspace <colorspace|pdfcspace>
  dup type /arraytype eq {
    //PCSdict 1 index 0 get .knownget { exec } if
  } if
} bdef
/setgcolorspace {	% <colorspace> setgcolorspace -
  dup pdfcolorspace currentcolorspace pdfcolorspace eq {
    pop
  } {
    setcolorspace
  } ifelse
} bdef
/fsexec		% <fillop|strokeop> fsexec -
 {		% Preserve the current point, if any.
    { currentpoint } stopped
    { $error /newerror false put   cvx exec }
    { 3 -1 roll cvx exec moveto }
   ifelse
 } bdef

% ---------------- Path painting and clipping ---------------- %

/S { setstrokestate /stroke fsexec } bdef
/f { setfillstate /fill fsexec } bdef
/f* { setfillstate /eofill fsexec } bdef
/n { newpath } bdef		% don't allow n to get bound in
/s { closepath S } bdef
/B { gsave setfillstate fill grestore S } bdef
/b { closepath B } bdef
/B* { gsave setfillstate eofill grestore S } bdef
/b* { closepath B* } bdef

% Clipping:

/Wdict 4 dict dup begin
/S { gsave setstrokestate stroke grestore n } bdef
/f { gsave setfillstate fill grestore n } bdef
/f* { gsave setfillstate eofill grestore n } bdef
/n { end clip newpath } bdef
end readonly def
/W { //Wdict begin } bdef
/W*dict 4 dict dup begin
Wdict { def } forall
/n { end eoclip newpath } bdef
end readonly def
/W* { //W*dict begin } bdef

% ---------------- Text control ---------------- %

/textbeginpage
 { /TextSpacing 0 def		% 0 Tc
   /TextLeading 0 def		% 0 TL
   /TextRenderingMode 0 def	% 0 Tr
   /TextRise 0 def		% 0 Ts
   /WordSpacing 0 def		% 0 Tw
   /TextHScaling 1.0 def	% 100 Tz
   /TextFont null def
   /FontMatrixNonHV //false def
   /Show { showfirst } def
 } bdef

% Contrary to the statement in the PDF manual, BT and ET *can* be nested,
% if the CharProc for a Type 3 font does a BT/ET itself.
% Since we always call the CharProc inside a q/Q, we simply ensure that
% the text state is saved and restored like the rest of the extended
% graphics state.

/settextmatrix {
  TextMatrix concat
  TextHScaling 1 ne { TextHScaling 1 scale } if
  TextRise 0 ne { 0 TextRise translate } if
  TextFont dup null eq { pop } { setfont } ifelse
} bdef
/settextstate {
	% The text state can be set even outside BT/ET.
  currentdict /TextSaveMatrix known {
    TextSaveMatrix setmatrix settextmatrix
  } if
} bdef
/settextposition {
		% Update the TextMatrix translation.
  gsave TextSaveMatrix setmatrix
  currentpoint TextRise sub TextMatrix 4 2 getinterval astore pop
		% We would like to do "grestore currentpoint translate"
		% here, but some PDF files set a singular text matrix
		% (0 0 0 0 <x> <y> Tm), so we can't do this.
  TextTempMatrix identmatrix setmatrix currentpoint
  grestore
  TextTempMatrix currentmatrix 4 2 getinterval astore pop
  TextTempMatrix setmatrix
} bdef

/BT {
  currentdict /TextLineMatrix .knownget
    { identmatrix pop TextMatrix identmatrix pop }
    { matrix /TextLineMatrix gput matrix /TextMatrix gput }
  ifelse
  { showfirst } /Show gput
  currentdict /TextSaveMatrix .knownget not {
    matrix dup /TextSaveMatrix gput
  } if currentmatrix pop settextmatrix
  matrix /TextTempMatrix gput		% see settextposition
} bdef
/ET {
  TextRenderingMode 4 ge { clip newpath } if
  TextSaveMatrix setmatrix
  currentdict /TextSaveMatrix undef
} bdef
/Tc { /TextSpacing gput { showfirst } /Show gput } bdef
/TL { /TextLeading gput } bdef
/Tr { dup .settextrenderingmode /TextRenderingMode gput { showfirst } /Show gput } bdef
/Ts { /TextRise gput settextstate } bdef
/Tw { /WordSpacing gput { showfirst } /Show gput } bdef
/Tz { 100 div /TextHScaling gput settextstate} bdef

% ---------------- Font control ---------------- %

% Test if the FontMatrix could transform a horizontal/vertical (depending
% on writing mode) advance vector in glyph space into one with a different
% direction in text space.
% - if FontMatrix = [a b c d tx ty], this condition translates to:
%       b != 0 for horizontal writing mode
%       c != 0 for vertical writing mode
% - when false, we automatically have wy/x == 0 in text space whenever wy/x == 0
%   in glyph space, and can avoid the slow method that is otherwise necessary
%   to implement zeroing wy/x cf PDF Ref 5.3.3 "Text space details"
    % Worker procedure for testing a single font matrix
/?FontMatrixNonHV {		    % ?horz <<fontdict>> -- ?horz ?nonhv
    /FontMatrix .knownget {
	1 index { 1 } { 2 } ifelse get 0 ne
    } {
	//false
    } ifelse
} bdef
    % Worker procedure for recursive checking of font matrices
/?FontMatrixNonHV {		    % {self} ?horz <<font>> -- {self} ?horz ?nonhv
    2 copy //?FontMatrixNonHV exec {	    % check the font's own FontMatrix
	pop pop //true
    } {
	% look for descendents/ components
	pop				    % {self} ?horz <<font>>
	dup /FontType get
	dup 0 eq {			    % Type 0: look into FDepVector
	    pop /FDepVector get 2 index	    % {self} ?horz [fonts..] {testproc}
	} {
	    9 eq {			    % Type 9 (CIDFontType 0): check FDArray
		/FDArray get //?FontMatrixNonHV
	    } {				    % all others: nothing more to check
		pop {} {}
	    } ifelse
	} ifelse
	%stack: {self} ?horz [fonts..] {testproc}
	//false 5 2 roll {		    % {testproc} false {self} ?horz <<subfont>>
	    4 index exec {
		4 -1 roll pop //true 4 1 roll
		exit
	    } if
	} forall
	%stack: {testproc} ?nonhv {self} ?horz
	4 2 roll exch pop
    } ifelse
} bdef
    % Main procedure
/?FontMatrixNonHV {		% <<rootfont>> -- ?nonhv
    //?FontMatrixNonHV exch
    % determine WMode
    dup /WMode .knownget { 0 eq } { //true } ifelse % {proc} <<rootfont>> ?horz
    exch
    % call the worker procedure
    //?FontMatrixNonHV exec
    exch pop exch pop
} bdef

/Tf {		% <font> <scale> Tf -
  dup 0 eq {
    (\n   **** Warning: Invalid 0.0 font scale given for Tf ****\n)
    pdfformaterror
    pop 0.00000001	% handle invalid scale by using a really small value
  } if
  1 index type /dicttype ne {
    selectfont currentfont
  } {
    dup 1 eq { pop } { scalefont } ifelse
  }
  ifelse
  dup ?FontMatrixNonHV dup FontMatrixNonHV ne {
    /FontMatrixNonHV gput
    { showfirst } /Show gput
  } {
    pop
  } ifelse
  /TextFont gput settextstate
} bdef

% Read a CFF font.
/FRD		% <resname> <file> FRD -
 { /FontSetInit /ProcSet findresource begin //true ReadData
 } bdef

% Copy a font, removing its FID.  If changed is true, also remove
% the UniqueID and XUID, if any.  If the original dictionary doesn't have
% the keys being removed, don't copy it.
/.copyfontdict		% <font> <changed> .copyfontdict <dict>
 { 1 index /FID known
   1 index { 2 index /UniqueID known or 2 index /XUID known or } if
    {		% We add 1 to the length just in case the original
		% didn't have a FID.
      exch dup length 1 add dict exch
       {		% Stack: changed newfont key value
	 1 index /FID eq 4 index
	  { 2 index /UniqueID eq or 2 index /XUID eq or }
	 if not { 3 copy put } if pop pop
       }
      forall exch
    }
   if pop
 } bdef

% Insert a new Encoding or Metrics into a font if necessary.
% Return a possibly updated font, and a flag to indicate whether
% the font was actually copied.
/.updatefontmetrics {	% <font> <Metrics|null> .updatefontmetrics
			%   <font'> <copied>
  dup //null ne {
    exch //true .copyfontdict dup /Metrics 4 -1 roll put //true
  } {
    pop //false
  } ifelse
} bdef

/.updatefontencoding {	% <font> <Encoding|null> .updatefontencoding
			%   <font'> <copied>
  dup //null ne { dup 2 index /Encoding get ne } { //false } ifelse {
    exch //false .copyfontdict dup /Encoding 4 -1 roll put //true
  } {
    pop //false
  } ifelse
} bdef

% Duplicate keys in CharString dictionary according to GlyphMap: <</new_glyph /old_glyph>>
% We have to do this because PDF fonts can associate multiple widths with the same glyph
% but Metrics dictionary works by the glyph name.
/.update_charstring {	% <font> <GlyphMap> .update_charstring  <font'> <copied>
  dup //null ne {
    exch //true .copyfontdict       % map font
    dup dup /CharStrings get        % map font font cstr
    dup length                      % map font font cstr len
    4 index length add              % map font font cstr len+map_len
    dict copy dup begin             % map font font cstr'
    /CharStrings exch put           % map font
    exch {                          % font /new /old
      currentdict exch .knownget {
        def
      } {
        currentdict /.notdef .knownget {
          def
        } {
          pop
          % The font has no .notdef.
          % Could not resolve the conflict,
          % but either the font is invalid or the glyph name is never used.
        } ifelse
      } ifelse
    } forall
    end //true
  } {
    pop //false
  } ifelse
} bdef

/.updatefont {	      % <font> <Encoding|null> <Metrics|null> <GlyphMap|null>
                      %        .updatefont <font'> <copied>
  4 2 roll            % <Metrics|null> <GlyphMap> <font> <Encoding|null>
  .updatefontencoding % <Metrics|null> <GlyphMap> <font> bool
  4 1 roll exch       % bool <Metrics|null> <font> <GlyphMap>
  .update_charstring  % bool <Metrics|null> <font> bool
  3 1 roll exch       % bool bool <font> <Metrics|null>
  .updatefontmetrics  % bool bool <font> bool
  4 2 roll or or      % <font> is_copied
} bdef

% ---------------- Text positioning ---------------- %

/Td {
  TextLineMatrix transform TextLineMatrix 4 2 getinterval astore pop
  TextLineMatrix TextMatrix copy pop settextstate
} bdef
/TD { dup neg /TextLeading gput Td } bdef
/T* { 0 TextLeading neg Td } bdef
/Tm {
  TextLineMatrix astore TextMatrix copy pop settextstate
} bdef

% ---------------- Text painting ---------------- %

/Vexch {
  rootfont /WMode knownoget { 1 eq { exch } if } if
} bind def

/textrenderingprocs [		% (0 is handled specially)
	% Painting-only modes
   { tf } { tS } { tB } { tn }
	% Clipping modes
   { gsave tf grestore tW }
   { gsave tS grestore tW }
   { gsave tB grestore tW }
   { tW }
] readonly def

/pdfwrite_textrenderingprocs [
	{ setfillstate show } bind
	{ setstrokestate show } bind
	{ gsave 0 .settextrenderingmode 
	  setfillstate dup show currentpoint 3 -1 roll 
	  grestore gsave setstrokestate false charpath stroke 
	  grestore moveto
	} bind
	{ setfillstate show } bind
	{ gsave 0 .settextrenderingmode 
	  setfillstate dup show grestore true charpath } bind
	{ gsave 1 .settextrenderingmode 
	  setstrokestate dup show grestore
	  true charpath } bind
	{ gsave 0 .settextrenderingmode 
	  setfillstate dup show grestore gsave dup 
	  setstrokestate false charpath stroke grestore 
	  true charpath } bind
	{ true charpath } bind
] readonly def

/setshowstate
 { WordSpacing 0 eq TextSpacing 0 eq and FontMatrixNonHV not and
    { 
	currentdevice .devicename /pdfwrite eq 
	{
		pdfwrite_textrenderingprocs TextRenderingMode get
	}
	{
		TextRenderingMode 0 eq {
	        { setfillstate show }
	      } {
	        TextRenderingMode 3 eq {
	            	% Some PDF files execute 'tm' with a singular matrix,
			% and then use the text rendering mode 3.
			% The graphics library currently cannot handle text
			% 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
	            2 index setfillstate show % Tr was set to graphic state.
	            setmatrix 
		    % now set the currentpoint using the original matrix
	            gsave nulldevice
	            setmatrix
	            false charpath currentpoint newpath 
	            grestore
	            moveto
	          }
	        } {
	          { false charpath textrenderingprocs TextRenderingMode get exec }
	        } ifelse
	      } ifelse
	} ifelse
    }
    { TextRenderingMode 0 eq TextRenderingMode 3 eq or
       % Tr was set to graphic state.
       { FontMatrixNonHV {
           {
             setfillstate
             [ TextSpacing WordSpacing 3 index
               {					    % str [... weach wword c undef|ythis xthis|undef
		 exch % will be removed, unless FontMatrix.xx/yy == 0 (FontMatrixNonHV already true)
                 Vexch pop                                  % str [... weach wword c wthis
                 3 index add exch 32 eq {1 index add} if    % str [... weach wword w
                 3 1 roll                                   % str [... w weach wword
               }
               % for the "exch" removed or not below, see comment in pdf_font.ps::getfontmetrics
	       currentfont /FontMatrix get 0 3 Vexch pop get 0 ne {
	         1 1 index length 1 sub getinterval cvx
	       } if
	       cshow pop pop ]
             { xshow } { yshow } Vexch pop exec
           }
         } {
           WordSpacing 0 eq
            { { setfillstate TextSpacing 0 Vexch 3 -1 roll ashow } }
	    { TextSpacing 0 eq
              { { setfillstate WordSpacing 0 Vexch 32 4 -1 roll widthshow } }
              { { setfillstate WordSpacing 0 Vexch 32
                   TextSpacing 0 Vexch 6 -1 roll awidthshow } }
	      ifelse
	    }
	   ifelse
         } ifelse
       }
       { { WordSpacing TextSpacing
			% Implement the combination of t3 and false charpath.
			% Note that we must use cshow for this, because we
			% can't parse multi-byte strings any other way.
			% Stack: string wword wchar
	    {
	     exch % will be removed, unless FontMatrixNonHV && FontMatrix.xx/yy == 0
			% Stack: str wword wchar ccode xthis ythis
	     Vexch pop currentpoint 6 3 roll
			% Stack: str wthis xorig yorig wword wchar ccode
	     (x) dup 0 3 index put //false charpath
             3 copy 32 eq { add } { exch pop } ifelse
			% Stack: str wthis xorig yorig wword wchar ccode wextra
             7 -3 roll moveto add
             0 Vexch rmoveto pop
	    }
            % for the "exch" removed or not below, see comment in pdf_font.ps::getfontmetrics
	    FontMatrixNonHV dup not exch {
	      currentfont /FontMatrix get 0 3 Vexch pop get 0 ne
	    } if {
	      1 1 index length 1 sub getinterval cvx
	    } if
	   4 -1 roll cshow pop pop
	   textrenderingprocs TextRenderingMode get exec
	 }
       }
      ifelse
    }
   ifelse /Show gput
 } bdef
/showfirst { setshowstate Show } def

/Tj {
  0 0 moveto Show settextposition
} bdef
/' { T* Tj } bdef
/" { exch Tc exch Tw T* Tj } bdef
/TJ {
  0 0 moveto {
    dup type /stringtype eq {
      Show
    } { -1000 div
      currentfont /ScaleMatrix .knownget { 0 get mul } if
      0 Vexch rmoveto
    } ifelse
  } forall settextposition
} bdef

/tf { setfillstate currentpoint fill moveto } bdef
/tn { currentpoint newpath moveto } bdef % Obsolete, never used.
% For stroking characters, temporarily restore the graphics CTM so that
% the line width will be transformed properly.
/Tmatrix matrix def
/tS
 { setstrokestate
   currentpoint //Tmatrix currentmatrix TextSaveMatrix setmatrix stroke
   setmatrix moveto
 } bdef
/tB { gsave tf grestore tS } bdef
% This does the wrong thing if there have been multiple text operations
% within a single BT/ET pair, but it's a start.
/tW { } bdef

% Text formatting and painting for the AcroForm field without appearance streams.
/Tform {                % <MaxLen> (V) <Ff> <Q> Tform -
  clippath pathbbox 4 2 roll pop pop                        % MaxLen (V) Ff Q dx dy
  currentfont /ScaleMatrix .knownget { 3 get } { 1 } ifelse % MaxLen (V) Ff Q dx dy yy
  currentfont /FontBBox get dup 1 get neg exch 3 get        % MaxLen (V) Ff Q dx dy yy desc asc
  dup 0 ne { div } { pop pop 0 } ifelse                     % MaxLen (V) Ff Q dx dy yy desc/asc
  1 index mul                                               % MaxLen (V) Ff Q dx dy yy desc/asc*yy

  4 index 16#1000 and 0 ne { % multiline
    8 { pop } repeat (Multiline form fields are not yet implemented.) =
  } {
    4 index 16#1000000 and 0 ne { % comb
      8 { pop } repeat (Combed form fields are not yet implemented.) =
    } { % plain text                                       
      3 1 roll sub add 2 div             % MaxLen (V) Ff Q dx (dy-yy+desc)/2
      0 exch moveto                      % MaxLen (V) Ff Q dx
      1 index 0 ne {
        3 index stringwidth pop          % MaxLen (V) Ff Q dx w
        sub exch 1 eq { 2 div } { 2 sub } ifelse % MaxLen (V) Ff (dx-w)/2
        0 rmoveto                        % MaxLen (V) Ff
        pop                              % MaxLen (V)
      } {
        pop pop pop                      % MaxLen (V)
        2 0 rmoveto
      } ifelse
      exch pop Show                      % -
    } ifelse
  } ifelse
} bdef

end readonly put		% GS_PDF_ProcSet

.setglobal