summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlgs/Resource/Init/gs_dps.ps
blob: cad7056230da8b941c2ce2e7357425cad84e5f05 (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
% Copyright (C) 2001-2018 Artifex Software, Inc.
% All Rights Reserved.
%
% This software is provided AS-IS with no warranty, either express or
% implied.
%
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
%
% Refer to licensing information at http://www.artifex.com or contact
% Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
% CA 94945, U.S.A., +1(415)492-9861, for further information.
%

% Initialization file for Display PostScript functions.

% ------ Errors ------ %

% These errors are only defined in DPS.
{ /invalidcontext /invalidid } { .registererror } forall

% ------ Contexts ------ %

% To create a context with private local VM, we use the .localfork
% operator to actually create the context, the new VM, and an empty
% userdict, and then we call the .initlocaldicts procedure to make
% local copies of the initial contents of the dictionaries in local VM.
% savedlocaldicts in systemdict is a global read-only dictionary whose
% elements are global read-only copies of these initial contents;
% we just copy its elements into local VM and install them in systemdict.
% userdict and internaldict require special handling.

% Switching between contexts with different local VMs requires
% changing the bindings in systemdict that reference local objects.
% For this purpose, each userdict has an entry called localdicts
% which holds the local copies of the elements of savedlocaldicts,
% plus internaldict.  The context switching code in the interpreter
% effectively copies this dictionary into systemdict.
% NOTE: the name localdicts is known to the interpreter.

% Switching between contexts also requires resetting the user parameters.
% The interpreter records the value of userparams (a local dictionary
% referenced from systemdict) for each context, and uses it for this.
% See gs_lev2.ps for more details.
% NOTE: the name userparams is known to the interpreter.

% Save copies of local dictionaries at the end of system initialization.
% Also save the initial gstate.
/.savelocalstate {
  .currentglobal //true .setglobal
  //systemdict /savedlocaldicts mark //systemdict {
    dup gcheck {
      pop pop
    } {
      dup type /dicttype eq {
                % Save a copy of this dictionary in global VM.
        dup maxlength dict .copydict readonly
      } {
        pop pop
      } ifelse
    } ifelse
  } forall .dicttomark readonly put
                % Create localdicts for the current context.
  //false .setglobal
  userdict /localdicts mark savedlocaldicts {
    pop dup load
  } forall /internaldict dup load
  .dicttomark readonly put
                % Save a copy of the initial gstate.
  //systemdict /savedinitialgstate gstate readonly .forceput
  .setglobal
} .bind executeonly def % must be bound and hidden for .forceput

% Initialize local dictionaries and gstate when creating a new context.
% Note that until this completes, we are in the anomalous situation of
% having systemdict point to dictionaries that are in a non-current
% local VM.  Because of this, we turn off garbage collection temporarily.
/.copylocal {		% <name> <dict> .copylocal <name> <dict'>
                % Copy a dictionary to the current (local) VM,
                % and make it read-only if its current definition is.
  dup maxlength dict .copydict
  1 index load wcheck not { readonly } if
} .bind def
% When this is called, the dictionary stack is in its initial state,
% and there is (anomalously) only one gstate on the gstate stack.
/.initlocaldicts {		% - .initlocaldicts -
  -2 vmreclaim
  .currentglobal //systemdict begin
  //false .setglobal
                % Since localdicts doesn't exist yet, references from
                % systemdict to local objects won't get restored if
                % a context switch happens in this code.  Therefore,
                % until localdicts is defined, we have to keep all our
                % state on the operand stack.

                % Acquire userdict.
                %****** WRONG IF NON-STANDARD INITIAL DSTACK ******
  countdictstack array dictstack
   { dup gcheck not { exit } if pop } forall
                % Create localdicts with a local copy of each dictionary,
                % except for userdict and userparams, which just need
                % to be filled in.
  mark savedlocaldicts {
    1 index /userdict eq {
                % Stack: userdict mark ... /userdict inituserdict
      counttomark 1 add index .copydict
    } {
      1 index /userparams eq {
                % Stack: userdict mark ... /userparams inituserparams
        userparams .copydict
      } {
        .copylocal
      } ifelse
    } ifelse
  } forall /internaldict dup .makeinternaldict .makeoperator
  .dicttomark readonly /localdicts exch put
                % localdicts is now defined in userdict.
                % Copy the definitions into systemdict.
  localdicts { .forcedef } forall
                % Set the user parameters.
  userparams readonly .setuserparams
                % Establish the initial gstate(s).
  /savedinitialgstate .systemvar setgstate gsave
                % Wrap up.
  end .setglobal
} odef

% Check whether an object is a procedure.
/.proccheck {			% <obj> .proccheck <bool>
  dup xcheck
  exch type dup /arraytype eq exch /packedarraytype eq or and
} bind def

% Create a context with private local VM.
% The .localfork operator does all the work, but we must ensure that
% .initlocaldicts gets called when the new context starts up.
/localfork {			% <mark> <obj1> ... <objN> <proc>
                                %   <stdin|null> <stdout|null>
                                %   localfork <context>
  .currentglobal //true .setglobal 3 index
  dup .proccheck not {
    pop .setglobal /localfork .systemvar /typecheck signalerror
  } if
  {exec .initlocaldicts} aload pop
  3 1 roll 3 packedarray cvx
  4 1 roll 5 -1 roll pop .setglobal .localfork
} odef

% Fork a context that shares VM.  The .fork operator creates an empty
% userparams dictionary for the context, but we still need to initialize
% this dictionary when the new context starts up.
/.postfork {		% - .postfork -
        % Initialize the user parameters.
  savedlocaldicts /userparams get userparams .copydict readonly pop
} odef
/fork {			% <mark> <obj1> ... <objN> <proc> fork <context>
  .currentglobal //false .setglobal 1 index
  dup .proccheck not {
    pop .setglobal /fork .systemvar /typecheck signalerror
  } if
  {exec .postfork} aload pop
  3 1 roll 3 packedarray cvx
  3 1 roll exch pop .setglobal .fork
} odef

% ------ Halftone phase ------ %

/sethalftonephase {		% <x> <y> sethalftonephase -
  -1 2 index 2 index .setscreenphase pop pop
} odef
/currenthalftonephase {		% - currenthalftonephase <x> <y>
  0 .currentscreenphase
} odef

% ------ Device-source images ------ */

.imagetypes 2 /.image2 load put

% ------ Device information ------ %

/.deviceinfodict mark
  /Colors //null /GrayValues //null /RedValues //null /GreenValues //null
  /BlueValues //null /ColorValues //null
.dicttomark readonly def
/deviceinfo {			% - deviceinfo <dict>
  currentdevice //.deviceinfodict .getdeviceparams .dicttomark
  dup begin
  /ColorValues .knownget {
    0 le
    { currentdict /ColorValues undef }
    {
      % hack around devices that incorrect set GrayValues
      Colors 3 eq { 1 } { GrayValues } ifelse
      RedValues mul GreenValues mul BlueValues mul ColorValues ne
      { currentdict /GrayValues undef
        currentdict /RedValues undef
        currentdict /GreenValues undef
        currentdict /BlueValues undef
      } if
    }
    ifelse
  } if
  currentdict end readonly
} odef

% The current implementation allocates a 2-element array each time.
% Perhaps we should change this to 2 separate parameters for X and Y?
/.wtdict mark
  /wtranslation //null
.dicttomark readonly def
/wtranslation {			% - wtranslation <x> <y>
  currentdevice //.wtdict .getdeviceparams exch pop exch pop aload pop
} odef
currentdict /.wtdict .undef

% ------ View clipping ------ %

/rectviewclip {			% <x> <y> <width> <height> rectviewclip -
                                % <numarray|numstring> rectviewclip -
  newpath .rectappend viewclip
} odef