/src/ghostpdl/base/gsstate.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Miscellaneous graphics state operators for Ghostscript library */ |
18 | | #include "gx.h" |
19 | | #include "memory_.h" |
20 | | #include "gserrors.h" |
21 | | #include "gsstruct.h" |
22 | | #include "gsutil.h" /* for gs_next_ids */ |
23 | | #include "gzstate.h" |
24 | | #include "gxcspace.h" /* here for gscolor2.h */ |
25 | | #include "gscolor2.h" |
26 | | #include "gscoord.h" /* for gs_initmatrix */ |
27 | | #include "gscie.h" |
28 | | #include "gxclipsr.h" |
29 | | #include "gxcmap.h" |
30 | | #include "gxdevice.h" |
31 | | #include "gxpcache.h" |
32 | | #include "gzht.h" |
33 | | #include "gzline.h" |
34 | | #include "gspath.h" |
35 | | #include "gzpath.h" |
36 | | #include "gzcpath.h" |
37 | | #include "gsovrc.h" |
38 | | #include "gxcolor2.h" |
39 | | #include "gscolor3.h" /* for gs_smoothness() */ |
40 | | #include "gxpcolor.h" |
41 | | #include "gsicc_manage.h" |
42 | | #include "gxdevsop.h" |
43 | | |
44 | | /* Forward references */ |
45 | | static gs_gstate *gstate_alloc(gs_memory_t *, client_name_t, |
46 | | const gs_gstate *); |
47 | | static gs_gstate *gstate_clone_for_gsave(gs_gstate *, |
48 | | client_name_t); |
49 | | static gs_gstate *gstate_clone_for_gstate(const gs_gstate *, gs_memory_t *, |
50 | | client_name_t); |
51 | | static void gstate_free_contents(gs_gstate *); |
52 | | static int gstate_copy(gs_gstate *, const gs_gstate *, |
53 | | gs_gstate_copy_reason_t, client_name_t); |
54 | | static void clip_stack_rc_adjust(gx_clip_stack_t *cs, int delta, client_name_t cname); |
55 | | |
56 | | /* |
57 | | * Graphics state storage management is complicated. There are many |
58 | | * different classes of storage associated with a graphics state: |
59 | | * |
60 | | * (1) The gstate object itself. This includes some objects physically |
61 | | * embedded within the gstate object, but because of garbage collection |
62 | | * requirements, there are no embedded objects that can be |
63 | | * referenced by non-transient pointers. We assume that the gstate |
64 | | * stack "owns" its gstates and that we can free the top gstate when |
65 | | * doing a restore. |
66 | | * |
67 | | * (2) Objects that are referenced directly by the gstate and whose lifetime |
68 | | * is independent of the gstate. These are garbage collected, not |
69 | | * reference counted, so we don't need to do anything special with them |
70 | | * when manipulating gstates. Currently this includes: |
71 | | * font |
72 | | * |
73 | | * (3) Objects that are referenced directly by the gstate, may be shared |
74 | | * among gstates, and should disappear when no gstates reference them. |
75 | | * These fall into two groups: |
76 | | * |
77 | | * (3a) Objects that are logically connected to individual gstates. |
78 | | * We use reference counting to manage these. Currently these are: |
79 | | * halftone, dev_ht(4), cie_render, black_generation, |
80 | | * undercolor_removal, set_transfer.*, cie_joint_caches, |
81 | | * clip_stack, {opacity,shape}.mask |
82 | | * effective_transfer.* may point to some of the same objects as |
83 | | * set_transfer.*, but don't contribute to the reference count. |
84 | | * Similarly, dev_color may point to the dev_ht object. For |
85 | | * simplicity, we initialize all of these pointers to 0 and then |
86 | | * allocate the object itself when needed. |
87 | | * |
88 | | * (3b) Objects whose lifetimes are associated with something else. |
89 | | * Currently these are: |
90 | | * pattern_cache, which is associated with the entire |
91 | | * stack, is allocated when first needed, and currently |
92 | | * is never freed; |
93 | | * view_clip, which is associated with the current |
94 | | * save level (effectively, with the gstate sub-stack |
95 | | * back to the save) and is managed specially; |
96 | | * |
97 | | * (4) Objects that are referenced directly by exactly one gstate and that |
98 | | * are not referenced (except transiently) from any other object. |
99 | | * These fall into two groups: |
100 | | * |
101 | | * (4b) Objects allocated individually, for the given reason: |
102 | | * line_params.dash.pattern (variable-length), |
103 | | * color_space, path, clip_path, effective_clip.path, |
104 | | * ccolor, dev_color |
105 | | * (may be referenced from image enumerators or elsewhere) |
106 | | * |
107 | | * (4b) The "client data" for a gstate. For the interpreter, this is |
108 | | * the refs associated with the gstate, such as the screen procedures. |
109 | | * Client-supplied procedures manage client data. |
110 | | * |
111 | | * (5) Objects referenced indirectly from gstate objects of category (4), |
112 | | * including objects that may also be referenced directly by the gstate. |
113 | | * The individual routines that manipulate these are responsible |
114 | | * for doing the right kind of reference counting or whatever. |
115 | | * Currently: |
116 | | * devices, path, clip_path, and (if different from both clip_path |
117 | | * and view_clip) effective_clip.path require |
118 | | * gx_path_assign/free, which uses a reference count; |
119 | | * color_space and ccolor require cs_adjust_color/cspace_count |
120 | | * or cs_adjust_counts, which use a reference count; |
121 | | * dev_color has no references to storage that it owns. |
122 | | * We count on garbage collection or restore to deallocate |
123 | | * sub-objects of halftone. |
124 | | * |
125 | | * Note that when after a gsave, the existing gstate references the related |
126 | | * objects that we allocate at the same time, and the newly allocated gstate |
127 | | * references the old related objects. Similarly, during a grestore, we |
128 | | * free the related objects referenced by the current gstate, but after the |
129 | | * grestore, we free the saved gstate, not the current one. However, when |
130 | | * we allocate gstates off-stack, the newly allocated gstate does reference |
131 | | * the newly allocated component objects. Note also that setgstate / |
132 | | * currentgstate may produce gstates in which different allocators own |
133 | | * different sub-objects; this is OK, because restore guarantees that there |
134 | | * won't be any dangling pointers (as long as we don't allow pointers from |
135 | | * global gstates to local objects). |
136 | | */ |
137 | | |
138 | | /* |
139 | | * Define these elements of the graphics state that are allocated |
140 | | * individually for each state, except for line_params.dash.pattern. |
141 | | * Note that effective_clip_shared is not on the list. |
142 | | */ |
143 | | typedef struct gs_gstate_parts_s { |
144 | | gx_path *path; |
145 | | gx_clip_path *clip_path; |
146 | | gx_clip_path *effective_clip_path; |
147 | | struct { |
148 | | gs_client_color *ccolor; |
149 | | gx_device_color *dev_color; |
150 | | } color[2]; |
151 | | } gs_gstate_parts; |
152 | | |
153 | | #define GSTATE_ASSIGN_PARTS(pto, pfrom)\ |
154 | 119M | ((pto)->path = (pfrom)->path, (pto)->clip_path = (pfrom)->clip_path,\ |
155 | 119M | (pto)->effective_clip_path = (pfrom)->effective_clip_path,\ |
156 | 119M | (pto)->color[0].ccolor = (pfrom)->color[0].ccolor,\ |
157 | 119M | (pto)->color[0].dev_color = (pfrom)->color[0].dev_color,\ |
158 | 119M | (pto)->color[1].ccolor = (pfrom)->color[1].ccolor,\ |
159 | 119M | (pto)->color[1].dev_color = (pfrom)->color[1].dev_color) |
160 | | |
161 | | extern_st(st_gs_gstate); /* for gstate_alloc() */ |
162 | | |
163 | | /* Copy client data, using the copy_for procedure if available, */ |
164 | | /* the copy procedure otherwise. */ |
165 | | static int |
166 | | gstate_copy_client_data(const gs_gstate * pgs, void *dto, void *dfrom, |
167 | | gs_gstate_copy_reason_t reason) |
168 | 118M | { |
169 | 118M | return (pgs->client_procs.copy_for != 0 ? |
170 | 0 | (*pgs->client_procs.copy_for) (dto, dfrom, reason) : |
171 | 118M | (*pgs->client_procs.copy) (dto, dfrom)); |
172 | 118M | } |
173 | | |
174 | | /* ------ Operations on the entire graphics state ------ */ |
175 | | |
176 | | /* |
177 | | * Allocate a path for the graphics state. We use stable memory because |
178 | | * some PostScript files have Type 3 fonts whose BuildChar procedure |
179 | | * uses the sequence save ... setcachedevice ... restore, and the path |
180 | | * built between the setcachedevice and the restore must not be freed. |
181 | | * If it weren't for this, we don't think stable memory would be needed. |
182 | | */ |
183 | | static gs_memory_t * |
184 | | gstate_path_memory(gs_memory_t *mem) |
185 | 60.2M | { |
186 | 60.2M | return gs_memory_stable(mem); |
187 | 60.2M | } |
188 | | |
189 | | /* Allocate and initialize a graphics state. */ |
190 | | gs_gstate * |
191 | | gs_gstate_alloc(gs_memory_t * mem) |
192 | 257k | { |
193 | 257k | gs_gstate *pgs = gstate_alloc(mem, "gs_gstate_alloc", NULL); |
194 | 257k | gs_memory_t *path_mem = gstate_path_memory(mem); |
195 | 257k | int code; |
196 | | |
197 | 257k | if (pgs == 0) |
198 | 0 | return 0; |
199 | 257k | GS_STATE_INIT_VALUES(pgs, 1.0); |
200 | | /* Need to set up at least enough to make gs_gstate_free happy */ |
201 | 257k | pgs->saved = 0; |
202 | 257k | pgs->clip_stack = NULL; |
203 | 257k | pgs->view_clip = NULL; |
204 | 257k | pgs->font = NULL; |
205 | 257k | pgs->root_font = NULL; |
206 | 257k | pgs->show_gstate = NULL; |
207 | 257k | pgs->device = NULL; |
208 | | |
209 | | /* |
210 | | * Just enough of the state is initialized at this point |
211 | | * that it's OK to call gs_gstate_free if an allocation fails. |
212 | | */ |
213 | | |
214 | 257k | code = gs_gstate_initialize(pgs, mem); |
215 | 257k | if (code < 0) |
216 | 0 | goto fail; |
217 | | |
218 | | /* Finish initializing the color rendering state. */ |
219 | | |
220 | 257k | rc_alloc_struct_1(pgs->halftone, gs_halftone, &st_halftone, mem, |
221 | 257k | goto fail, "gs_gstate_alloc(halftone)"); |
222 | 257k | pgs->halftone->type = ht_type_none; |
223 | | |
224 | | /* Initialize other things not covered by initgraphics */ |
225 | | |
226 | 257k | pgs->clip_stack = 0; |
227 | 257k | pgs->view_clip = gx_cpath_alloc(path_mem, "gs_gstate_alloc(view_clip)"); |
228 | 257k | if (pgs->view_clip == NULL) |
229 | 0 | goto fail; |
230 | 257k | pgs->view_clip->rule = 0; /* no clipping */ |
231 | 257k | pgs->effective_clip_id = pgs->clip_path->id; |
232 | 257k | pgs->effective_view_clip_id = gs_no_id; |
233 | 257k | pgs->in_cachedevice = 0; |
234 | 257k | pgs->device = 0; /* setting device adjusts refcts */ |
235 | 257k | code = gs_nulldevice(pgs); |
236 | 257k | if (code < 0) |
237 | 0 | goto fail; |
238 | 257k | gs_setfillconstantalpha(pgs, 1.0); |
239 | 257k | gs_setstrokeconstantalpha(pgs, 1.0); |
240 | 257k | gs_setalphaisshape(pgs, false); |
241 | 257k | gs_settransfer(pgs, gs_identity_transfer); |
242 | 257k | gs_setflat(pgs, 1.0); |
243 | 257k | gs_setfilladjust(pgs, 0.3, 0.3); |
244 | 257k | gs_setlimitclamp(pgs, false); |
245 | 257k | gs_setstrokeadjust(pgs, true); |
246 | 257k | pgs->font = 0; /* Not right, but acceptable until the */ |
247 | | /* PostScript code does the first setfont. */ |
248 | 257k | pgs->root_font = 0; /* ditto */ |
249 | 257k | pgs->in_charpath = (gs_char_path_mode) 0; |
250 | 257k | pgs->show_gstate = 0; |
251 | 257k | pgs->level = 0; |
252 | 257k | if (gs_initgraphics(pgs) >= 0) |
253 | 257k | return pgs; |
254 | | /* Something went very wrong. */ |
255 | 0 | fail: |
256 | 0 | gs_gstate_free(pgs); |
257 | 0 | return 0; |
258 | 257k | } |
259 | | |
260 | | /* Set the client data in a graphics state. */ |
261 | | /* This should only be done to a newly created state. */ |
262 | | void |
263 | | gs_gstate_set_client(gs_gstate * pgs, void *pdata, |
264 | | const gs_gstate_client_procs * pprocs, bool client_has_pattern_streams) |
265 | 1.09M | { |
266 | 1.09M | pgs->client_data = pdata; |
267 | 1.09M | pgs->client_procs = *pprocs; |
268 | 1.09M | pgs->have_pattern_streams = client_has_pattern_streams; |
269 | 1.09M | } |
270 | | |
271 | | /* Get the client data from a graphics state. */ |
272 | | #undef gs_gstate_client_data /* gzstate.h makes this a macro */ |
273 | | void * |
274 | | gs_gstate_client_data(const gs_gstate * pgs) |
275 | 69.7M | { |
276 | 69.7M | return pgs->client_data; |
277 | 69.7M | } |
278 | | |
279 | | /* Free the chain of gstates.*/ |
280 | | void |
281 | | gs_gstate_free_chain(gs_gstate * pgs) |
282 | 27.0k | { |
283 | 27.0k | gs_gstate *saved = pgs, *tmp; |
284 | | |
285 | 54.0k | while(saved != 0) { |
286 | 27.0k | tmp = saved->saved; |
287 | 27.0k | gs_gstate_free(saved); |
288 | 27.0k | saved = tmp; |
289 | 27.0k | } |
290 | 27.0k | } |
291 | | |
292 | | /* Free a graphics state. */ |
293 | | void |
294 | | gs_gstate_free(gs_gstate * pgs) |
295 | 1.26M | { |
296 | 1.26M | if (pgs == NULL) |
297 | 7.29k | return; |
298 | 1.26M | gstate_free_contents(pgs); |
299 | 1.26M | gs_free_object(pgs->memory, pgs, "gs_gstate_free"); |
300 | 1.26M | } |
301 | | |
302 | | /* Save the graphics state. */ |
303 | | int |
304 | | gs_gsave(gs_gstate * pgs) |
305 | 58.5M | { |
306 | 58.5M | gs_gstate *pnew = gstate_clone_for_gsave(pgs, "gs_gsave"); |
307 | | |
308 | 58.5M | if (pnew == NULL) |
309 | 3 | return_error(gs_error_VMerror); |
310 | | /* As of PLRM3, the interaction between gsave and the clip stack is |
311 | | * now clear. gsave stores the clip stack into the saved graphics |
312 | | * state, but then clears it in the current graphics state. |
313 | | * |
314 | | * Ordinarily, reference count rules would indicate an rc_decrement() |
315 | | * on pgs->clip_stack, but gstate_clone() has an exception for |
316 | | * the clip_stack field. |
317 | | */ |
318 | 58.5M | pgs->clip_stack = NULL; |
319 | 58.5M | pgs->saved = pnew; |
320 | 58.5M | if (pgs->show_gstate == pgs) |
321 | 0 | pgs->show_gstate = pnew->show_gstate = pnew; |
322 | 58.5M | pgs->trans_flags.xstate_change = false; |
323 | 58.5M | pgs->level++; |
324 | 58.5M | if_debug2m('g', pgs->memory, "[g]gsave -> "PRI_INTPTR", level = %d\n", |
325 | 58.5M | (intptr_t)pnew, pgs->level); |
326 | 58.5M | return 0; |
327 | 58.5M | } |
328 | | |
329 | | /* |
330 | | * Save the graphics state for a 'save'. |
331 | | * We cut the stack below the new gstate, and return the old one. |
332 | | * In addition to an ordinary gsave, we create a new view clip path. |
333 | | */ |
334 | | int |
335 | | gs_gsave_for_save(gs_gstate * pgs, gs_gstate ** psaved) |
336 | 1.18M | { |
337 | 1.18M | int code; |
338 | 1.18M | gx_clip_path *old_cpath = pgs->view_clip; |
339 | 1.18M | gx_clip_path *new_cpath; |
340 | | |
341 | 1.18M | if (old_cpath) { |
342 | 1.18M | new_cpath = |
343 | 1.18M | gx_cpath_alloc_shared(old_cpath, pgs->memory, |
344 | 1.18M | "gs_gsave_for_save(view_clip)"); |
345 | 1.18M | if (new_cpath == 0) |
346 | 0 | return_error(gs_error_VMerror); |
347 | 1.18M | } else { |
348 | 0 | new_cpath = 0; |
349 | 0 | } |
350 | 1.18M | code = gs_gsave(pgs); |
351 | 1.18M | if (code < 0) |
352 | 2 | goto fail; |
353 | 1.18M | if (pgs->effective_clip_path == pgs->view_clip) |
354 | 0 | pgs->effective_clip_path = new_cpath; |
355 | 1.18M | pgs->view_clip = new_cpath; |
356 | | /* Cut the stack so we can't grestore past here. */ |
357 | 1.18M | *psaved = pgs->saved; |
358 | 1.18M | pgs->saved = 0; |
359 | | |
360 | 1.18M | code = gs_gsave(pgs); |
361 | 1.18M | if (code < 0) { |
362 | 0 | pgs->saved = *psaved; |
363 | 0 | *psaved = NULL; |
364 | 0 | gs_grestore(pgs); |
365 | 0 | return code; |
366 | 0 | } |
367 | 1.18M | return code; |
368 | 2 | fail: |
369 | 2 | if (new_cpath) |
370 | 2 | gx_cpath_free(new_cpath, "gs_gsave_for_save(view_clip)"); |
371 | 2 | return code; |
372 | 1.18M | } |
373 | | |
374 | | /* Restore the graphics state. Can fully empty graphics stack */ |
375 | | int /* return 0 if ok, 1 if stack was empty */ |
376 | | gs_grestore_only(gs_gstate * pgs) |
377 | 58.3M | { |
378 | 58.3M | gs_gstate *saved = pgs->saved; |
379 | 58.3M | gs_gstate tmp_gstate; |
380 | 58.3M | void *pdata = pgs->client_data; |
381 | 58.3M | void *sdata; |
382 | | |
383 | 58.3M | if_debug2m('g', pgs->memory, "[g]grestore "PRI_INTPTR", level was %d\n", |
384 | 58.3M | (intptr_t)saved, pgs->level); |
385 | 58.3M | if (!saved) |
386 | 0 | return 1; |
387 | 58.3M | sdata = saved->client_data; |
388 | 58.3M | if (saved->pattern_cache == 0) |
389 | 94.6k | saved->pattern_cache = pgs->pattern_cache; |
390 | | /* Swap back the client data pointers. */ |
391 | 58.3M | pgs->client_data = sdata; |
392 | 58.3M | saved->client_data = pdata; |
393 | 58.3M | if (pdata != 0 && sdata != 0) |
394 | 58.3M | gstate_copy_client_data(pgs, pdata, sdata, copy_for_grestore); |
395 | 58.3M | gstate_free_contents(pgs); |
396 | 58.3M | tmp_gstate = *pgs; /* temp after contents freed (with pointers zeroed) */ |
397 | 58.3M | *pgs = *saved; |
398 | 58.3M | if (pgs->show_gstate == saved) |
399 | 0 | pgs->show_gstate = pgs; |
400 | 58.3M | *saved = tmp_gstate; /* restore "freed" state (pointers zeroed after contents freed) */ |
401 | 58.3M | gs_free_object(pgs->memory, saved, "gs_grestore"); |
402 | | |
403 | 58.3M | return 0; |
404 | 58.3M | } |
405 | | |
406 | | /* Restore the graphics state per PostScript semantics */ |
407 | | int |
408 | | gs_grestore(gs_gstate * pgs) |
409 | 58.2M | { |
410 | 58.2M | int code; |
411 | 58.2M | if (!pgs->saved) |
412 | 0 | return gs_gsave(pgs); /* shouldn't ever happen */ |
413 | 58.2M | code = gs_grestore_only(pgs); |
414 | 58.2M | if (code < 0) |
415 | 0 | return code; |
416 | | |
417 | | /* Wraparound: make sure there are always >= 1 saves on stack */ |
418 | 58.2M | if (pgs->saved) |
419 | 46.6M | return 0; |
420 | 11.6M | return gs_gsave(pgs); |
421 | 58.2M | } |
422 | | |
423 | | /* Restore the graphics state for a 'restore', splicing the old stack */ |
424 | | /* back on. Note that we actually do a grestoreall + 2 grestores. */ |
425 | | int |
426 | | gs_grestoreall_for_restore(gs_gstate * pgs, gs_gstate * saved) |
427 | 1.18M | { |
428 | 1.18M | int code; |
429 | | |
430 | 1.89M | while (pgs->saved->saved) { |
431 | 712k | code = gs_grestore(pgs); |
432 | 712k | if (code < 0) |
433 | 0 | return code; |
434 | 712k | } |
435 | | /* Make sure we don't leave dangling pointers in the caches. */ |
436 | 1.18M | if (pgs->pattern_cache) |
437 | 1.18M | (*pgs->pattern_cache->free_all) (pgs->pattern_cache); |
438 | 1.18M | pgs->saved->saved = saved; |
439 | 1.18M | code = gs_grestore(pgs); |
440 | 1.18M | if (code < 0) |
441 | 0 | return code; |
442 | 1.18M | if (pgs->view_clip) { |
443 | 1.18M | gx_cpath_free(pgs->view_clip, "gs_grestoreall_for_restore"); |
444 | 1.18M | pgs->view_clip = 0; |
445 | 1.18M | } |
446 | 1.18M | return gs_grestore(pgs); |
447 | 1.18M | } |
448 | | |
449 | | /* Restore to the bottommost graphics state (at this save level). */ |
450 | | int |
451 | | gs_grestoreall(gs_gstate * pgs) |
452 | 97 | { |
453 | 97 | if (!pgs->saved) /* shouldn't happen */ |
454 | 0 | return gs_gsave(pgs); |
455 | 97 | while (pgs->saved->saved) { |
456 | 0 | int code = gs_grestore(pgs); |
457 | |
|
458 | 0 | if (code < 0) |
459 | 0 | return code; |
460 | 0 | } |
461 | 97 | return gs_grestore(pgs); |
462 | 97 | } |
463 | | |
464 | | /* Allocate and return a new graphics state. */ |
465 | | gs_gstate * |
466 | | gs_gstate_copy(const gs_gstate * pgs, gs_memory_t * mem) |
467 | 1.16M | { |
468 | 1.16M | gs_gstate *pnew; |
469 | | |
470 | 1.16M | pnew = gstate_clone_for_gstate(pgs, mem, "gs_gstate"); |
471 | 1.16M | if (pnew == NULL) |
472 | 0 | return NULL; |
473 | 1.16M | clip_stack_rc_adjust(pnew->clip_stack, 1, "gs_gstate_copy"); |
474 | 1.16M | pnew->saved = NULL; |
475 | | /* |
476 | | * Prevent dangling references from the show_gstate pointer. If |
477 | | * this context is its own show_gstate, set the pointer in the clone |
478 | | * to point to the clone; otherwise, set the pointer in the clone to |
479 | | * NULL, and let gs_setgstate fix it up. |
480 | | */ |
481 | 1.16M | pnew->show_gstate = |
482 | 1.16M | (pgs->show_gstate == pgs ? pnew : NULL); |
483 | 1.16M | return pnew; |
484 | 1.16M | } |
485 | | |
486 | | /* Copy one previously allocated graphics state to another. */ |
487 | | int |
488 | | gs_copygstate(gs_gstate * pto, const gs_gstate * pfrom) |
489 | 0 | { |
490 | 0 | return gstate_copy(pto, pfrom, copy_for_copygstate, "gs_copygstate"); |
491 | 0 | } |
492 | | |
493 | | /* Copy the current graphics state to a previously allocated one. */ |
494 | | int |
495 | | gs_currentgstate(gs_gstate * pto, const gs_gstate * pgs) |
496 | 2 | { |
497 | 2 | int code = |
498 | 2 | gstate_copy(pto, pgs, copy_for_currentgstate, "gs_currentgstate"); |
499 | | |
500 | 2 | if (code >= 0) |
501 | 2 | pto->view_clip = 0; |
502 | 2 | return code; |
503 | 2 | } |
504 | | |
505 | | /* Restore the current graphics state from a previously allocated one. */ |
506 | | int |
507 | | gs_setgstate(gs_gstate * pgs, const gs_gstate * pfrom) |
508 | 60.2k | { |
509 | | /* |
510 | | * The implementation is the same as currentgstate, |
511 | | * except we must preserve the saved pointer, the level, |
512 | | * the view clip, and possibly the show_gstate. |
513 | | */ |
514 | 60.2k | gs_gstate *saved_show = pgs->show_gstate; |
515 | 60.2k | int level = pgs->level; |
516 | 60.2k | gx_clip_path *view_clip = pgs->view_clip; |
517 | 60.2k | int code; |
518 | | |
519 | 60.2k | pgs->view_clip = 0; /* prevent refcount decrementing */ |
520 | 60.2k | code = gstate_copy(pgs, pfrom, copy_for_setgstate, "gs_setgstate"); |
521 | 60.2k | if (code < 0) |
522 | 0 | return code; |
523 | 60.2k | pgs->level = level; |
524 | 60.2k | pgs->view_clip = view_clip; |
525 | 60.2k | pgs->show_gstate = |
526 | 60.2k | (pgs->show_gstate == pfrom ? pgs : saved_show); |
527 | 60.2k | return 0; |
528 | 60.2k | } |
529 | | |
530 | | /* Get the allocator pointer of a graphics state. */ |
531 | | /* This is provided only for the interpreter */ |
532 | | /* and for color space implementation. */ |
533 | | gs_memory_t * |
534 | | gs_gstate_memory(const gs_gstate * pgs) |
535 | 285k | { |
536 | 285k | return pgs->memory; |
537 | 285k | } |
538 | | |
539 | | /* Get the saved pointer of the graphics state. */ |
540 | | /* This is provided only for Level 2 grestore. */ |
541 | | gs_gstate * |
542 | | gs_gstate_saved(const gs_gstate * pgs) |
543 | 20.5M | { |
544 | 20.5M | return pgs->saved; |
545 | 20.5M | } |
546 | | |
547 | | /* Swap the saved pointer of the graphics state. */ |
548 | | /* This is provided only for save/restore. */ |
549 | | gs_gstate * |
550 | | gs_gstate_swap_saved(gs_gstate * pgs, gs_gstate * new_saved) |
551 | 0 | { |
552 | 0 | gs_gstate *saved = pgs->saved; |
553 | |
|
554 | 0 | pgs->saved = new_saved; |
555 | 0 | return saved; |
556 | 0 | } |
557 | | |
558 | | /* Swap the memory pointer of the graphics state. */ |
559 | | /* This is provided only for the interpreter. */ |
560 | | gs_memory_t * |
561 | | gs_gstate_swap_memory(gs_gstate * pgs, gs_memory_t * mem) |
562 | 4 | { |
563 | 4 | gs_memory_t *memory = pgs->memory; |
564 | | |
565 | 4 | pgs->memory = mem; |
566 | 4 | return memory; |
567 | 4 | } |
568 | | |
569 | | /* ------ Operations on components ------ */ |
570 | | |
571 | | /* |
572 | | * Push an overprint compositor onto the current device. Note that if |
573 | | * the current device already is an overprint compositor, the |
574 | | * composite will update its parameters but not create a new |
575 | | * compositor device. |
576 | | */ |
577 | | int |
578 | | gs_gstate_update_overprint(gs_gstate * pgs, const gs_overprint_params_t * pparams) |
579 | 1.34M | { |
580 | 1.34M | gs_composite_t * pct = 0; |
581 | 1.34M | int code; |
582 | 1.34M | gx_device * dev = pgs->device; |
583 | 1.34M | gx_device * ovptdev; |
584 | | |
585 | 1.34M | code = gs_create_overprint(&pct, pparams, pgs->memory); |
586 | 1.34M | if (code >= 0) { |
587 | 1.34M | code = dev_proc(dev, composite)( dev, |
588 | 1.34M | &ovptdev, |
589 | 1.34M | pct, |
590 | 1.34M | pgs, |
591 | 1.34M | pgs->memory, |
592 | 1.34M | NULL); |
593 | 1.34M | if (code >= 0 || code == gs_error_handled){ |
594 | 1.34M | if (code == 1) { |
595 | 0 | gx_set_device_only(pgs, ovptdev); |
596 | | /* Get rid of extra reference */ |
597 | 0 | rc_decrement(ovptdev, "gs_gstate_update_overprint(ovptdev)"); |
598 | 0 | } |
599 | 1.34M | code = 0; |
600 | 1.34M | } |
601 | 1.34M | } |
602 | 1.34M | if (pct != 0) |
603 | 1.34M | gs_free_object(pgs->memory, pct, "gs_gstate_update_overprint"); |
604 | | |
605 | | /* the following hack handles devices that don't support compositors */ |
606 | 1.34M | if (code == gs_error_unknownerror && !pparams->retain_any_comps) |
607 | 0 | code = 0; |
608 | 1.34M | return code; |
609 | 1.34M | } |
610 | | |
611 | | /* |
612 | | * Reset the overprint mode for the current color space and color. This |
613 | | * routine should be called whenever the current device (i.e.: color |
614 | | * model), overprint, overprint mode, color space, or color are modified. |
615 | | * |
616 | | * The need reason this routine must be called for changes in the current |
617 | | * color and must consider the current color involves the Pattern color |
618 | | * space. In that space, the "color" (pattern) can determine if the base |
619 | | * color space is used (PatternType 1 with PaintType 2), or may provide |
620 | | * is own color space (PatternType 1 with PaintType 1, PatternType 2). |
621 | | * |
622 | | * The most general situation (PatternType 1 with PaintType 1) cannot be |
623 | | * handled properly due to limitations of the pattern cache mechanism, |
624 | | * so in this case overprint is effectively disable by making all color |
625 | | * components "drawn". |
626 | | */ |
627 | | int |
628 | | gs_do_set_overprint(gs_gstate * pgs) |
629 | 673k | { |
630 | 673k | const gs_color_space * pcs = gs_currentcolorspace_inline(pgs); |
631 | 673k | const gs_client_color * pcc = gs_currentcolor_inline(pgs); |
632 | 673k | int code = 0; |
633 | | |
634 | 673k | if (cs_num_components(pcs) < 0 && pcc->pattern != 0) |
635 | 0 | code = pcc->pattern->type->procs.set_color(pcc, pgs); |
636 | 673k | else { |
637 | 673k | gx_device* dev = pgs->device; |
638 | 673k | cmm_dev_profile_t* dev_profile; |
639 | 673k | gs_color_space_index pcs_index = gs_color_space_get_index(pcs); |
640 | | |
641 | 673k | dev_proc(dev, get_profile)(dev, &dev_profile); |
642 | 673k | if (dev_profile->overprint_control == gs_overprint_control_disable) |
643 | 0 | return code; |
644 | | |
645 | | /* Transparency device that supports spots and where we have |
646 | | sep or devicen colors needs special consideration if the device |
647 | | is in a additive blend mode. This could |
648 | | be written more compactly, but it would be unreadable. */ |
649 | 673k | if (dev_proc(dev, dev_spec_op)(dev, gxdso_pdf14_sep_device, NULL, 0) && |
650 | 673k | (dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE)) { |
651 | 169k | if (pcs_index == gs_color_space_index_Separation) { |
652 | 8.52k | if (!(pcs->params.separation.color_type == SEP_MIX || |
653 | 8.52k | pcs->params.separation.color_type == SEP_ENUM)) { |
654 | | /* Sep color is not a spot color. We can't do OP and trans */ |
655 | 0 | return code; |
656 | 0 | } |
657 | 160k | } else if (pcs_index == gs_color_space_index_DeviceN) { |
658 | 0 | if (pcs->params.device_n.color_type != SEP_PURE_SPOT) { |
659 | | /* DeviceN has process colors We can't do OP and trans. */ |
660 | 0 | return code; |
661 | 0 | } |
662 | 0 | } |
663 | 169k | } |
664 | | |
665 | | /* If we have a CIE-based space, use the ICC equivalent space */ |
666 | 673k | if (gs_color_space_is_PSCIE(pcs) && pcs->icc_equivalent != NULL) |
667 | 0 | pcs = pcs->icc_equivalent; |
668 | | |
669 | | /* The spaces that do not allow opm (e.g. ones that are not ICC or DeviceCMYK) |
670 | | will blow away any true setting later. But we have to be prepared |
671 | | in case this is a CMYK ICC space for example. Hence we set effective mode |
672 | | to mode here (Bug 698721)*/ |
673 | 673k | pgs->color[0].effective_opm = pgs->overprint_mode; |
674 | | |
675 | 673k | if_debug2m(gs_debug_flag_overprint, pgs->memory, |
676 | 673k | "[overprint] gs_do_set_overprint. Preset effective mode. pgs->color[0].effective_opm = %d pgs->color[1].effective_opm = %d\n", |
677 | 673k | pgs->color[0].effective_opm, pgs->color[1].effective_opm); |
678 | | |
679 | 673k | pcs->type->set_overprint(pcs, pgs); |
680 | 673k | } |
681 | 673k | return code; |
682 | 673k | } |
683 | | |
684 | | /* setoverprint (non-stroke case) interpreter code |
685 | | ensures that this is called when appropriate. This |
686 | | should only be coming when we are doing PS files. |
687 | | As they don't have separate stroke and fill overprint |
688 | | controls */ |
689 | | void |
690 | | gs_setoverprint(gs_gstate * pgs, bool ovp) |
691 | 2.33M | { |
692 | 2.33M | pgs->overprint = ovp; |
693 | 2.33M | pgs->stroke_overprint = ovp; |
694 | 2.33M | } |
695 | | |
696 | | /* currentoverprint */ |
697 | | bool |
698 | | gs_currentoverprint(const gs_gstate * pgs) |
699 | 1.16M | { |
700 | 1.16M | return pgs->overprint; |
701 | 1.16M | } |
702 | | |
703 | | /* setstrokeoverprint */ |
704 | | void |
705 | | gs_setstrokeoverprint(gs_gstate * pgs, bool ovp) |
706 | 370k | { |
707 | 370k | pgs->stroke_overprint = ovp; |
708 | 370k | } |
709 | | |
710 | | /* currentstrokeoverprint */ |
711 | | bool |
712 | | gs_currentstrokeoverprint(const gs_gstate * pgs) |
713 | 21.9k | { |
714 | 21.9k | return pgs->stroke_overprint; |
715 | 21.9k | } |
716 | | |
717 | | /* setstrokeoverprint */ |
718 | | void |
719 | | gs_setfilloverprint(gs_gstate * pgs, bool ovp) |
720 | 372k | { |
721 | 372k | pgs->overprint = ovp; |
722 | 372k | } |
723 | | |
724 | | /* currentstrokeoverprint */ |
725 | | bool |
726 | | gs_currentfilloverprint(const gs_gstate * pgs) |
727 | 37.2k | { |
728 | 37.2k | return pgs->overprint; |
729 | 37.2k | } |
730 | | |
731 | | /* setoverprintmode */ |
732 | | int |
733 | | gs_setoverprintmode(gs_gstate * pgs, int mode) |
734 | 378k | { |
735 | 378k | if (mode < 0 || mode > 1) |
736 | 12 | return_error(gs_error_rangecheck); |
737 | 378k | pgs->overprint_mode = mode; |
738 | | |
739 | 378k | return 0; |
740 | 378k | } |
741 | | |
742 | | /* currentoverprintmode */ |
743 | | int |
744 | | gs_currentoverprintmode(const gs_gstate * pgs) |
745 | 0 | { |
746 | 0 | return pgs->overprint_mode; |
747 | 0 | } |
748 | | |
749 | | void |
750 | | gs_setcpsimode(gs_memory_t *mem, bool mode) |
751 | 0 | { |
752 | 0 | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
753 | |
|
754 | 0 | libctx->core->CPSI_mode = mode; |
755 | 0 | } |
756 | | |
757 | | /* currentcpsimode */ |
758 | | bool |
759 | | gs_currentcpsimode(const gs_memory_t * mem) |
760 | 613M | { |
761 | 613M | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
762 | | |
763 | 613M | return libctx->core->CPSI_mode; |
764 | 613M | } |
765 | | |
766 | | /* The edgebuffer based scanconverter can only cope with values of 0 |
767 | | * or 0.5 (i.e. 'center of pixel' or 'any part of pixel'). These |
768 | | * are the only values required for correct behaviour according to |
769 | | * the PDF and PS specs. Therefore, if we are using the edgebuffer |
770 | | * based scan converter, force these values. */ |
771 | | static void |
772 | | sanitize_fill_adjust(gs_gstate * pgs) |
773 | 420k | { |
774 | 420k | int scanconverter = gs_getscanconverter(pgs->memory); |
775 | 420k | if (scanconverter >= GS_SCANCONVERTER_EDGEBUFFER || (GS_SCANCONVERTER_DEFAULT_IS_EDGEBUFFER && scanconverter == GS_SCANCONVERTER_DEFAULT)) { |
776 | 420k | fixed adjust = (pgs->fill_adjust.x >= float2fixed(0.25) || pgs->fill_adjust.y >= float2fixed(0.25) ? fixed_half : 0); |
777 | 420k | pgs->fill_adjust.x = adjust; |
778 | 420k | pgs->fill_adjust.y = adjust; |
779 | 420k | } |
780 | 420k | } |
781 | | |
782 | | void |
783 | | gs_setscanconverter(gs_gstate * gs, int converter) |
784 | 0 | { |
785 | 0 | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(gs->memory); |
786 | |
|
787 | 0 | libctx->core->scanconverter = converter; |
788 | |
|
789 | 0 | sanitize_fill_adjust(gs); |
790 | 0 | } |
791 | | |
792 | | /* getscanconverter */ |
793 | | int |
794 | | gs_getscanconverter(const gs_memory_t * mem) |
795 | 20.6M | { |
796 | 20.6M | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
797 | | |
798 | 20.6M | return libctx->core->scanconverter; |
799 | 20.6M | } |
800 | | |
801 | | /* setrenderingintent |
802 | | * |
803 | | * Use ICC numbers from Table 18 (section 6.1.11) rather than the PDF order |
804 | | * to reduce re-coding and confusion. |
805 | | * Perceptual 0 |
806 | | * Relative Colorimetric 1 |
807 | | * Saturation 2 |
808 | | * AbsoluteColorimetric 3 |
809 | | */ |
810 | | int |
811 | 147k | gs_setrenderingintent(gs_gstate *pgs, int ri) { |
812 | 147k | if (ri < 0 || ri > 3) |
813 | 0 | return_error(gs_error_rangecheck); |
814 | 147k | pgs->renderingintent = ri; |
815 | 147k | return 0; |
816 | 147k | } |
817 | | |
818 | | /* currentrenderingintent */ |
819 | | int |
820 | | gs_currentrenderingintent(const gs_gstate * pgs) |
821 | 0 | { |
822 | 0 | return pgs->renderingintent; |
823 | 0 | } |
824 | | |
825 | | int |
826 | 0 | gs_setblackptcomp(gs_gstate *pgs, bool bkpt) { |
827 | 0 | pgs->blackptcomp = bkpt; |
828 | 0 | return 0; |
829 | 0 | } |
830 | | |
831 | | /* currentrenderingintent */ |
832 | | bool |
833 | | gs_currentblackptcomp(const gs_gstate * pgs) |
834 | 0 | { |
835 | 0 | return pgs->blackptcomp; |
836 | 0 | } |
837 | | |
838 | | /* |
839 | | * Reset most of the graphics state. |
840 | | */ |
841 | | int |
842 | | gs_initgraphics(gs_gstate * pgs) |
843 | 1.32M | { |
844 | 1.32M | int code; |
845 | 1.32M | const gs_gstate gstate_initial = { |
846 | 1.32M | gs_gstate_initial(1.0) |
847 | 1.32M | }; |
848 | 1.32M | gs_matrix m; |
849 | 1.32M | gs_make_identity(&m); |
850 | | |
851 | 1.32M | gs_initmatrix(pgs); |
852 | 1.32M | if ((code = gs_newpath(pgs)) < 0 || |
853 | 1.32M | (code = gs_initclip(pgs)) < 0 || |
854 | 1.32M | (code = gs_setlinewidth(pgs, 1.0)) < 0 || |
855 | 1.32M | (code = gs_setlinestartcap(pgs, gstate_initial.line_params.start_cap)) < 0 || |
856 | 1.32M | (code = gs_setlineendcap(pgs, gstate_initial.line_params.end_cap)) < 0 || |
857 | 1.32M | (code = gs_setlinedashcap(pgs, gstate_initial.line_params.dash_cap)) < 0 || |
858 | 1.32M | (code = gs_setlinejoin(pgs, gstate_initial.line_params.join)) < 0 || |
859 | 1.32M | (code = gs_setcurvejoin(pgs, gstate_initial.line_params.curve_join)) < 0 || |
860 | 1.32M | (code = gs_setdash(pgs, (float *)0, 0, 0.0)) < 0 || |
861 | 1.32M | (gs_setdashadapt(pgs, false), |
862 | 1.32M | (code = gs_setdotlength(pgs, 0.0, false))) < 0 || |
863 | 1.32M | (code = gs_setdotorientation(pgs)) < 0 || |
864 | 1.32M | (code = gs_setmiterlimit(pgs, gstate_initial.line_params.miter_limit)) < 0 |
865 | 1.32M | ) |
866 | 0 | return code; |
867 | 1.32M | gs_init_rop(pgs); |
868 | | /* Initialize things so that gx_remap_color won't crash. */ |
869 | 1.32M | if (pgs->icc_manager->default_gray == 0x00) { |
870 | 162k | gs_color_space *pcs1, *pcs2; |
871 | | |
872 | 162k | pcs1 = gs_cspace_new_DeviceGray(pgs->memory); |
873 | 162k | if (pcs1 == NULL) |
874 | 0 | return_error(gs_error_unknownerror); |
875 | | |
876 | 162k | if (pgs->color[0].color_space != NULL) { |
877 | 0 | gs_setcolorspace(pgs, pcs1); |
878 | 0 | rc_decrement_cs(pcs1, "gs_initgraphics"); |
879 | 162k | } else { |
880 | 162k | pgs->color[0].color_space = pcs1; |
881 | 162k | gs_setcolorspace(pgs, pcs1); |
882 | 162k | } |
883 | 162k | code = gx_set_dev_color(pgs); |
884 | 162k | if (code < 0) |
885 | 0 | return code; |
886 | | |
887 | 162k | gs_swapcolors_quick(pgs); /* To color 1 */ |
888 | | |
889 | 162k | pcs2 = gs_cspace_new_DeviceGray(pgs->memory); |
890 | 162k | if (pcs2 == NULL) |
891 | 0 | return_error(gs_error_unknownerror); |
892 | | |
893 | 162k | if (pgs->color[0].color_space != NULL) { |
894 | 0 | gs_setcolorspace(pgs, pcs2); |
895 | 0 | rc_decrement_cs(pcs2, "gs_initgraphics"); |
896 | 162k | } else { |
897 | 162k | pgs->color[0].color_space = pcs2; |
898 | 162k | gs_setcolorspace(pgs, pcs2); |
899 | 162k | } |
900 | 162k | code = gx_set_dev_color(pgs); |
901 | | |
902 | 162k | gs_swapcolors_quick(pgs); /* To color 0 */ |
903 | | |
904 | 162k | if (code < 0) |
905 | 0 | return code; |
906 | | |
907 | 1.16M | } else { |
908 | 1.16M | gs_color_space *pcs1, *pcs2; |
909 | | |
910 | 1.16M | pcs1 = gs_cspace_new_ICC(pgs->memory, pgs, 1); |
911 | 1.16M | if (pcs1 == NULL) |
912 | 0 | return_error(gs_error_unknownerror); |
913 | | |
914 | 1.16M | if (pgs->color[0].color_space != NULL) { |
915 | 1.06M | gs_setcolorspace(pgs, pcs1); |
916 | 1.06M | rc_decrement_cs(pcs1, "gs_initgraphics"); |
917 | 1.06M | } else { |
918 | 94.6k | pgs->color[0].color_space = pcs1; |
919 | 94.6k | gs_setcolorspace(pgs, pcs1); |
920 | 94.6k | } |
921 | 1.16M | code = gx_set_dev_color(pgs); |
922 | 1.16M | if (code < 0) |
923 | 0 | return code; |
924 | | |
925 | 1.16M | gs_swapcolors_quick(pgs); /* To color 1 */ |
926 | 1.16M | pcs2 = gs_cspace_new_ICC(pgs->memory, pgs, 1); |
927 | 1.16M | if (pcs2 == NULL) |
928 | 0 | return_error(gs_error_unknownerror); |
929 | | |
930 | 1.16M | if (pgs->color[0].color_space != NULL) { |
931 | 1.06M | gs_setcolorspace(pgs, pcs2); |
932 | 1.06M | rc_decrement_cs(pcs2, "gs_initgraphics"); |
933 | 1.06M | } else { |
934 | 94.6k | pgs->color[0].color_space = pcs2; |
935 | 94.6k | gs_setcolorspace(pgs, pcs2); |
936 | 94.6k | } |
937 | 1.16M | code = gx_set_dev_color(pgs); |
938 | | |
939 | 1.16M | gs_swapcolors_quick(pgs); /* To color 0 */ |
940 | | |
941 | 1.16M | if (code < 0) |
942 | 0 | return code; |
943 | 1.16M | } |
944 | 1.32M | pgs->in_cachedevice = 0; |
945 | | |
946 | 1.32M | code = gs_settextspacing(pgs, (double)0.0); |
947 | 1.32M | if (code < 0) |
948 | 0 | goto exit; |
949 | 1.32M | code = gs_settextleading(pgs, (double)0.0); |
950 | 1.32M | if (code < 0) |
951 | 0 | goto exit; |
952 | | |
953 | 1.32M | gs_settextrenderingmode(pgs, 0); |
954 | | |
955 | 1.32M | code = gs_setwordspacing(pgs, (double)0.0); |
956 | 1.32M | if (code < 0) |
957 | 0 | goto exit; |
958 | 1.32M | code = gs_settexthscaling(pgs, (double)100.0); |
959 | 1.32M | if (code < 0) |
960 | 0 | goto exit; |
961 | | |
962 | 1.32M | gs_setaccuratecurves(pgs, true); |
963 | | |
964 | 1.32M | code = gs_setstrokeconstantalpha(pgs, 1.0); |
965 | 1.32M | if (code < 0) |
966 | 0 | goto exit; |
967 | 1.32M | code = gs_setfillconstantalpha(pgs, 1.0); |
968 | 1.32M | if (code < 0) |
969 | 0 | goto exit; |
970 | 1.32M | code = gs_setalphaisshape(pgs, 0); |
971 | 1.32M | if (code < 0) |
972 | 0 | goto exit; |
973 | 1.32M | code = gs_setblendmode(pgs, BLEND_MODE_Compatible); |
974 | 1.32M | if (code < 0) |
975 | 0 | goto exit; |
976 | 1.32M | code = gs_settextknockout(pgs, true); |
977 | 1.32M | if (code < 0) |
978 | 0 | goto exit; |
979 | 1.32M | code = gs_setsmoothness(pgs, 0.02); /* Match gs code */ |
980 | 1.32M | if (code < 0) |
981 | 0 | goto exit; |
982 | | |
983 | 1.32M | code = gs_settextmatrix(pgs, &m); |
984 | 1.32M | if (code < 0) |
985 | 0 | goto exit; |
986 | | |
987 | 1.32M | code = gs_settextlinematrix(pgs, &m); |
988 | 1.32M | if (code < 0) |
989 | 0 | goto exit; |
990 | 1.32M | exit: |
991 | 1.32M | return code; |
992 | 1.32M | } |
993 | | |
994 | | /* setfilladjust */ |
995 | | int |
996 | | gs_setfilladjust(gs_gstate * pgs, double adjust_x, double adjust_y) |
997 | 420k | { |
998 | 420k | #define CLAMP_TO_HALF(v)\ |
999 | 840k | ((v) <= 0 ? fixed_0 : (v) >= 0.5 ? fixed_half : float2fixed(v)); |
1000 | | |
1001 | 420k | pgs->fill_adjust.x = CLAMP_TO_HALF(adjust_x); |
1002 | 420k | pgs->fill_adjust.y = CLAMP_TO_HALF(adjust_y); |
1003 | | |
1004 | 420k | sanitize_fill_adjust(pgs); |
1005 | | |
1006 | 420k | return 0; |
1007 | 420k | #undef CLAMP_TO_HALF |
1008 | 420k | } |
1009 | | |
1010 | | /* currentfilladjust */ |
1011 | | int |
1012 | | gs_currentfilladjust(const gs_gstate * pgs, gs_point * adjust) |
1013 | 383k | { |
1014 | 383k | adjust->x = fixed2float(pgs->fill_adjust.x); |
1015 | 383k | adjust->y = fixed2float(pgs->fill_adjust.y); |
1016 | 383k | return 0; |
1017 | 383k | } |
1018 | | |
1019 | | /* setlimitclamp */ |
1020 | | void |
1021 | | gs_setlimitclamp(gs_gstate * pgs, bool clamp) |
1022 | 514k | { |
1023 | 514k | pgs->clamp_coordinates = clamp; |
1024 | 514k | } |
1025 | | |
1026 | | /* currentlimitclamp */ |
1027 | | bool |
1028 | | gs_currentlimitclamp(const gs_gstate * pgs) |
1029 | 0 | { |
1030 | 0 | return pgs->clamp_coordinates; |
1031 | 0 | } |
1032 | | |
1033 | | /* settextrenderingmode */ |
1034 | | void |
1035 | | gs_settextrenderingmode(gs_gstate * pgs, uint trm) |
1036 | 2.09M | { |
1037 | 2.09M | pgs->text_rendering_mode = trm; |
1038 | 2.09M | } |
1039 | | |
1040 | | /* currenttextrenderingmode */ |
1041 | | uint |
1042 | | gs_currenttextrenderingmode(const gs_gstate * pgs) |
1043 | 31.8M | { |
1044 | 31.8M | return pgs->text_rendering_mode; |
1045 | 31.8M | } |
1046 | | |
1047 | | double |
1048 | | gs_currenttextspacing(const gs_gstate *pgs) |
1049 | 19.6M | { |
1050 | 19.6M | return pgs->textspacing; |
1051 | 19.6M | } |
1052 | | |
1053 | | int |
1054 | | gs_settextspacing(gs_gstate *pgs, double Tc) |
1055 | 2.08M | { |
1056 | 2.08M | int code = 0; |
1057 | 2.08M | gs_fixed_point dxy; |
1058 | | |
1059 | 2.08M | code = gs_distance_transform2fixed(&pgs->ctm, Tc, 1, &dxy); |
1060 | 2.08M | if (code < 0) |
1061 | 5.80k | return code; |
1062 | | |
1063 | 2.08M | pgs->textspacing = (float)Tc; |
1064 | 2.08M | return 0; |
1065 | 2.08M | } |
1066 | | |
1067 | | double |
1068 | | gs_currenttextleading(const gs_gstate *pgs) |
1069 | 0 | { |
1070 | 0 | return pgs->textleading; |
1071 | 0 | } |
1072 | | |
1073 | | int |
1074 | | gs_settextleading(gs_gstate *pgs, double TL) |
1075 | 1.72M | { |
1076 | 1.72M | pgs->textleading = (float)TL; |
1077 | 1.72M | return 0; |
1078 | 1.72M | } |
1079 | | |
1080 | | double |
1081 | | gs_currenttextrise(const gs_gstate *pgs) |
1082 | 0 | { |
1083 | 0 | return pgs->textrise; |
1084 | 0 | } |
1085 | | |
1086 | | int |
1087 | | gs_settextrise(gs_gstate *pgs, double Ts) |
1088 | 4.29k | { |
1089 | 4.29k | pgs->textrise = (float)Ts; |
1090 | 4.29k | return 0; |
1091 | 4.29k | } |
1092 | | |
1093 | | double |
1094 | | gs_currentwordspacing(const gs_gstate *pgs) |
1095 | 19.6M | { |
1096 | 19.6M | return pgs->wordspacing; |
1097 | 19.6M | } |
1098 | | |
1099 | | int |
1100 | | gs_setwordspacing(gs_gstate *pgs, double Tw) |
1101 | 1.46M | { |
1102 | 1.46M | pgs->wordspacing = (float)Tw; |
1103 | 1.46M | return 0; |
1104 | 1.46M | } |
1105 | | |
1106 | | int |
1107 | | gs_settexthscaling(gs_gstate *pgs, double Tz) |
1108 | 1.53M | { |
1109 | 1.53M | pgs->texthscaling = (float)Tz; |
1110 | 1.53M | return 0; |
1111 | 1.53M | } |
1112 | | |
1113 | | double |
1114 | | gs_currenttexthscaling(const gs_gstate *pgs) |
1115 | 0 | { |
1116 | 0 | return pgs->texthscaling; |
1117 | 0 | } |
1118 | | |
1119 | | int |
1120 | | gs_setPDFfontsize(gs_gstate *pgs, double Tf) |
1121 | 1.98M | { |
1122 | 1.98M | pgs->PDFfontsize = (float)Tf; |
1123 | 1.98M | return 0; |
1124 | 1.98M | } |
1125 | | |
1126 | | double |
1127 | | gs_currentPDFfontsize(const gs_gstate *pgs) |
1128 | 0 | { |
1129 | 0 | return pgs->PDFfontsize; |
1130 | 0 | } |
1131 | | |
1132 | | int |
1133 | | gs_settextlinematrix(gs_gstate *pgs, gs_matrix *m) |
1134 | 9.18M | { |
1135 | 9.18M | pgs->textlinematrix.xx = m->xx; |
1136 | 9.18M | pgs->textlinematrix.xy = m->xy; |
1137 | 9.18M | pgs->textlinematrix.yx = m->yx; |
1138 | 9.18M | pgs->textlinematrix.yy = m->yy; |
1139 | 9.18M | pgs->textlinematrix.tx = m->tx; |
1140 | 9.18M | pgs->textlinematrix.ty = m->ty; |
1141 | 9.18M | return 0; |
1142 | 9.18M | } |
1143 | | int |
1144 | | gs_gettextlinematrix(gs_gstate *pgs, gs_matrix *m) |
1145 | 0 | { |
1146 | 0 | m->xx = pgs->textlinematrix.xx; |
1147 | 0 | m->xy = pgs->textlinematrix.xy; |
1148 | 0 | m->yx = pgs->textlinematrix.yx; |
1149 | 0 | m->yy = pgs->textlinematrix.yy; |
1150 | 0 | m->tx = pgs->textlinematrix.tx; |
1151 | 0 | m->ty = pgs->textlinematrix.ty; |
1152 | 0 | return 0; |
1153 | 0 | } |
1154 | | |
1155 | | int |
1156 | | gs_settextmatrix(gs_gstate *pgs, gs_matrix *m) |
1157 | 9.18M | { |
1158 | 9.18M | pgs->textmatrix.xx = m->xx; |
1159 | 9.18M | pgs->textmatrix.xy = m->xy; |
1160 | 9.18M | pgs->textmatrix.yx = m->yx; |
1161 | 9.18M | pgs->textmatrix.yy = m->yy; |
1162 | 9.18M | pgs->textmatrix.tx = m->tx; |
1163 | 9.18M | pgs->textmatrix.ty = m->ty; |
1164 | 9.18M | return 0; |
1165 | 9.18M | } |
1166 | | int |
1167 | | gs_gettextmatrix(gs_gstate *pgs, gs_matrix *m) |
1168 | 0 | { |
1169 | 0 | m->xx = pgs->textmatrix.xx; |
1170 | 0 | m->xy = pgs->textmatrix.xy; |
1171 | 0 | m->yx = pgs->textmatrix.yx; |
1172 | 0 | m->yy = pgs->textmatrix.yy; |
1173 | 0 | m->tx = pgs->textmatrix.tx; |
1174 | 0 | m->ty = pgs->textmatrix.ty; |
1175 | 0 | return 0; |
1176 | 0 | } |
1177 | | |
1178 | | |
1179 | | /* sethpglpathmode */ |
1180 | | void |
1181 | | gs_sethpglpathmode(gs_gstate * pgs, bool path) |
1182 | 0 | { |
1183 | 0 | pgs->hpgl_path_mode = path; |
1184 | 0 | } |
1185 | | |
1186 | | /* currenthpglpathmode */ |
1187 | | bool |
1188 | | gs_currenthpglpathmode(const gs_gstate * pgs) |
1189 | 0 | { |
1190 | 0 | return pgs->hpgl_path_mode; |
1191 | 0 | } |
1192 | | |
1193 | | /* ------ Internal routines ------ */ |
1194 | | |
1195 | | /* Free the privately allocated parts of a gstate. */ |
1196 | | static void |
1197 | | gstate_free_parts(gs_gstate * parts, gs_memory_t * mem, client_name_t cname) |
1198 | 119M | { |
1199 | 119M | gs_free_object(mem, parts->color[1].dev_color, cname); |
1200 | 119M | gs_free_object(mem, parts->color[1].ccolor, cname); |
1201 | 119M | gs_free_object(mem, parts->color[0].dev_color, cname); |
1202 | 119M | gs_free_object(mem, parts->color[0].ccolor, cname); |
1203 | 119M | parts->color[1].dev_color = 0; |
1204 | 119M | parts->color[1].ccolor = 0; |
1205 | 119M | parts->color[0].dev_color = 0; |
1206 | 119M | parts->color[0].ccolor = 0; |
1207 | 119M | if (!parts->effective_clip_shared && parts->effective_clip_path) { |
1208 | 0 | gx_cpath_free(parts->effective_clip_path, cname); |
1209 | 0 | parts->effective_clip_path = 0; |
1210 | 0 | } |
1211 | 119M | gx_cpath_free(parts->clip_path, cname); |
1212 | 119M | parts->clip_path = 0; |
1213 | 119M | if (parts->path) { |
1214 | 59.9M | gx_path_free(parts->path, cname); |
1215 | 59.9M | parts->path = 0; |
1216 | 59.9M | } |
1217 | 119M | } |
1218 | | |
1219 | | static inline void |
1220 | | gstate_parts_init_dev_color(gx_device_color *dc) |
1221 | 119M | { |
1222 | 119M | gx_device_color_type dct = dc->type; |
1223 | 119M | gs_graphics_type_tag_t gtt = dc->tag; |
1224 | 119M | memset(dc, 0x00, sizeof(gx_device_color)); |
1225 | 119M | dc->type = dct; |
1226 | 119M | dc->tag = gtt; |
1227 | 119M | } |
1228 | | |
1229 | | /* Allocate the privately allocated parts of a gstate. */ |
1230 | | static int |
1231 | | gstate_alloc_parts(gs_gstate * parts, const gs_gstate * shared, |
1232 | | gs_memory_t * mem, client_name_t cname) |
1233 | 59.9M | { |
1234 | 59.9M | gs_memory_t *path_mem = gstate_path_memory(mem); |
1235 | | |
1236 | 59.9M | parts->path = |
1237 | 59.9M | (shared ? |
1238 | 59.7M | gx_path_alloc_shared(shared->path, path_mem, |
1239 | 59.7M | "gstate_alloc_parts(path)") : |
1240 | 59.9M | gx_path_alloc(path_mem, "gstate_alloc_parts(path)")); |
1241 | 59.9M | parts->clip_path = |
1242 | 59.9M | (shared ? |
1243 | 59.7M | gx_cpath_alloc_shared(shared->clip_path, mem, |
1244 | 59.7M | "gstate_alloc_parts(clip_path)") : |
1245 | 59.9M | gx_cpath_alloc(mem, "gstate_alloc_parts(clip_path)")); |
1246 | 59.9M | if (!shared || shared->effective_clip_shared) { |
1247 | 59.9M | parts->effective_clip_path = parts->clip_path; |
1248 | 59.9M | parts->effective_clip_shared = true; |
1249 | 59.9M | } else { |
1250 | 0 | parts->effective_clip_path = |
1251 | 0 | gx_cpath_alloc_shared(shared->effective_clip_path, mem, |
1252 | 0 | "gstate_alloc_parts(effective_clip_path)"); |
1253 | 0 | parts->effective_clip_shared = false; |
1254 | 0 | } |
1255 | 59.9M | parts->color[0].color_space = NULL; |
1256 | 59.9M | parts->color[1].color_space = NULL; |
1257 | 59.9M | parts->color[0].ccolor = |
1258 | 59.9M | gs_alloc_struct(mem, gs_client_color, &st_client_color, cname); |
1259 | 59.9M | parts->color[1].ccolor = |
1260 | 59.9M | gs_alloc_struct(mem, gs_client_color, &st_client_color, cname); |
1261 | 59.9M | parts->color[0].dev_color = |
1262 | 59.9M | gs_alloc_struct(mem, gx_device_color, &st_device_color, cname); |
1263 | 59.9M | parts->color[1].dev_color = |
1264 | 59.9M | gs_alloc_struct(mem, gx_device_color, &st_device_color, cname); |
1265 | 59.9M | if (parts->path == 0 || parts->clip_path == 0 || |
1266 | 59.9M | parts->effective_clip_path == 0 || |
1267 | 59.9M | parts->color[0].ccolor == 0 || parts->color[0].dev_color == 0 || |
1268 | 59.9M | parts->color[1].ccolor == 0 || parts->color[1].dev_color == 0 |
1269 | 59.9M | ) { |
1270 | 2 | gstate_free_parts(parts, mem, cname); |
1271 | 2 | return_error(gs_error_VMerror); |
1272 | 2 | } |
1273 | 59.9M | gstate_parts_init_dev_color(parts->color[0].dev_color); |
1274 | 59.9M | gstate_parts_init_dev_color(parts->color[1].dev_color); |
1275 | 59.9M | return 0; |
1276 | 59.9M | } |
1277 | | |
1278 | | /* |
1279 | | * Allocate a gstate and its contents. |
1280 | | * If pfrom is not NULL, the path, clip_path, and (if distinct from both |
1281 | | * clip_path and view_clip) effective_clip_path share the segments of |
1282 | | * pfrom's corresponding path(s). |
1283 | | */ |
1284 | | static gs_gstate * |
1285 | | gstate_alloc(gs_memory_t * mem, client_name_t cname, const gs_gstate * pfrom) |
1286 | 59.9M | { |
1287 | 59.9M | gs_gstate *pgs = |
1288 | 59.9M | gs_alloc_struct(mem, gs_gstate, &st_gs_gstate, cname); |
1289 | | |
1290 | 59.9M | if (pgs == NULL) |
1291 | 1 | return NULL; |
1292 | 59.9M | memset(pgs, 0x00, sizeof(gs_gstate)); |
1293 | 59.9M | if (gstate_alloc_parts(pgs, pfrom, mem, cname) < 0) { |
1294 | 2 | gs_free_object(mem, pgs, cname); |
1295 | 2 | return NULL; |
1296 | 2 | } |
1297 | 59.9M | pgs->memory = mem; |
1298 | 59.9M | return pgs; |
1299 | 59.9M | } |
1300 | | |
1301 | | /* Copy the dash pattern from one gstate to another. */ |
1302 | | static int |
1303 | | gstate_copy_dash(gs_memory_t *mem, gx_dash_params *dash , const gs_gstate * pfrom) |
1304 | 249k | { |
1305 | 249k | return gx_set_dash(dash, pfrom->line_params.dash.pattern, |
1306 | 249k | pfrom->line_params.dash.pattern_size, |
1307 | 249k | pfrom->line_params.dash.offset, mem); |
1308 | 249k | } |
1309 | | |
1310 | | typedef struct { |
1311 | | gs_gstate_parts parts; |
1312 | | gx_dash_params dash; |
1313 | | } gs_gstate_clone_data; |
1314 | | |
1315 | | static gs_gstate * |
1316 | | gstate_clone_core(const gs_gstate *pfrom, |
1317 | | gs_memory_t *mem, |
1318 | | client_name_t cname, |
1319 | | gs_gstate_clone_data *clone_data, |
1320 | | gs_gstate_copy_reason_t reason) |
1321 | 59.7M | { |
1322 | 59.7M | gs_gstate *pgs = gstate_alloc(mem, cname, pfrom); |
1323 | 59.7M | void *pdata = NULL; |
1324 | | |
1325 | 59.7M | if (pgs == NULL) |
1326 | 3 | return NULL; |
1327 | 59.7M | if (pfrom->client_data != NULL) { |
1328 | 59.6M | pdata = (*pfrom->client_procs.alloc) (mem); |
1329 | | |
1330 | 59.6M | if (pdata == NULL || |
1331 | 59.6M | gstate_copy_client_data(pfrom, pdata, pfrom->client_data, |
1332 | 59.6M | reason) < 0) |
1333 | 0 | goto failEarly; |
1334 | 59.6M | } |
1335 | | /* Copy the dash and dash pattern if necessary. */ |
1336 | 59.7M | clone_data->dash = gs_currentlineparams_inline(pfrom)->dash; |
1337 | 59.7M | if (clone_data->dash.pattern) { |
1338 | 248k | int code; |
1339 | | |
1340 | 248k | clone_data->dash.pattern = NULL; /* Ensures a fresh allocation */ |
1341 | 248k | code = gstate_copy_dash(mem, &clone_data->dash, pfrom); |
1342 | 248k | if (code < 0) |
1343 | 0 | goto fail; |
1344 | 248k | } |
1345 | | /* Some records within pgs are allocated. We copy pfrom into pgs |
1346 | | * wholesale (to avoid problems with the structure being updated and |
1347 | | * us having to keep it in sync), so we copy those allocated regions |
1348 | | * out first. The caller of this routine will then put them back |
1349 | | * into either pgs or pfrom as appropriate. */ |
1350 | 59.7M | GSTATE_ASSIGN_PARTS(&clone_data->parts, pgs); |
1351 | 59.7M | *pgs = *pfrom; |
1352 | 59.7M | pgs->client_data = pdata; |
1353 | | |
1354 | 59.7M | gs_gstate_copied(pgs); |
1355 | | /* Don't do anything to clip_stack. */ |
1356 | | |
1357 | 59.7M | rc_increment(pgs->device); |
1358 | 59.7M | *clone_data->parts.color[0].ccolor = *pgs->color[0].ccolor; |
1359 | 59.7M | *clone_data->parts.color[0].dev_color = *pgs->color[0].dev_color; |
1360 | 59.7M | *clone_data->parts.color[1].ccolor = *pgs->color[1].ccolor; |
1361 | 59.7M | *clone_data->parts.color[1].dev_color = *pgs->color[1].dev_color; |
1362 | 59.7M | cs_adjust_counts_icc(pgs, 1); |
1363 | 59.7M | cs_adjust_swappedcounts_icc(pgs, 1); |
1364 | | |
1365 | 59.7M | return pgs; |
1366 | | |
1367 | 0 | fail: |
1368 | 0 | gs_free_object(mem, clone_data->dash.pattern, cname); |
1369 | 0 | if (pdata != NULL) |
1370 | 0 | (*pfrom->client_procs.free) (pdata, mem, pgs); |
1371 | 0 | failEarly: |
1372 | 0 | gstate_free_parts(pgs, mem, cname); |
1373 | 0 | gs_free_object(mem, pgs, cname); |
1374 | |
|
1375 | 0 | return NULL; |
1376 | 0 | } |
1377 | | |
1378 | | |
1379 | | /* Clone an existing graphics state for use in gsave. The clone refers |
1380 | | * to the old contents, and the old state refers to the new contents. */ |
1381 | | /* Return NULL if the allocation fails. */ |
1382 | | static gs_gstate * |
1383 | | gstate_clone_for_gsave(gs_gstate *pfrom, |
1384 | | client_name_t cname) |
1385 | 58.5M | { |
1386 | 58.5M | gs_gstate_clone_data clone_data; |
1387 | 58.5M | gs_gstate *pgs = gstate_clone_core(pfrom, pfrom->memory, cname, |
1388 | 58.5M | &clone_data, copy_for_gsave); |
1389 | | |
1390 | 58.5M | if (pgs == NULL) |
1391 | 3 | return NULL; |
1392 | | |
1393 | | /* Newly allocated parts go back into pfrom, not pgs! */ |
1394 | 58.5M | GSTATE_ASSIGN_PARTS(pfrom, &clone_data.parts); |
1395 | 58.5M | gs_currentlineparams_inline(pfrom)->dash = clone_data.dash; |
1396 | | |
1397 | 58.5M | return pgs; |
1398 | 58.5M | } |
1399 | | |
1400 | | /* Clone an existing graphics state. The view_clip is not copied. */ |
1401 | | /* Return NULL if the allocation fails. */ |
1402 | | static gs_gstate * |
1403 | | gstate_clone_for_gstate(const gs_gstate *pfrom, |
1404 | | gs_memory_t *mem, |
1405 | | client_name_t cname) |
1406 | 1.16M | { |
1407 | 1.16M | gs_gstate_clone_data clone_data; |
1408 | 1.16M | gs_gstate *pgs = gstate_clone_core(pfrom, mem, cname, &clone_data, |
1409 | 1.16M | copy_for_gstate); |
1410 | | |
1411 | 1.16M | if (pgs == NULL) |
1412 | 0 | return NULL; |
1413 | 1.16M | GSTATE_ASSIGN_PARTS(pgs, &clone_data.parts); |
1414 | 1.16M | pgs->view_clip = NULL; |
1415 | 1.16M | gs_currentlineparams_inline(pgs)->dash = clone_data.dash; |
1416 | 1.16M | pgs->memory = mem; |
1417 | | |
1418 | 1.16M | return pgs; |
1419 | 1.16M | } |
1420 | | |
1421 | | /* Adjust reference counters for the whole clip stack */ |
1422 | | /* accessible from the given point */ |
1423 | | static void |
1424 | | clip_stack_rc_adjust(gx_clip_stack_t *cs, int delta, client_name_t cname) |
1425 | 120M | { |
1426 | 120M | gx_clip_stack_t *p = cs; |
1427 | | |
1428 | 120M | while(p) { |
1429 | 1 | gx_clip_stack_t *q = p; |
1430 | 1 | p = p->next; |
1431 | 1 | rc_adjust(q, delta, cname); |
1432 | 1 | } |
1433 | 120M | } |
1434 | | |
1435 | | /* |
1436 | | * Finalization for graphics states. This is where we handle RC for those |
1437 | | * elements. |
1438 | | */ |
1439 | | void |
1440 | | gs_gstate_finalize(const gs_memory_t *cmem,void *vptr) |
1441 | 59.9M | { |
1442 | 59.9M | gs_gstate *pgs = (gs_gstate *)vptr; |
1443 | 59.9M | (void)cmem; /* unused */ |
1444 | | |
1445 | 59.9M | if (cmem == NULL) |
1446 | 0 | return; /* place for breakpoint */ |
1447 | 59.9M | gstate_free_contents(pgs); |
1448 | 59.9M | } |
1449 | | |
1450 | | /* Release the composite parts of a graphics state, */ |
1451 | | /* but not the state itself. */ |
1452 | | static void |
1453 | | gstate_free_contents(gs_gstate * pgs) |
1454 | 119M | { |
1455 | 119M | gs_memory_t *mem = pgs->memory; |
1456 | 119M | const char *const cname = "gstate_free_contents"; |
1457 | | |
1458 | 119M | rc_decrement(pgs->device, cname); |
1459 | 119M | pgs->device = 0; |
1460 | 119M | clip_stack_rc_adjust(pgs->clip_stack, -1, cname); |
1461 | 119M | pgs->clip_stack = 0; |
1462 | 119M | if (pgs->view_clip != NULL && pgs->level == 0) { |
1463 | 257k | gx_cpath_free(pgs->view_clip, cname); |
1464 | 257k | pgs->view_clip = NULL; |
1465 | 257k | } |
1466 | 119M | if (pgs->client_data != 0) |
1467 | 59.8M | (*pgs->client_procs.free) (pgs->client_data, mem, pgs); |
1468 | 119M | pgs->client_data = 0; |
1469 | 119M | cs_adjust_counts_icc(pgs, -1); |
1470 | 119M | cs_adjust_swappedcounts_icc(pgs, -1); |
1471 | 119M | pgs->color[0].color_space = 0; |
1472 | 119M | pgs->color[1].color_space = 0; |
1473 | 119M | gs_free_object(mem, pgs->line_params.dash.pattern, cname); |
1474 | 119M | pgs->line_params.dash.pattern = 0; |
1475 | 119M | gstate_free_parts(pgs, mem, cname); /* this also clears pointers to freed elements */ |
1476 | 119M | gs_gstate_release(pgs); |
1477 | 119M | } |
1478 | | |
1479 | | /* Copy one gstate to another. */ |
1480 | | static int |
1481 | | gstate_copy(gs_gstate * pto, const gs_gstate * pfrom, |
1482 | | gs_gstate_copy_reason_t reason, client_name_t cname) |
1483 | 60.2k | { |
1484 | 60.2k | gs_gstate_parts parts; |
1485 | | |
1486 | 60.2k | GSTATE_ASSIGN_PARTS(&parts, pto); |
1487 | | /* Copy the dash pattern if necessary. */ |
1488 | 60.2k | if (pfrom->line_params.dash.pattern || pto->line_params.dash.pattern) { |
1489 | 1.18k | int code = gstate_copy_dash(pto->memory, |
1490 | 1.18k | &(gs_currentlineparams_inline(pto)->dash), pfrom); |
1491 | | |
1492 | 1.18k | if (code < 0) |
1493 | 0 | return code; |
1494 | 1.18k | } |
1495 | | /* |
1496 | | * It's OK to decrement the counts before incrementing them, |
1497 | | * because anything that is going to survive has a count of |
1498 | | * at least 2 (pto and somewhere else) initially. |
1499 | | * Handle references from contents. |
1500 | | */ |
1501 | 60.2k | cs_adjust_counts_icc(pto, -1); |
1502 | 60.2k | cs_adjust_swappedcounts_icc(pto, -1); |
1503 | 60.2k | gx_path_assign_preserve(pto->path, pfrom->path); |
1504 | 60.2k | gx_cpath_assign_preserve(pto->clip_path, pfrom->clip_path); |
1505 | | /* |
1506 | | * effective_clip_shared will be copied, but we need to do the |
1507 | | * right thing with effective_clip_path. |
1508 | | */ |
1509 | 60.2k | if (pfrom->effective_clip_shared) { |
1510 | | /* |
1511 | | * pfrom->effective_clip_path is either pfrom->view_clip or |
1512 | | * pfrom->clip_path. |
1513 | | */ |
1514 | 60.2k | parts.effective_clip_path = |
1515 | 60.2k | (pfrom->effective_clip_path == pfrom->view_clip ? |
1516 | 60.2k | pto->view_clip : parts.clip_path); |
1517 | 60.2k | } else |
1518 | 0 | gx_cpath_assign_preserve(pto->effective_clip_path, |
1519 | 0 | pfrom->effective_clip_path); |
1520 | 60.2k | *parts.color[0].ccolor = *pfrom->color[0].ccolor; |
1521 | 60.2k | *parts.color[0].dev_color = *pfrom->color[0].dev_color; |
1522 | 60.2k | *parts.color[1].ccolor = *pfrom->color[1].ccolor; |
1523 | 60.2k | *parts.color[1].dev_color = *pfrom->color[1].dev_color; |
1524 | | /* Handle references from gstate object. */ |
1525 | 60.2k | rc_pre_assign(pto->device, pfrom->device, cname); |
1526 | 60.2k | if (pto->clip_stack != pfrom->clip_stack) { |
1527 | 0 | clip_stack_rc_adjust(pfrom->clip_stack, 1, cname); |
1528 | 0 | clip_stack_rc_adjust(pto->clip_stack, -1, cname); |
1529 | 0 | } |
1530 | 60.2k | { |
1531 | 60.2k | struct gx_pattern_cache_s *pcache = pto->pattern_cache; |
1532 | 60.2k | void *pdata = pto->client_data; |
1533 | 60.2k | gs_memory_t *mem = pto->memory; |
1534 | 60.2k | gs_gstate *saved = pto->saved; |
1535 | 60.2k | float *pattern = pto->line_params.dash.pattern; |
1536 | | |
1537 | 60.2k | gs_gstate_pre_assign(pto, (const gs_gstate *)pfrom); |
1538 | 60.2k | *pto = *pfrom; |
1539 | 60.2k | pto->client_data = pdata; |
1540 | 60.2k | pto->memory = mem; |
1541 | 60.2k | pto->saved = saved; |
1542 | 60.2k | pto->line_params.dash.pattern = pattern; |
1543 | 60.2k | if (pto->pattern_cache == 0) |
1544 | 0 | pto->pattern_cache = pcache; |
1545 | 60.2k | if (pfrom->client_data != 0) { |
1546 | | /* We need to break 'const' here. */ |
1547 | 57.6k | gstate_copy_client_data((gs_gstate *) pfrom, pdata, |
1548 | 57.6k | pfrom->client_data, reason); |
1549 | 57.6k | } |
1550 | 60.2k | } |
1551 | 60.2k | GSTATE_ASSIGN_PARTS(pto, &parts); |
1552 | 60.2k | cs_adjust_counts_icc(pto, 1); |
1553 | 60.2k | cs_adjust_swappedcounts_icc(pto, 1); |
1554 | 60.2k | pto->show_gstate = |
1555 | 60.2k | (pfrom->show_gstate == pfrom ? pto : 0); |
1556 | 60.2k | return 0; |
1557 | 60.2k | } |
1558 | | |
1559 | | /* Accessories. */ |
1560 | | gs_id gx_get_clip_path_id(gs_gstate *pgs) |
1561 | 83.2k | { |
1562 | 83.2k | return pgs->clip_path->id; |
1563 | 83.2k | } |
1564 | | |
1565 | | void gs_swapcolors_quick(const gs_gstate *cpgs) |
1566 | 32.0M | { |
1567 | 32.0M | union { |
1568 | 32.0M | const gs_gstate *cpgs; |
1569 | 32.0M | gs_gstate *pgs; |
1570 | 32.0M | } const_breaker; |
1571 | 32.0M | gs_gstate *pgs; |
1572 | 32.0M | struct gx_cie_joint_caches_s *tmp_cie; |
1573 | 32.0M | gs_devicen_color_map tmp_ccm; |
1574 | 32.0M | gs_client_color *tmp_cc; |
1575 | 32.0M | int tmp; |
1576 | 32.0M | gx_device_color *tmp_dc; |
1577 | 32.0M | gs_color_space *tmp_cs; |
1578 | | |
1579 | | /* Break const just once, neatly, here rather than |
1580 | | * hackily in every caller. */ |
1581 | 32.0M | const_breaker.cpgs = cpgs; |
1582 | 32.0M | pgs = const_breaker.pgs; |
1583 | | |
1584 | 32.0M | tmp_cc = pgs->color[0].ccolor; |
1585 | 32.0M | pgs->color[0].ccolor = pgs->color[1].ccolor; |
1586 | 32.0M | pgs->color[1].ccolor = tmp_cc; |
1587 | | |
1588 | 32.0M | tmp_dc = pgs->color[0].dev_color; |
1589 | 32.0M | pgs->color[0].dev_color = pgs->color[1].dev_color; |
1590 | 32.0M | pgs->color[1].dev_color = tmp_dc; |
1591 | | |
1592 | 32.0M | tmp_cs = pgs->color[0].color_space; |
1593 | 32.0M | pgs->color[0].color_space = pgs->color[1].color_space; |
1594 | 32.0M | pgs->color[1].color_space = tmp_cs; |
1595 | | |
1596 | | /* Overprint and effective_op vary with stroke/fill and cs */ |
1597 | 32.0M | tmp = pgs->color[0].effective_opm; |
1598 | 32.0M | pgs->color[0].effective_opm = pgs->color[1].effective_opm; |
1599 | 32.0M | pgs->color[1].effective_opm = tmp; |
1600 | | |
1601 | | /* Swap the bits of the gs_gstate that depend on the current color */ |
1602 | 32.0M | tmp_cie = pgs->cie_joint_caches; |
1603 | 32.0M | pgs->cie_joint_caches = pgs->cie_joint_caches_alt; |
1604 | 32.0M | pgs->cie_joint_caches_alt = tmp_cie; |
1605 | | |
1606 | 32.0M | tmp_ccm = pgs->color_component_map; |
1607 | 32.0M | pgs->color_component_map = pgs->color_component_map_alt; |
1608 | 32.0M | pgs->color_component_map_alt = tmp_ccm; |
1609 | | |
1610 | 32.0M | pgs->is_fill_color = !(pgs->is_fill_color); /* used by overprint for fill_stroke */ |
1611 | 32.0M | } |
1612 | | |
1613 | | int |
1614 | | gs_clip_bounds_in_user_space(gs_gstate *pgs, gs_rect *ubox) |
1615 | 93.3k | { |
1616 | 93.3k | gx_clip_path *clip_path; |
1617 | 93.3k | gs_rect dbox; |
1618 | 93.3k | int code; |
1619 | | |
1620 | 93.3k | code = gx_effective_clip_path(pgs, &clip_path); |
1621 | 93.3k | if (code < 0) |
1622 | 0 | return code; |
1623 | | |
1624 | 93.3k | dbox.p.x = fixed2float(clip_path->outer_box.p.x); |
1625 | 93.3k | dbox.p.y = fixed2float(clip_path->outer_box.p.y); |
1626 | 93.3k | dbox.q.x = fixed2float(clip_path->outer_box.q.x); |
1627 | 93.3k | dbox.q.y = fixed2float(clip_path->outer_box.q.y); |
1628 | 93.3k | return gs_bbox_transform_inverse(&dbox, &ctm_only(pgs), ubox); |
1629 | 93.3k | } |