/src/ghostpdl/base/gsstate.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2022 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., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, 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 | 1.55M | ((pto)->path = (pfrom)->path, (pto)->clip_path = (pfrom)->clip_path,\ |
155 | 1.55M | (pto)->effective_clip_path = (pfrom)->effective_clip_path,\ |
156 | 1.55M | (pto)->color[0].ccolor = (pfrom)->color[0].ccolor,\ |
157 | 1.55M | (pto)->color[0].dev_color = (pfrom)->color[0].dev_color,\ |
158 | 1.55M | (pto)->color[1].ccolor = (pfrom)->color[1].ccolor,\ |
159 | 1.55M | (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 | 1.52M | { |
169 | 1.52M | return (pgs->client_procs.copy_for != 0 ? |
170 | 0 | (*pgs->client_procs.copy_for) (dto, dfrom, reason) : |
171 | 1.52M | (*pgs->client_procs.copy) (dto, dfrom)); |
172 | 1.52M | } |
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 | 776k | { |
186 | 776k | return gs_memory_stable(mem); |
187 | 776k | } |
188 | | |
189 | | /* Allocate and initialize a graphics state. */ |
190 | | gs_gstate * |
191 | | gs_gstate_alloc(gs_memory_t * mem) |
192 | 1.35k | { |
193 | 1.35k | gs_gstate *pgs = gstate_alloc(mem, "gs_gstate_alloc", NULL); |
194 | 1.35k | gs_memory_t *path_mem = gstate_path_memory(mem); |
195 | 1.35k | int code; |
196 | | |
197 | 1.35k | if (pgs == 0) |
198 | 0 | return 0; |
199 | 1.35k | GS_STATE_INIT_VALUES(pgs, 1.0); |
200 | | /* Need to set up at least enough to make gs_gstate_free happy */ |
201 | 1.35k | pgs->saved = 0; |
202 | 1.35k | pgs->clip_stack = NULL; |
203 | 1.35k | pgs->view_clip = NULL; |
204 | 1.35k | pgs->font = NULL; |
205 | 1.35k | pgs->root_font = NULL; |
206 | 1.35k | pgs->show_gstate = NULL; |
207 | 1.35k | 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 | 1.35k | code = gs_gstate_initialize(pgs, mem); |
215 | 1.35k | if (code < 0) |
216 | 0 | goto fail; |
217 | | |
218 | | /* Finish initializing the color rendering state. */ |
219 | | |
220 | 1.35k | rc_alloc_struct_1(pgs->halftone, gs_halftone, &st_halftone, mem, |
221 | 1.35k | goto fail, "gs_gstate_alloc(halftone)"); |
222 | 1.35k | pgs->halftone->type = ht_type_none; |
223 | | |
224 | | /* Initialize other things not covered by initgraphics */ |
225 | | |
226 | 1.35k | pgs->clip_stack = 0; |
227 | 1.35k | pgs->view_clip = gx_cpath_alloc(path_mem, "gs_gstate_alloc(view_clip)"); |
228 | 1.35k | if (pgs->view_clip == NULL) |
229 | 0 | goto fail; |
230 | 1.35k | pgs->view_clip->rule = 0; /* no clipping */ |
231 | 1.35k | pgs->effective_clip_id = pgs->clip_path->id; |
232 | 1.35k | pgs->effective_view_clip_id = gs_no_id; |
233 | 1.35k | pgs->in_cachedevice = 0; |
234 | 1.35k | pgs->device = 0; /* setting device adjusts refcts */ |
235 | 1.35k | code = gs_nulldevice(pgs); |
236 | 1.35k | if (code < 0) |
237 | 0 | goto fail; |
238 | 1.35k | gs_setfillconstantalpha(pgs, 1.0); |
239 | 1.35k | gs_setstrokeconstantalpha(pgs, 1.0); |
240 | 1.35k | gs_setalphaisshape(pgs, false); |
241 | 1.35k | gs_settransfer(pgs, gs_identity_transfer); |
242 | 1.35k | gs_setflat(pgs, 1.0); |
243 | 1.35k | gs_setfilladjust(pgs, 0.3, 0.3); |
244 | 1.35k | gs_setlimitclamp(pgs, false); |
245 | 1.35k | gs_setstrokeadjust(pgs, true); |
246 | 1.35k | pgs->font = 0; /* Not right, but acceptable until the */ |
247 | | /* PostScript code does the first setfont. */ |
248 | 1.35k | pgs->root_font = 0; /* ditto */ |
249 | 1.35k | pgs->in_charpath = (gs_char_path_mode) 0; |
250 | 1.35k | pgs->show_gstate = 0; |
251 | 1.35k | pgs->level = 0; |
252 | 1.35k | if (gs_initgraphics(pgs) >= 0) |
253 | 1.35k | return pgs; |
254 | | /* Something went very wrong. */ |
255 | 0 | fail: |
256 | 0 | gs_gstate_free(pgs); |
257 | 0 | return 0; |
258 | 1.35k | } |
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 | 8.76k | { |
266 | 8.76k | pgs->client_data = pdata; |
267 | 8.76k | pgs->client_procs = *pprocs; |
268 | 8.76k | pgs->have_pattern_streams = client_has_pattern_streams; |
269 | 8.76k | } |
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 | 101k | { |
276 | 101k | return pgs->client_data; |
277 | 101k | } |
278 | | |
279 | | /* Free the chain of gstates.*/ |
280 | | void |
281 | | gs_gstate_free_chain(gs_gstate * pgs) |
282 | 713 | { |
283 | 713 | gs_gstate *saved = pgs, *tmp; |
284 | | |
285 | 1.42k | while(saved != 0) { |
286 | 713 | tmp = saved->saved; |
287 | 713 | gs_gstate_free(saved); |
288 | 713 | saved = tmp; |
289 | 713 | } |
290 | 713 | } |
291 | | |
292 | | /* Free a graphics state. */ |
293 | | void |
294 | | gs_gstate_free(gs_gstate * pgs) |
295 | 24.3k | { |
296 | 24.3k | if (pgs == NULL) |
297 | 0 | return; |
298 | 24.3k | gstate_free_contents(pgs); |
299 | 24.3k | gs_free_object(pgs->memory, pgs, "gs_gstate_free"); |
300 | 24.3k | } |
301 | | |
302 | | /* Save the graphics state. */ |
303 | | int |
304 | | gs_gsave(gs_gstate * pgs) |
305 | 750k | { |
306 | 750k | gs_gstate *pnew = gstate_clone_for_gsave(pgs, "gs_gsave"); |
307 | | |
308 | 750k | if (pnew == NULL) |
309 | 0 | 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 | 750k | pgs->clip_stack = NULL; |
319 | 750k | pgs->saved = pnew; |
320 | 750k | if (pgs->show_gstate == pgs) |
321 | 0 | pgs->show_gstate = pnew->show_gstate = pnew; |
322 | 750k | pgs->trans_flags.xstate_change = false; |
323 | 750k | pgs->level++; |
324 | 750k | if_debug2m('g', pgs->memory, "[g]gsave -> "PRI_INTPTR", level = %d\n", |
325 | 750k | (intptr_t)pnew, pgs->level); |
326 | 750k | return 0; |
327 | 750k | } |
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 | 15.1k | { |
337 | 15.1k | int code; |
338 | 15.1k | gx_clip_path *old_cpath = pgs->view_clip; |
339 | 15.1k | gx_clip_path *new_cpath; |
340 | | |
341 | 15.1k | if (old_cpath) { |
342 | 15.1k | new_cpath = |
343 | 15.1k | gx_cpath_alloc_shared(old_cpath, pgs->memory, |
344 | 15.1k | "gs_gsave_for_save(view_clip)"); |
345 | 15.1k | if (new_cpath == 0) |
346 | 0 | return_error(gs_error_VMerror); |
347 | 15.1k | } else { |
348 | 0 | new_cpath = 0; |
349 | 0 | } |
350 | 15.1k | code = gs_gsave(pgs); |
351 | 15.1k | if (code < 0) |
352 | 0 | goto fail; |
353 | 15.1k | if (pgs->effective_clip_path == pgs->view_clip) |
354 | 0 | pgs->effective_clip_path = new_cpath; |
355 | 15.1k | pgs->view_clip = new_cpath; |
356 | | /* Cut the stack so we can't grestore past here. */ |
357 | 15.1k | *psaved = pgs->saved; |
358 | 15.1k | pgs->saved = 0; |
359 | | |
360 | 15.1k | code = gs_gsave(pgs); |
361 | 15.1k | if (code < 0) { |
362 | 0 | pgs->saved = *psaved; |
363 | 0 | *psaved = NULL; |
364 | 0 | gs_grestore(pgs); |
365 | 0 | return code; |
366 | 0 | } |
367 | 15.1k | return code; |
368 | 0 | fail: |
369 | 0 | if (new_cpath) |
370 | 0 | gx_cpath_free(new_cpath, "gs_gsave_for_save(view_clip)"); |
371 | 0 | return code; |
372 | 15.1k | } |
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 | 749k | { |
378 | 749k | gs_gstate *saved = pgs->saved; |
379 | 749k | gs_gstate tmp_gstate; |
380 | 749k | void *pdata = pgs->client_data; |
381 | 749k | void *sdata; |
382 | | |
383 | 749k | if_debug2m('g', pgs->memory, "[g]grestore "PRI_INTPTR", level was %d\n", |
384 | 749k | (intptr_t)saved, pgs->level); |
385 | 749k | if (!saved) |
386 | 0 | return 1; |
387 | 749k | sdata = saved->client_data; |
388 | 749k | if (saved->pattern_cache == 0) |
389 | 669 | saved->pattern_cache = pgs->pattern_cache; |
390 | | /* Swap back the client data pointers. */ |
391 | 749k | pgs->client_data = sdata; |
392 | 749k | saved->client_data = pdata; |
393 | 749k | if (pdata != 0 && sdata != 0) |
394 | 749k | gstate_copy_client_data(pgs, pdata, sdata, copy_for_grestore); |
395 | 749k | gstate_free_contents(pgs); |
396 | 749k | tmp_gstate = *pgs; /* temp after contents freed (with pointers zeroed) */ |
397 | 749k | *pgs = *saved; |
398 | 749k | if (pgs->show_gstate == saved) |
399 | 0 | pgs->show_gstate = pgs; |
400 | 749k | *saved = tmp_gstate; /* restore "freed" state (pointers zeroed after contents freed) */ |
401 | 749k | gs_free_object(pgs->memory, saved, "gs_grestore"); |
402 | | |
403 | 749k | return 0; |
404 | 749k | } |
405 | | |
406 | | /* Restore the graphics state per PostScript semantics */ |
407 | | int |
408 | | gs_grestore(gs_gstate * pgs) |
409 | 749k | { |
410 | 749k | int code; |
411 | 749k | if (!pgs->saved) |
412 | 0 | return gs_gsave(pgs); /* shouldn't ever happen */ |
413 | 749k | code = gs_grestore_only(pgs); |
414 | 749k | if (code < 0) |
415 | 0 | return code; |
416 | | |
417 | | /* Wraparound: make sure there are always >= 1 saves on stack */ |
418 | 749k | if (pgs->saved) |
419 | 749k | return 0; |
420 | 0 | return gs_gsave(pgs); |
421 | 749k | } |
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 | 15.1k | { |
428 | 15.1k | int code; |
429 | | |
430 | 15.1k | while (pgs->saved->saved) { |
431 | 1 | code = gs_grestore(pgs); |
432 | 1 | if (code < 0) |
433 | 0 | return code; |
434 | 1 | } |
435 | | /* Make sure we don't leave dangling pointers in the caches. */ |
436 | 15.1k | if (pgs->pattern_cache) |
437 | 15.1k | (*pgs->pattern_cache->free_all) (pgs->pattern_cache); |
438 | 15.1k | pgs->saved->saved = saved; |
439 | 15.1k | code = gs_grestore(pgs); |
440 | 15.1k | if (code < 0) |
441 | 0 | return code; |
442 | 15.1k | if (pgs->view_clip) { |
443 | 15.1k | gx_cpath_free(pgs->view_clip, "gs_grestoreall_for_restore"); |
444 | 15.1k | pgs->view_clip = 0; |
445 | 15.1k | } |
446 | 15.1k | return gs_grestore(pgs); |
447 | 15.1k | } |
448 | | |
449 | | /* Restore to the bottommost graphics state (at this save level). */ |
450 | | int |
451 | | gs_grestoreall(gs_gstate * pgs) |
452 | 0 | { |
453 | 0 | if (!pgs->saved) /* shouldn't happen */ |
454 | 0 | return gs_gsave(pgs); |
455 | 0 | while (pgs->saved->saved) { |
456 | 0 | int code = gs_grestore(pgs); |
457 | |
|
458 | 0 | if (code < 0) |
459 | 0 | return code; |
460 | 0 | } |
461 | 0 | return gs_grestore(pgs); |
462 | 0 | } |
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 | 23.6k | { |
468 | 23.6k | gs_gstate *pnew; |
469 | | |
470 | 23.6k | pnew = gstate_clone_for_gstate(pgs, mem, "gs_gstate"); |
471 | 23.6k | if (pnew == NULL) |
472 | 0 | return NULL; |
473 | 23.6k | clip_stack_rc_adjust(pnew->clip_stack, 1, "gs_gstate_copy"); |
474 | 23.6k | 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 | 23.6k | pnew->show_gstate = |
482 | 23.6k | (pgs->show_gstate == pgs ? pnew : NULL); |
483 | 23.6k | return pnew; |
484 | 23.6k | } |
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 | 0 | { |
497 | 0 | int code = |
498 | 0 | gstate_copy(pto, pgs, copy_for_currentgstate, "gs_currentgstate"); |
499 | |
|
500 | 0 | if (code >= 0) |
501 | 0 | pto->view_clip = 0; |
502 | 0 | return code; |
503 | 0 | } |
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 | 1.49k | { |
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 | 1.49k | gs_gstate *saved_show = pgs->show_gstate; |
515 | 1.49k | int level = pgs->level; |
516 | 1.49k | gx_clip_path *view_clip = pgs->view_clip; |
517 | 1.49k | int code; |
518 | | |
519 | 1.49k | pgs->view_clip = 0; /* prevent refcount decrementing */ |
520 | 1.49k | code = gstate_copy(pgs, pfrom, copy_for_setgstate, "gs_setgstate"); |
521 | 1.49k | if (code < 0) |
522 | 0 | return code; |
523 | 1.49k | pgs->level = level; |
524 | 1.49k | pgs->view_clip = view_clip; |
525 | 1.49k | pgs->show_gstate = |
526 | 1.49k | (pgs->show_gstate == pfrom ? pgs : saved_show); |
527 | 1.49k | return 0; |
528 | 1.49k | } |
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 | 2.82k | { |
536 | 2.82k | return pgs->memory; |
537 | 2.82k | } |
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 | 4.48k | { |
544 | 4.48k | return pgs->saved; |
545 | 4.48k | } |
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 | 0 | { |
563 | 0 | gs_memory_t *memory = pgs->memory; |
564 | |
|
565 | 0 | pgs->memory = mem; |
566 | 0 | return memory; |
567 | 0 | } |
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 | 83 | { |
580 | 83 | gs_composite_t * pct = 0; |
581 | 83 | int code; |
582 | 83 | gx_device * dev = pgs->device; |
583 | 83 | gx_device * ovptdev; |
584 | | |
585 | 83 | code = gs_create_overprint(&pct, pparams, pgs->memory); |
586 | 83 | if (code >= 0) { |
587 | 83 | code = dev_proc(dev, composite)( dev, |
588 | 83 | &ovptdev, |
589 | 83 | pct, |
590 | 83 | pgs, |
591 | 83 | pgs->memory, |
592 | 83 | NULL); |
593 | 83 | if (code >= 0 || code == gs_error_handled){ |
594 | 83 | 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 | 83 | code = 0; |
600 | 83 | } |
601 | 83 | } |
602 | 83 | if (pct != 0) |
603 | 83 | gs_free_object(pgs->memory, pct, "gs_gstate_update_overprint"); |
604 | | |
605 | | /* the following hack handles devices that don't support compositors */ |
606 | 83 | if (code == gs_error_unknownerror && !pparams->retain_any_comps) |
607 | 0 | code = 0; |
608 | 83 | return code; |
609 | 83 | } |
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 | 82 | { |
630 | 82 | const gs_color_space * pcs = gs_currentcolorspace_inline(pgs); |
631 | 82 | const gs_client_color * pcc = gs_currentcolor_inline(pgs); |
632 | 82 | int code = 0; |
633 | | |
634 | 82 | if (cs_num_components(pcs) < 0 && pcc->pattern != 0) |
635 | 0 | code = pcc->pattern->type->procs.set_color(pcc, pgs); |
636 | 82 | else { |
637 | 82 | gx_device* dev = pgs->device; |
638 | 82 | cmm_dev_profile_t* dev_profile; |
639 | 82 | gs_color_space_index pcs_index = gs_color_space_get_index(pcs); |
640 | | |
641 | 82 | dev_proc(dev, get_profile)(dev, &dev_profile); |
642 | 82 | 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 | 82 | if (dev_proc(dev, dev_spec_op)(dev, gxdso_pdf14_sep_device, NULL, 0) && |
650 | 82 | (dev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE) && |
651 | 82 | (pcs_index == gs_color_space_index_DeviceN || |
652 | 0 | pcs_index == gs_color_space_index_Separation)) { |
653 | 0 | if (pcs_index == gs_color_space_index_Separation) { |
654 | 0 | if (!(pcs->params.separation.color_type == SEP_MIX || |
655 | 0 | pcs->params.separation.color_type == SEP_ENUM)) { |
656 | | /* Sep color is not a spot color. We can't do OP and trans */ |
657 | 0 | return code; |
658 | 0 | } |
659 | 0 | } |
660 | 0 | if (pcs_index == gs_color_space_index_DeviceN) { |
661 | 0 | if (pcs->params.device_n.color_type != SEP_PURE_SPOT) { |
662 | | /* DeviceN has process colors We can't do OP and trans. */ |
663 | 0 | return code; |
664 | 0 | } |
665 | 0 | } |
666 | 0 | } |
667 | | |
668 | | /* If we have a CIE-based space, use the ICC equivalent space */ |
669 | 82 | if (gs_color_space_is_PSCIE(pcs) && pcs->icc_equivalent != NULL) |
670 | 0 | pcs = pcs->icc_equivalent; |
671 | | |
672 | | /* The spaces that do not allow opm (e.g. ones that are not ICC or DeviceCMYK) |
673 | | will blow away any true setting later. But we have to be prepared |
674 | | in case this is a CMYK ICC space for example. Hence we set effective mode |
675 | | to mode here (Bug 698721)*/ |
676 | 82 | pgs->color[0].effective_opm = pgs->overprint_mode; |
677 | | |
678 | 82 | if_debug2m(gs_debug_flag_overprint, pgs->memory, |
679 | 82 | "[overprint] gs_do_set_overprint. Preset effective mode. pgs->color[0].effective_opm = %d pgs->color[1].effective_opm = %d\n", |
680 | 82 | pgs->color[0].effective_opm, pgs->color[1].effective_opm); |
681 | | |
682 | 82 | pcs->type->set_overprint(pcs, pgs); |
683 | 82 | } |
684 | 82 | return code; |
685 | 82 | } |
686 | | |
687 | | /* setoverprint (non-stroke case) interpreter code |
688 | | ensures that this is called when appropriate. This |
689 | | should only be coming when we are doing PS files. |
690 | | As they don't have separate stroke and fill overprint |
691 | | controls */ |
692 | | void |
693 | | gs_setoverprint(gs_gstate * pgs, bool ovp) |
694 | 11.1k | { |
695 | 11.1k | pgs->overprint = ovp; |
696 | 11.1k | pgs->stroke_overprint = ovp; |
697 | 11.1k | } |
698 | | |
699 | | /* currentoverprint */ |
700 | | bool |
701 | | gs_currentoverprint(const gs_gstate * pgs) |
702 | 5.59k | { |
703 | 5.59k | return pgs->overprint; |
704 | 5.59k | } |
705 | | |
706 | | /* setstrokeoverprint */ |
707 | | void |
708 | | gs_setstrokeoverprint(gs_gstate * pgs, bool ovp) |
709 | 2.46k | { |
710 | 2.46k | pgs->stroke_overprint = ovp; |
711 | 2.46k | } |
712 | | |
713 | | /* currentstrokeoverprint */ |
714 | | bool |
715 | | gs_currentstrokeoverprint(const gs_gstate * pgs) |
716 | 0 | { |
717 | 0 | return pgs->stroke_overprint; |
718 | 0 | } |
719 | | |
720 | | /* setstrokeoverprint */ |
721 | | void |
722 | | gs_setfilloverprint(gs_gstate * pgs, bool ovp) |
723 | 2.46k | { |
724 | 2.46k | pgs->overprint = ovp; |
725 | 2.46k | } |
726 | | |
727 | | /* currentstrokeoverprint */ |
728 | | bool |
729 | | gs_currentfilloverprint(const gs_gstate * pgs) |
730 | 0 | { |
731 | 0 | return pgs->overprint; |
732 | 0 | } |
733 | | |
734 | | /* setoverprintmode */ |
735 | | int |
736 | | gs_setoverprintmode(gs_gstate * pgs, int mode) |
737 | 14.0k | { |
738 | 14.0k | if (mode < 0 || mode > 1) |
739 | 0 | return_error(gs_error_rangecheck); |
740 | 14.0k | pgs->overprint_mode = mode; |
741 | | |
742 | 14.0k | return 0; |
743 | 14.0k | } |
744 | | |
745 | | /* currentoverprintmode */ |
746 | | int |
747 | | gs_currentoverprintmode(const gs_gstate * pgs) |
748 | 0 | { |
749 | 0 | return pgs->overprint_mode; |
750 | 0 | } |
751 | | |
752 | | void |
753 | | gs_setcpsimode(gs_memory_t *mem, bool mode) |
754 | 0 | { |
755 | 0 | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
756 | |
|
757 | 0 | libctx->core->CPSI_mode = mode; |
758 | 0 | } |
759 | | |
760 | | /* currentcpsimode */ |
761 | | bool |
762 | | gs_currentcpsimode(const gs_memory_t * mem) |
763 | 2.61M | { |
764 | 2.61M | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
765 | | |
766 | 2.61M | return libctx->core->CPSI_mode; |
767 | 2.61M | } |
768 | | |
769 | | /* The edgebuffer based scanconverter can only cope with values of 0 |
770 | | * or 0.5 (i.e. 'center of pixel' or 'any part of pixel'). These |
771 | | * are the only values required for correct behaviour according to |
772 | | * the PDF and PS specs. Therefore, if we are using the edgebuffer |
773 | | * based scan converter, force these values. */ |
774 | | static void |
775 | | sanitize_fill_adjust(gs_gstate * pgs) |
776 | 2.03k | { |
777 | 2.03k | int scanconverter = gs_getscanconverter(pgs->memory); |
778 | 2.03k | if (scanconverter >= GS_SCANCONVERTER_EDGEBUFFER || (GS_SCANCONVERTER_DEFAULT_IS_EDGEBUFFER && scanconverter == GS_SCANCONVERTER_DEFAULT)) { |
779 | 2.03k | fixed adjust = (pgs->fill_adjust.x >= float2fixed(0.25) || pgs->fill_adjust.y >= float2fixed(0.25) ? fixed_half : 0); |
780 | 2.03k | pgs->fill_adjust.x = adjust; |
781 | 2.03k | pgs->fill_adjust.y = adjust; |
782 | 2.03k | } |
783 | 2.03k | } |
784 | | |
785 | | void |
786 | | gs_setscanconverter(gs_gstate * gs, int converter) |
787 | 0 | { |
788 | 0 | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(gs->memory); |
789 | |
|
790 | 0 | libctx->core->scanconverter = converter; |
791 | |
|
792 | 0 | sanitize_fill_adjust(gs); |
793 | 0 | } |
794 | | |
795 | | /* getscanconverter */ |
796 | | int |
797 | | gs_getscanconverter(const gs_memory_t * mem) |
798 | 432k | { |
799 | 432k | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
800 | | |
801 | 432k | return libctx->core->scanconverter; |
802 | 432k | } |
803 | | |
804 | | /* setrenderingintent |
805 | | * |
806 | | * Use ICC numbers from Table 18 (section 6.1.11) rather than the PDF order |
807 | | * to reduce re-coding and confusion. |
808 | | * Perceptual 0 |
809 | | * Relative Colorimetric 1 |
810 | | * Saturation 2 |
811 | | * AbsoluteColorimetric 3 |
812 | | */ |
813 | | int |
814 | 13.2k | gs_setrenderingintent(gs_gstate *pgs, int ri) { |
815 | 13.2k | if (ri < 0 || ri > 3) |
816 | 0 | return_error(gs_error_rangecheck); |
817 | 13.2k | pgs->renderingintent = ri; |
818 | 13.2k | return 0; |
819 | 13.2k | } |
820 | | |
821 | | /* currentrenderingintent */ |
822 | | int |
823 | | gs_currentrenderingintent(const gs_gstate * pgs) |
824 | 5.99k | { |
825 | 5.99k | return pgs->renderingintent; |
826 | 5.99k | } |
827 | | |
828 | | int |
829 | 0 | gs_setblackptcomp(gs_gstate *pgs, bool bkpt) { |
830 | 0 | pgs->blackptcomp = bkpt; |
831 | 0 | return 0; |
832 | 0 | } |
833 | | |
834 | | /* currentrenderingintent */ |
835 | | bool |
836 | | gs_currentblackptcomp(const gs_gstate * pgs) |
837 | 0 | { |
838 | 0 | return pgs->blackptcomp; |
839 | 0 | } |
840 | | |
841 | | /* |
842 | | * Reset most of the graphics state. |
843 | | */ |
844 | | int |
845 | | gs_initgraphics(gs_gstate * pgs) |
846 | 5.71k | { |
847 | 5.71k | int code; |
848 | 5.71k | const gs_gstate gstate_initial = { |
849 | 5.71k | gs_gstate_initial(1.0) |
850 | 5.71k | }; |
851 | 5.71k | gs_matrix m; |
852 | 5.71k | gs_make_identity(&m); |
853 | | |
854 | 5.71k | gs_initmatrix(pgs); |
855 | 5.71k | if ((code = gs_newpath(pgs)) < 0 || |
856 | 5.71k | (code = gs_initclip(pgs)) < 0 || |
857 | 5.71k | (code = gs_setlinewidth(pgs, 1.0)) < 0 || |
858 | 5.71k | (code = gs_setlinestartcap(pgs, gstate_initial.line_params.start_cap)) < 0 || |
859 | 5.71k | (code = gs_setlineendcap(pgs, gstate_initial.line_params.end_cap)) < 0 || |
860 | 5.71k | (code = gs_setlinedashcap(pgs, gstate_initial.line_params.dash_cap)) < 0 || |
861 | 5.71k | (code = gs_setlinejoin(pgs, gstate_initial.line_params.join)) < 0 || |
862 | 5.71k | (code = gs_setcurvejoin(pgs, gstate_initial.line_params.curve_join)) < 0 || |
863 | 5.71k | (code = gs_setdash(pgs, (float *)0, 0, 0.0)) < 0 || |
864 | 5.71k | (gs_setdashadapt(pgs, false), |
865 | 5.71k | (code = gs_setdotlength(pgs, 0.0, false))) < 0 || |
866 | 5.71k | (code = gs_setdotorientation(pgs)) < 0 || |
867 | 5.71k | (code = gs_setmiterlimit(pgs, gstate_initial.line_params.miter_limit)) < 0 |
868 | 5.71k | ) |
869 | 0 | return code; |
870 | 5.71k | gs_init_rop(pgs); |
871 | | /* Initialize things so that gx_remap_color won't crash. */ |
872 | 5.71k | if (pgs->icc_manager->default_gray == 0x00) { |
873 | 683 | gs_color_space *pcs1, *pcs2; |
874 | | |
875 | 683 | pcs1 = gs_cspace_new_DeviceGray(pgs->memory); |
876 | 683 | if (pcs1 == NULL) |
877 | 0 | return_error(gs_error_unknownerror); |
878 | | |
879 | 683 | if (pgs->color[0].color_space != NULL) { |
880 | 0 | gs_setcolorspace(pgs, pcs1); |
881 | 0 | rc_decrement_cs(pcs1, "gs_initgraphics"); |
882 | 683 | } else { |
883 | 683 | pgs->color[0].color_space = pcs1; |
884 | 683 | gs_setcolorspace(pgs, pcs1); |
885 | 683 | } |
886 | 683 | code = gx_set_dev_color(pgs); |
887 | 683 | if (code < 0) |
888 | 0 | return code; |
889 | | |
890 | 683 | gs_swapcolors_quick(pgs); /* To color 1 */ |
891 | | |
892 | 683 | pcs2 = gs_cspace_new_DeviceGray(pgs->memory); |
893 | 683 | if (pcs2 == NULL) |
894 | 0 | return_error(gs_error_unknownerror); |
895 | | |
896 | 683 | if (pgs->color[0].color_space != NULL) { |
897 | 0 | gs_setcolorspace(pgs, pcs2); |
898 | 0 | rc_decrement_cs(pcs2, "gs_initgraphics"); |
899 | 683 | } else { |
900 | 683 | pgs->color[0].color_space = pcs2; |
901 | 683 | gs_setcolorspace(pgs, pcs2); |
902 | 683 | } |
903 | 683 | code = gx_set_dev_color(pgs); |
904 | | |
905 | 683 | gs_swapcolors_quick(pgs); /* To color 0 */ |
906 | | |
907 | 683 | if (code < 0) |
908 | 0 | return code; |
909 | | |
910 | 5.03k | } else { |
911 | 5.03k | gs_color_space *pcs1, *pcs2; |
912 | | |
913 | 5.03k | pcs1 = gs_cspace_new_ICC(pgs->memory, pgs, 1); |
914 | 5.03k | if (pcs1 == NULL) |
915 | 0 | return_error(gs_error_unknownerror); |
916 | | |
917 | 5.03k | if (pgs->color[0].color_space != NULL) { |
918 | 4.36k | gs_setcolorspace(pgs, pcs1); |
919 | 4.36k | rc_decrement_cs(pcs1, "gs_initgraphics"); |
920 | 4.36k | } else { |
921 | 669 | pgs->color[0].color_space = pcs1; |
922 | 669 | gs_setcolorspace(pgs, pcs1); |
923 | 669 | } |
924 | 5.03k | code = gx_set_dev_color(pgs); |
925 | 5.03k | if (code < 0) |
926 | 0 | return code; |
927 | | |
928 | 5.03k | gs_swapcolors_quick(pgs); /* To color 1 */ |
929 | 5.03k | pcs2 = gs_cspace_new_ICC(pgs->memory, pgs, 1); |
930 | 5.03k | if (pcs2 == NULL) |
931 | 0 | return_error(gs_error_unknownerror); |
932 | | |
933 | 5.03k | if (pgs->color[0].color_space != NULL) { |
934 | 4.36k | gs_setcolorspace(pgs, pcs2); |
935 | 4.36k | rc_decrement_cs(pcs2, "gs_initgraphics"); |
936 | 4.36k | } else { |
937 | 669 | pgs->color[0].color_space = pcs2; |
938 | 669 | gs_setcolorspace(pgs, pcs2); |
939 | 669 | } |
940 | 5.03k | code = gx_set_dev_color(pgs); |
941 | | |
942 | 5.03k | gs_swapcolors_quick(pgs); /* To color 0 */ |
943 | | |
944 | 5.03k | if (code < 0) |
945 | 0 | return code; |
946 | 5.03k | } |
947 | 5.71k | pgs->in_cachedevice = 0; |
948 | | |
949 | 5.71k | code = gs_settextspacing(pgs, (double)0.0); |
950 | 5.71k | if (code < 0) |
951 | 0 | goto exit; |
952 | 5.71k | code = gs_settextleading(pgs, (double)0.0); |
953 | 5.71k | if (code < 0) |
954 | 0 | goto exit; |
955 | | |
956 | 5.71k | gs_settextrenderingmode(pgs, 0); |
957 | | |
958 | 5.71k | code = gs_setwordspacing(pgs, (double)0.0); |
959 | 5.71k | if (code < 0) |
960 | 0 | goto exit; |
961 | 5.71k | code = gs_settexthscaling(pgs, (double)100.0); |
962 | 5.71k | if (code < 0) |
963 | 0 | goto exit; |
964 | | |
965 | 5.71k | gs_setaccuratecurves(pgs, true); |
966 | | |
967 | 5.71k | code = gs_setstrokeconstantalpha(pgs, 1.0); |
968 | 5.71k | if (code < 0) |
969 | 0 | goto exit; |
970 | 5.71k | code = gs_setfillconstantalpha(pgs, 1.0); |
971 | 5.71k | if (code < 0) |
972 | 0 | goto exit; |
973 | 5.71k | code = gs_setalphaisshape(pgs, 0); |
974 | 5.71k | if (code < 0) |
975 | 0 | goto exit; |
976 | 5.71k | code = gs_setblendmode(pgs, BLEND_MODE_Compatible); |
977 | 5.71k | if (code < 0) |
978 | 0 | goto exit; |
979 | 5.71k | code = gs_settextknockout(pgs, true); |
980 | 5.71k | if (code < 0) |
981 | 0 | goto exit; |
982 | 5.71k | code = gs_setsmoothness(pgs, 0.02); /* Match gs code */ |
983 | 5.71k | if (code < 0) |
984 | 0 | goto exit; |
985 | | |
986 | 5.71k | code = gs_settextmatrix(pgs, &m); |
987 | 5.71k | if (code < 0) |
988 | 0 | goto exit; |
989 | | |
990 | 5.71k | code = gs_settextlinematrix(pgs, &m); |
991 | 5.71k | if (code < 0) |
992 | 0 | goto exit; |
993 | 5.71k | exit: |
994 | 5.71k | return code; |
995 | 5.71k | } |
996 | | |
997 | | /* setfilladjust */ |
998 | | int |
999 | | gs_setfilladjust(gs_gstate * pgs, double adjust_x, double adjust_y) |
1000 | 2.03k | { |
1001 | 2.03k | #define CLAMP_TO_HALF(v)\ |
1002 | 4.07k | ((v) <= 0 ? fixed_0 : (v) >= 0.5 ? fixed_half : float2fixed(v)); |
1003 | | |
1004 | 2.03k | pgs->fill_adjust.x = CLAMP_TO_HALF(adjust_x); |
1005 | 2.03k | pgs->fill_adjust.y = CLAMP_TO_HALF(adjust_y); |
1006 | | |
1007 | 2.03k | sanitize_fill_adjust(pgs); |
1008 | | |
1009 | 2.03k | return 0; |
1010 | 2.03k | #undef CLAMP_TO_HALF |
1011 | 2.03k | } |
1012 | | |
1013 | | /* currentfilladjust */ |
1014 | | int |
1015 | | gs_currentfilladjust(const gs_gstate * pgs, gs_point * adjust) |
1016 | 9.30k | { |
1017 | 9.30k | adjust->x = fixed2float(pgs->fill_adjust.x); |
1018 | 9.30k | adjust->y = fixed2float(pgs->fill_adjust.y); |
1019 | 9.30k | return 0; |
1020 | 9.30k | } |
1021 | | |
1022 | | /* setlimitclamp */ |
1023 | | void |
1024 | | gs_setlimitclamp(gs_gstate * pgs, bool clamp) |
1025 | 2.70k | { |
1026 | 2.70k | pgs->clamp_coordinates = clamp; |
1027 | 2.70k | } |
1028 | | |
1029 | | /* currentlimitclamp */ |
1030 | | bool |
1031 | | gs_currentlimitclamp(const gs_gstate * pgs) |
1032 | 0 | { |
1033 | 0 | return pgs->clamp_coordinates; |
1034 | 0 | } |
1035 | | |
1036 | | /* settextrenderingmode */ |
1037 | | void |
1038 | | gs_settextrenderingmode(gs_gstate * pgs, uint trm) |
1039 | 11.0k | { |
1040 | 11.0k | pgs->text_rendering_mode = trm; |
1041 | 11.0k | } |
1042 | | |
1043 | | /* currenttextrenderingmode */ |
1044 | | uint |
1045 | | gs_currenttextrenderingmode(const gs_gstate * pgs) |
1046 | 899k | { |
1047 | 899k | return pgs->text_rendering_mode; |
1048 | 899k | } |
1049 | | |
1050 | | double |
1051 | | gs_currenttextspacing(const gs_gstate *pgs) |
1052 | 557k | { |
1053 | 557k | return pgs->textspacing; |
1054 | 557k | } |
1055 | | |
1056 | | int |
1057 | | gs_settextspacing(gs_gstate *pgs, double Tc) |
1058 | 32.1k | { |
1059 | 32.1k | int code = 0; |
1060 | 32.1k | gs_fixed_point dxy; |
1061 | | |
1062 | 32.1k | code = gs_distance_transform2fixed(&pgs->ctm, Tc, 1, &dxy); |
1063 | 32.1k | if (code < 0) |
1064 | 1 | return code; |
1065 | | |
1066 | 32.1k | pgs->textspacing = (float)Tc; |
1067 | 32.1k | return 0; |
1068 | 32.1k | } |
1069 | | |
1070 | | double |
1071 | | gs_currenttextleading(const gs_gstate *pgs) |
1072 | 0 | { |
1073 | 0 | return pgs->textleading; |
1074 | 0 | } |
1075 | | |
1076 | | int |
1077 | | gs_settextleading(gs_gstate *pgs, double TL) |
1078 | 20.5k | { |
1079 | 20.5k | pgs->textleading = (float)TL; |
1080 | 20.5k | return 0; |
1081 | 20.5k | } |
1082 | | |
1083 | | double |
1084 | | gs_currenttextrise(const gs_gstate *pgs) |
1085 | 0 | { |
1086 | 0 | return pgs->textrise; |
1087 | 0 | } |
1088 | | |
1089 | | int |
1090 | | gs_settextrise(gs_gstate *pgs, double Ts) |
1091 | 54 | { |
1092 | 54 | pgs->textrise = (float)Ts; |
1093 | 54 | return 0; |
1094 | 54 | } |
1095 | | |
1096 | | double |
1097 | | gs_currentwordspacing(const gs_gstate *pgs) |
1098 | 557k | { |
1099 | 557k | return pgs->wordspacing; |
1100 | 557k | } |
1101 | | |
1102 | | int |
1103 | | gs_setwordspacing(gs_gstate *pgs, double Tw) |
1104 | 8.36k | { |
1105 | 8.36k | pgs->wordspacing = (float)Tw; |
1106 | 8.36k | return 0; |
1107 | 8.36k | } |
1108 | | |
1109 | | int |
1110 | | gs_settexthscaling(gs_gstate *pgs, double Tz) |
1111 | 31.4k | { |
1112 | 31.4k | pgs->texthscaling = (float)Tz; |
1113 | 31.4k | return 0; |
1114 | 31.4k | } |
1115 | | |
1116 | | double |
1117 | | gs_currenttexthscaling(const gs_gstate *pgs) |
1118 | 0 | { |
1119 | 0 | return pgs->texthscaling; |
1120 | 0 | } |
1121 | | |
1122 | | int |
1123 | | gs_setPDFfontsize(gs_gstate *pgs, double Tf) |
1124 | 35.8k | { |
1125 | 35.8k | pgs->PDFfontsize = (float)Tf; |
1126 | 35.8k | return 0; |
1127 | 35.8k | } |
1128 | | |
1129 | | double |
1130 | | gs_currentPDFfontsize(const gs_gstate *pgs) |
1131 | 0 | { |
1132 | 0 | return pgs->PDFfontsize; |
1133 | 0 | } |
1134 | | |
1135 | | int |
1136 | | gs_settextlinematrix(gs_gstate *pgs, gs_matrix *m) |
1137 | 234k | { |
1138 | 234k | pgs->textlinematrix.xx = m->xx; |
1139 | 234k | pgs->textlinematrix.xy = m->xy; |
1140 | 234k | pgs->textlinematrix.yx = m->yx; |
1141 | 234k | pgs->textlinematrix.yy = m->yy; |
1142 | 234k | pgs->textlinematrix.tx = m->tx; |
1143 | 234k | pgs->textlinematrix.ty = m->ty; |
1144 | 234k | return 0; |
1145 | 234k | } |
1146 | | int |
1147 | | gs_gettextlinematrix(gs_gstate *pgs, gs_matrix *m) |
1148 | 0 | { |
1149 | 0 | m->xx = pgs->textlinematrix.xx; |
1150 | 0 | m->xy = pgs->textlinematrix.xy; |
1151 | 0 | m->yx = pgs->textlinematrix.yx; |
1152 | 0 | m->yy = pgs->textlinematrix.yy; |
1153 | 0 | m->tx = pgs->textlinematrix.tx; |
1154 | 0 | m->ty = pgs->textlinematrix.ty; |
1155 | 0 | return 0; |
1156 | 0 | } |
1157 | | |
1158 | | int |
1159 | | gs_settextmatrix(gs_gstate *pgs, gs_matrix *m) |
1160 | 234k | { |
1161 | 234k | pgs->textmatrix.xx = m->xx; |
1162 | 234k | pgs->textmatrix.xy = m->xy; |
1163 | 234k | pgs->textmatrix.yx = m->yx; |
1164 | 234k | pgs->textmatrix.yy = m->yy; |
1165 | 234k | pgs->textmatrix.tx = m->tx; |
1166 | 234k | pgs->textmatrix.ty = m->ty; |
1167 | 234k | return 0; |
1168 | 234k | } |
1169 | | int |
1170 | | gs_gettextmatrix(gs_gstate *pgs, gs_matrix *m) |
1171 | 0 | { |
1172 | 0 | m->xx = pgs->textmatrix.xx; |
1173 | 0 | m->xy = pgs->textmatrix.xy; |
1174 | 0 | m->yx = pgs->textmatrix.yx; |
1175 | 0 | m->yy = pgs->textmatrix.yy; |
1176 | 0 | m->tx = pgs->textmatrix.tx; |
1177 | 0 | m->ty = pgs->textmatrix.ty; |
1178 | 0 | return 0; |
1179 | 0 | } |
1180 | | |
1181 | | |
1182 | | /* sethpglpathmode */ |
1183 | | void |
1184 | | gs_sethpglpathmode(gs_gstate * pgs, bool path) |
1185 | 0 | { |
1186 | 0 | pgs->hpgl_path_mode = path; |
1187 | 0 | } |
1188 | | |
1189 | | /* currenthpglpathmode */ |
1190 | | bool |
1191 | | gs_currenthpglpathmode(const gs_gstate * pgs) |
1192 | 0 | { |
1193 | 0 | return pgs->hpgl_path_mode; |
1194 | 0 | } |
1195 | | |
1196 | | /* ------ Internal routines ------ */ |
1197 | | |
1198 | | /* Free the privately allocated parts of a gstate. */ |
1199 | | static void |
1200 | | gstate_free_parts(gs_gstate * parts, gs_memory_t * mem, client_name_t cname) |
1201 | 1.54M | { |
1202 | 1.54M | gs_free_object(mem, parts->color[1].dev_color, cname); |
1203 | 1.54M | gs_free_object(mem, parts->color[1].ccolor, cname); |
1204 | 1.54M | gs_free_object(mem, parts->color[0].dev_color, cname); |
1205 | 1.54M | gs_free_object(mem, parts->color[0].ccolor, cname); |
1206 | 1.54M | parts->color[1].dev_color = 0; |
1207 | 1.54M | parts->color[1].ccolor = 0; |
1208 | 1.54M | parts->color[0].dev_color = 0; |
1209 | 1.54M | parts->color[0].ccolor = 0; |
1210 | 1.54M | if (!parts->effective_clip_shared && parts->effective_clip_path) { |
1211 | 0 | gx_cpath_free(parts->effective_clip_path, cname); |
1212 | 0 | parts->effective_clip_path = 0; |
1213 | 0 | } |
1214 | 1.54M | gx_cpath_free(parts->clip_path, cname); |
1215 | 1.54M | parts->clip_path = 0; |
1216 | 1.54M | if (parts->path) { |
1217 | 775k | gx_path_free(parts->path, cname); |
1218 | 775k | parts->path = 0; |
1219 | 775k | } |
1220 | 1.54M | } |
1221 | | |
1222 | | static inline void |
1223 | | gstate_parts_init_dev_color(gx_device_color *dc) |
1224 | 1.55M | { |
1225 | 1.55M | gx_device_color_type dct = dc->type; |
1226 | 1.55M | gs_graphics_type_tag_t gtt = dc->tag; |
1227 | 1.55M | memset(dc, 0x00, sizeof(gx_device_color)); |
1228 | 1.55M | dc->type = dct; |
1229 | 1.55M | dc->tag = gtt; |
1230 | 1.55M | } |
1231 | | |
1232 | | /* Allocate the privately allocated parts of a gstate. */ |
1233 | | static int |
1234 | | gstate_alloc_parts(gs_gstate * parts, const gs_gstate * shared, |
1235 | | gs_memory_t * mem, client_name_t cname) |
1236 | 775k | { |
1237 | 775k | gs_memory_t *path_mem = gstate_path_memory(mem); |
1238 | | |
1239 | 775k | parts->path = |
1240 | 775k | (shared ? |
1241 | 774k | gx_path_alloc_shared(shared->path, path_mem, |
1242 | 774k | "gstate_alloc_parts(path)") : |
1243 | 775k | gx_path_alloc(path_mem, "gstate_alloc_parts(path)")); |
1244 | 775k | parts->clip_path = |
1245 | 775k | (shared ? |
1246 | 774k | gx_cpath_alloc_shared(shared->clip_path, mem, |
1247 | 774k | "gstate_alloc_parts(clip_path)") : |
1248 | 775k | gx_cpath_alloc(mem, "gstate_alloc_parts(clip_path)")); |
1249 | 775k | if (!shared || shared->effective_clip_shared) { |
1250 | 775k | parts->effective_clip_path = parts->clip_path; |
1251 | 775k | parts->effective_clip_shared = true; |
1252 | 775k | } else { |
1253 | 0 | parts->effective_clip_path = |
1254 | 0 | gx_cpath_alloc_shared(shared->effective_clip_path, mem, |
1255 | 0 | "gstate_alloc_parts(effective_clip_path)"); |
1256 | 0 | parts->effective_clip_shared = false; |
1257 | 0 | } |
1258 | 775k | parts->color[0].color_space = NULL; |
1259 | 775k | parts->color[1].color_space = NULL; |
1260 | 775k | parts->color[0].ccolor = |
1261 | 775k | gs_alloc_struct(mem, gs_client_color, &st_client_color, cname); |
1262 | 775k | parts->color[1].ccolor = |
1263 | 775k | gs_alloc_struct(mem, gs_client_color, &st_client_color, cname); |
1264 | 775k | parts->color[0].dev_color = |
1265 | 775k | gs_alloc_struct(mem, gx_device_color, &st_device_color, cname); |
1266 | 775k | parts->color[1].dev_color = |
1267 | 775k | gs_alloc_struct(mem, gx_device_color, &st_device_color, cname); |
1268 | 775k | if (parts->path == 0 || parts->clip_path == 0 || |
1269 | 775k | parts->effective_clip_path == 0 || |
1270 | 775k | parts->color[0].ccolor == 0 || parts->color[0].dev_color == 0 || |
1271 | 775k | parts->color[1].ccolor == 0 || parts->color[1].dev_color == 0 |
1272 | 775k | ) { |
1273 | 0 | gstate_free_parts(parts, mem, cname); |
1274 | 0 | return_error(gs_error_VMerror); |
1275 | 0 | } |
1276 | 775k | gstate_parts_init_dev_color(parts->color[0].dev_color); |
1277 | 775k | gstate_parts_init_dev_color(parts->color[1].dev_color); |
1278 | 775k | return 0; |
1279 | 775k | } |
1280 | | |
1281 | | /* |
1282 | | * Allocate a gstate and its contents. |
1283 | | * If pfrom is not NULL, the path, clip_path, and (if distinct from both |
1284 | | * clip_path and view_clip) effective_clip_path share the segments of |
1285 | | * pfrom's corresponding path(s). |
1286 | | */ |
1287 | | static gs_gstate * |
1288 | | gstate_alloc(gs_memory_t * mem, client_name_t cname, const gs_gstate * pfrom) |
1289 | 775k | { |
1290 | 775k | gs_gstate *pgs = |
1291 | 775k | gs_alloc_struct(mem, gs_gstate, &st_gs_gstate, cname); |
1292 | | |
1293 | 775k | if (pgs == NULL) |
1294 | 0 | return NULL; |
1295 | 775k | memset(pgs, 0x00, sizeof(gs_gstate)); |
1296 | 775k | if (gstate_alloc_parts(pgs, pfrom, mem, cname) < 0) { |
1297 | 0 | gs_free_object(mem, pgs, cname); |
1298 | 0 | return NULL; |
1299 | 0 | } |
1300 | 775k | pgs->memory = mem; |
1301 | 775k | return pgs; |
1302 | 775k | } |
1303 | | |
1304 | | /* Copy the dash pattern from one gstate to another. */ |
1305 | | static int |
1306 | | gstate_copy_dash(gs_memory_t *mem, gx_dash_params *dash , const gs_gstate * pfrom) |
1307 | 7.58k | { |
1308 | 7.58k | return gx_set_dash(dash, pfrom->line_params.dash.pattern, |
1309 | 7.58k | pfrom->line_params.dash.pattern_size, |
1310 | 7.58k | pfrom->line_params.dash.offset, mem); |
1311 | 7.58k | } |
1312 | | |
1313 | | typedef struct { |
1314 | | gs_gstate_parts parts; |
1315 | | gx_dash_params dash; |
1316 | | } gs_gstate_clone_data; |
1317 | | |
1318 | | static gs_gstate * |
1319 | | gstate_clone_core(const gs_gstate *pfrom, |
1320 | | gs_memory_t *mem, |
1321 | | client_name_t cname, |
1322 | | gs_gstate_clone_data *clone_data, |
1323 | | gs_gstate_copy_reason_t reason) |
1324 | 774k | { |
1325 | 774k | gs_gstate *pgs = gstate_alloc(mem, cname, pfrom); |
1326 | 774k | void *pdata = NULL; |
1327 | | |
1328 | 774k | if (pgs == NULL) |
1329 | 0 | return NULL; |
1330 | 774k | if (pfrom->client_data != NULL) { |
1331 | 773k | pdata = (*pfrom->client_procs.alloc) (mem); |
1332 | | |
1333 | 773k | if (pdata == NULL || |
1334 | 773k | gstate_copy_client_data(pfrom, pdata, pfrom->client_data, |
1335 | 773k | reason) < 0) |
1336 | 0 | goto failEarly; |
1337 | 773k | } |
1338 | | /* Copy the dash and dash pattern if necessary. */ |
1339 | 774k | clone_data->dash = gs_currentlineparams_inline(pfrom)->dash; |
1340 | 774k | if (clone_data->dash.pattern) { |
1341 | 7.56k | int code; |
1342 | | |
1343 | 7.56k | clone_data->dash.pattern = NULL; /* Ensures a fresh allocation */ |
1344 | 7.56k | code = gstate_copy_dash(mem, &clone_data->dash, pfrom); |
1345 | 7.56k | if (code < 0) |
1346 | 0 | goto fail; |
1347 | 7.56k | } |
1348 | | /* Some records within pgs are allocated. We copy pfrom into pgs |
1349 | | * wholesale (to avoid problems with the structure being updated and |
1350 | | * us having to keep it in sync), so we copy those allocated regions |
1351 | | * out first. The caller of this routine will then put them back |
1352 | | * into either pgs or pfrom as appropriate. */ |
1353 | 774k | GSTATE_ASSIGN_PARTS(&clone_data->parts, pgs); |
1354 | 774k | *pgs = *pfrom; |
1355 | 774k | pgs->client_data = pdata; |
1356 | | |
1357 | 774k | gs_gstate_copied(pgs); |
1358 | | /* Don't do anything to clip_stack. */ |
1359 | | |
1360 | 774k | rc_increment(pgs->device); |
1361 | 774k | *clone_data->parts.color[0].ccolor = *pgs->color[0].ccolor; |
1362 | 774k | *clone_data->parts.color[0].dev_color = *pgs->color[0].dev_color; |
1363 | 774k | *clone_data->parts.color[1].ccolor = *pgs->color[1].ccolor; |
1364 | 774k | *clone_data->parts.color[1].dev_color = *pgs->color[1].dev_color; |
1365 | 774k | cs_adjust_counts_icc(pgs, 1); |
1366 | 774k | cs_adjust_swappedcounts_icc(pgs, 1); |
1367 | | |
1368 | 774k | return pgs; |
1369 | | |
1370 | 0 | fail: |
1371 | 0 | gs_free_object(mem, clone_data->dash.pattern, cname); |
1372 | 0 | if (pdata != NULL) |
1373 | 0 | (*pfrom->client_procs.free) (pdata, mem, pgs); |
1374 | 0 | failEarly: |
1375 | 0 | gstate_free_parts(pgs, mem, cname); |
1376 | 0 | gs_free_object(mem, pgs, cname); |
1377 | |
|
1378 | 0 | return NULL; |
1379 | 0 | } |
1380 | | |
1381 | | |
1382 | | /* Clone an existing graphics state for use in gsave. The clone refers |
1383 | | * to the old contents, and the old state refers to the new contents. */ |
1384 | | /* Return NULL if the allocation fails. */ |
1385 | | static gs_gstate * |
1386 | | gstate_clone_for_gsave(gs_gstate *pfrom, |
1387 | | client_name_t cname) |
1388 | 750k | { |
1389 | 750k | gs_gstate_clone_data clone_data; |
1390 | 750k | gs_gstate *pgs = gstate_clone_core(pfrom, pfrom->memory, cname, |
1391 | 750k | &clone_data, copy_for_gsave); |
1392 | | |
1393 | 750k | if (pgs == NULL) |
1394 | 0 | return NULL; |
1395 | | |
1396 | | /* Newly allocated parts go back into pfrom, not pgs! */ |
1397 | 750k | GSTATE_ASSIGN_PARTS(pfrom, &clone_data.parts); |
1398 | 750k | gs_currentlineparams_inline(pfrom)->dash = clone_data.dash; |
1399 | | |
1400 | 750k | return pgs; |
1401 | 750k | } |
1402 | | |
1403 | | /* Clone an existing graphics state. The view_clip is not copied. */ |
1404 | | /* Return NULL if the allocation fails. */ |
1405 | | static gs_gstate * |
1406 | | gstate_clone_for_gstate(const gs_gstate *pfrom, |
1407 | | gs_memory_t *mem, |
1408 | | client_name_t cname) |
1409 | 23.6k | { |
1410 | 23.6k | gs_gstate_clone_data clone_data; |
1411 | 23.6k | gs_gstate *pgs = gstate_clone_core(pfrom, mem, cname, &clone_data, |
1412 | 23.6k | copy_for_gstate); |
1413 | | |
1414 | 23.6k | if (pgs == NULL) |
1415 | 0 | return NULL; |
1416 | 23.6k | GSTATE_ASSIGN_PARTS(pgs, &clone_data.parts); |
1417 | 23.6k | pgs->view_clip = NULL; |
1418 | 23.6k | gs_currentlineparams_inline(pgs)->dash = clone_data.dash; |
1419 | 23.6k | pgs->memory = mem; |
1420 | | |
1421 | 23.6k | return pgs; |
1422 | 23.6k | } |
1423 | | |
1424 | | /* Adjust reference counters for the whole clip stack */ |
1425 | | /* accessible from the given point */ |
1426 | | static void |
1427 | | clip_stack_rc_adjust(gx_clip_stack_t *cs, int delta, client_name_t cname) |
1428 | 1.57M | { |
1429 | 1.57M | gx_clip_stack_t *p = cs; |
1430 | | |
1431 | 1.57M | while(p) { |
1432 | 0 | gx_clip_stack_t *q = p; |
1433 | 0 | p = p->next; |
1434 | 0 | rc_adjust(q, delta, cname); |
1435 | 0 | } |
1436 | 1.57M | } |
1437 | | |
1438 | | /* |
1439 | | * Finalization for graphics states. This is where we handle RC for those |
1440 | | * elements. |
1441 | | */ |
1442 | | void |
1443 | | gs_gstate_finalize(const gs_memory_t *cmem,void *vptr) |
1444 | 775k | { |
1445 | 775k | gs_gstate *pgs = (gs_gstate *)vptr; |
1446 | 775k | (void)cmem; /* unused */ |
1447 | | |
1448 | 775k | if (cmem == NULL) |
1449 | 0 | return; /* place for breakpoint */ |
1450 | 775k | gstate_free_contents(pgs); |
1451 | 775k | } |
1452 | | |
1453 | | /* Release the composite parts of a graphics state, */ |
1454 | | /* but not the state itself. */ |
1455 | | static void |
1456 | | gstate_free_contents(gs_gstate * pgs) |
1457 | 1.54M | { |
1458 | 1.54M | gs_memory_t *mem = pgs->memory; |
1459 | 1.54M | const char *const cname = "gstate_free_contents"; |
1460 | | |
1461 | 1.54M | rc_decrement(pgs->device, cname); |
1462 | 1.54M | pgs->device = 0; |
1463 | 1.54M | clip_stack_rc_adjust(pgs->clip_stack, -1, cname); |
1464 | 1.54M | pgs->clip_stack = 0; |
1465 | 1.54M | if (pgs->view_clip != NULL && pgs->level == 0) { |
1466 | 1.35k | gx_cpath_free(pgs->view_clip, cname); |
1467 | 1.35k | pgs->view_clip = NULL; |
1468 | 1.35k | } |
1469 | 1.54M | if (pgs->client_data != 0) |
1470 | 774k | (*pgs->client_procs.free) (pgs->client_data, mem, pgs); |
1471 | 1.54M | pgs->client_data = 0; |
1472 | 1.54M | cs_adjust_counts_icc(pgs, -1); |
1473 | 1.54M | cs_adjust_swappedcounts_icc(pgs, -1); |
1474 | 1.54M | pgs->color[0].color_space = 0; |
1475 | 1.54M | pgs->color[1].color_space = 0; |
1476 | 1.54M | gs_free_object(mem, pgs->line_params.dash.pattern, cname); |
1477 | 1.54M | pgs->line_params.dash.pattern = 0; |
1478 | 1.54M | gstate_free_parts(pgs, mem, cname); /* this also clears pointers to freed elements */ |
1479 | 1.54M | gs_gstate_release(pgs); |
1480 | 1.54M | } |
1481 | | |
1482 | | /* Copy one gstate to another. */ |
1483 | | static int |
1484 | | gstate_copy(gs_gstate * pto, const gs_gstate * pfrom, |
1485 | | gs_gstate_copy_reason_t reason, client_name_t cname) |
1486 | 1.49k | { |
1487 | 1.49k | gs_gstate_parts parts; |
1488 | | |
1489 | 1.49k | GSTATE_ASSIGN_PARTS(&parts, pto); |
1490 | | /* Copy the dash pattern if necessary. */ |
1491 | 1.49k | if (pfrom->line_params.dash.pattern || pto->line_params.dash.pattern) { |
1492 | 21 | int code = gstate_copy_dash(pto->memory, |
1493 | 21 | &(gs_currentlineparams_inline(pto)->dash), pfrom); |
1494 | | |
1495 | 21 | if (code < 0) |
1496 | 0 | return code; |
1497 | 21 | } |
1498 | | /* |
1499 | | * It's OK to decrement the counts before incrementing them, |
1500 | | * because anything that is going to survive has a count of |
1501 | | * at least 2 (pto and somewhere else) initially. |
1502 | | * Handle references from contents. |
1503 | | */ |
1504 | 1.49k | cs_adjust_counts_icc(pto, -1); |
1505 | 1.49k | cs_adjust_swappedcounts_icc(pto, -1); |
1506 | 1.49k | gx_path_assign_preserve(pto->path, pfrom->path); |
1507 | 1.49k | gx_cpath_assign_preserve(pto->clip_path, pfrom->clip_path); |
1508 | | /* |
1509 | | * effective_clip_shared will be copied, but we need to do the |
1510 | | * right thing with effective_clip_path. |
1511 | | */ |
1512 | 1.49k | if (pfrom->effective_clip_shared) { |
1513 | | /* |
1514 | | * pfrom->effective_clip_path is either pfrom->view_clip or |
1515 | | * pfrom->clip_path. |
1516 | | */ |
1517 | 1.49k | parts.effective_clip_path = |
1518 | 1.49k | (pfrom->effective_clip_path == pfrom->view_clip ? |
1519 | 1.49k | pto->view_clip : parts.clip_path); |
1520 | 1.49k | } else |
1521 | 0 | gx_cpath_assign_preserve(pto->effective_clip_path, |
1522 | 0 | pfrom->effective_clip_path); |
1523 | 1.49k | *parts.color[0].ccolor = *pfrom->color[0].ccolor; |
1524 | 1.49k | *parts.color[0].dev_color = *pfrom->color[0].dev_color; |
1525 | 1.49k | *parts.color[1].ccolor = *pfrom->color[1].ccolor; |
1526 | 1.49k | *parts.color[1].dev_color = *pfrom->color[1].dev_color; |
1527 | | /* Handle references from gstate object. */ |
1528 | 1.49k | rc_pre_assign(pto->device, pfrom->device, cname); |
1529 | 1.49k | if (pto->clip_stack != pfrom->clip_stack) { |
1530 | 0 | clip_stack_rc_adjust(pfrom->clip_stack, 1, cname); |
1531 | 0 | clip_stack_rc_adjust(pto->clip_stack, -1, cname); |
1532 | 0 | } |
1533 | 1.49k | { |
1534 | 1.49k | struct gx_pattern_cache_s *pcache = pto->pattern_cache; |
1535 | 1.49k | void *pdata = pto->client_data; |
1536 | 1.49k | gs_memory_t *mem = pto->memory; |
1537 | 1.49k | gs_gstate *saved = pto->saved; |
1538 | 1.49k | float *pattern = pto->line_params.dash.pattern; |
1539 | | |
1540 | 1.49k | gs_gstate_pre_assign(pto, (const gs_gstate *)pfrom); |
1541 | 1.49k | *pto = *pfrom; |
1542 | 1.49k | pto->client_data = pdata; |
1543 | 1.49k | pto->memory = mem; |
1544 | 1.49k | pto->saved = saved; |
1545 | 1.49k | pto->line_params.dash.pattern = pattern; |
1546 | 1.49k | if (pto->pattern_cache == 0) |
1547 | 0 | pto->pattern_cache = pcache; |
1548 | 1.49k | if (pfrom->client_data != 0) { |
1549 | | /* We need to break 'const' here. */ |
1550 | 1.43k | gstate_copy_client_data((gs_gstate *) pfrom, pdata, |
1551 | 1.43k | pfrom->client_data, reason); |
1552 | 1.43k | } |
1553 | 1.49k | } |
1554 | 1.49k | GSTATE_ASSIGN_PARTS(pto, &parts); |
1555 | 1.49k | cs_adjust_counts_icc(pto, 1); |
1556 | 1.49k | cs_adjust_swappedcounts_icc(pto, 1); |
1557 | 1.49k | pto->show_gstate = |
1558 | 1.49k | (pfrom->show_gstate == pfrom ? pto : 0); |
1559 | 1.49k | return 0; |
1560 | 1.49k | } |
1561 | | |
1562 | | /* Accessories. */ |
1563 | | gs_id gx_get_clip_path_id(gs_gstate *pgs) |
1564 | 0 | { |
1565 | 0 | return pgs->clip_path->id; |
1566 | 0 | } |
1567 | | |
1568 | | void gs_swapcolors_quick(const gs_gstate *cpgs) |
1569 | 1.00M | { |
1570 | 1.00M | union { |
1571 | 1.00M | const gs_gstate *cpgs; |
1572 | 1.00M | gs_gstate *pgs; |
1573 | 1.00M | } const_breaker; |
1574 | 1.00M | gs_gstate *pgs; |
1575 | 1.00M | struct gx_cie_joint_caches_s *tmp_cie; |
1576 | 1.00M | gs_devicen_color_map tmp_ccm; |
1577 | 1.00M | gs_client_color *tmp_cc; |
1578 | 1.00M | int tmp; |
1579 | 1.00M | gx_device_color *tmp_dc; |
1580 | 1.00M | gs_color_space *tmp_cs; |
1581 | | |
1582 | | /* Break const just once, neatly, here rather than |
1583 | | * hackily in every caller. */ |
1584 | 1.00M | const_breaker.cpgs = cpgs; |
1585 | 1.00M | pgs = const_breaker.pgs; |
1586 | | |
1587 | 1.00M | tmp_cc = pgs->color[0].ccolor; |
1588 | 1.00M | pgs->color[0].ccolor = pgs->color[1].ccolor; |
1589 | 1.00M | pgs->color[1].ccolor = tmp_cc; |
1590 | | |
1591 | 1.00M | tmp_dc = pgs->color[0].dev_color; |
1592 | 1.00M | pgs->color[0].dev_color = pgs->color[1].dev_color; |
1593 | 1.00M | pgs->color[1].dev_color = tmp_dc; |
1594 | | |
1595 | 1.00M | tmp_cs = pgs->color[0].color_space; |
1596 | 1.00M | pgs->color[0].color_space = pgs->color[1].color_space; |
1597 | 1.00M | pgs->color[1].color_space = tmp_cs; |
1598 | | |
1599 | | /* Overprint and effective_op vary with stroke/fill and cs */ |
1600 | 1.00M | tmp = pgs->color[0].effective_opm; |
1601 | 1.00M | pgs->color[0].effective_opm = pgs->color[1].effective_opm; |
1602 | 1.00M | pgs->color[1].effective_opm = tmp; |
1603 | | |
1604 | | /* Swap the bits of the gs_gstate that depend on the current color */ |
1605 | 1.00M | tmp_cie = pgs->cie_joint_caches; |
1606 | 1.00M | pgs->cie_joint_caches = pgs->cie_joint_caches_alt; |
1607 | 1.00M | pgs->cie_joint_caches_alt = tmp_cie; |
1608 | | |
1609 | 1.00M | tmp_ccm = pgs->color_component_map; |
1610 | 1.00M | pgs->color_component_map = pgs->color_component_map_alt; |
1611 | 1.00M | pgs->color_component_map_alt = tmp_ccm; |
1612 | | |
1613 | 1.00M | pgs->is_fill_color = !(pgs->is_fill_color); /* used by overprint for fill_stroke */ |
1614 | 1.00M | } |