/src/ghostpdl/pcl/pxl/pxsessio.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2023 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 | | /* pxsessio.c */ |
18 | | /* PCL XL session operators */ |
19 | | |
20 | | #include "math_.h" /* for fabs */ |
21 | | #include "stdio_.h" |
22 | | #include "string_.h" |
23 | | #include "pxoper.h" |
24 | | #include "pxpthr.h" |
25 | | #include "pxstate.h" |
26 | | #include "pxfont.h" |
27 | | #include "pjparse.h" |
28 | | #include "gschar.h" |
29 | | #include "gscoord.h" |
30 | | #include "gserrors.h" /* for gs_error_undefined */ |
31 | | #include "gspaint.h" |
32 | | #include "gsparam.h" |
33 | | #include "gsstate.h" |
34 | | #include "gxfixed.h" |
35 | | #include "gxpath.h" /* for gx_clip_to_rectangle */ |
36 | | #include "gxdcolor.h" |
37 | | #include "gxpcolor.h" |
38 | | #include "gxfcache.h" |
39 | | #include "gxdevice.h" |
40 | | #include "gxstate.h" |
41 | | #include "pjtop.h" |
42 | | #include "pllfont.h" |
43 | | #include "pxptable.h" |
44 | | #include "gzstate.h" |
45 | | |
46 | | /* Imported operators */ |
47 | | px_operator_proc(pxCloseDataSource); |
48 | | px_operator_proc(pxNewPath); |
49 | | px_operator_proc(pxPopGS); |
50 | | px_operator_proc(pxPushGS); |
51 | | px_operator_proc(pxSetHalftoneMethod); |
52 | | px_operator_proc(pxSetPageDefaultCTM); |
53 | | |
54 | | /* |
55 | | * Define the known paper sizes and unprintable margins. For convenience, |
56 | | * we define this in terms of 300 dpi pixels, in portrait orientation. This |
57 | | * table should obviously be device-dependent. |
58 | | */ |
59 | 8.31k | #define media_size_scale (72.0 / 300.0) |
60 | | #define m_default 50, 50, 50, 50 |
61 | | #define m_data(ms_enum, mstr, res, width, height) \ |
62 | | {ms_enum, mstr, width * 300 / (res), height * 300 / (res), m_default}, |
63 | | static px_media_t known_media[] = { |
64 | | px_enumerate_media(m_data) |
65 | | }; |
66 | | #undef m_data |
67 | | #undef m_default |
68 | | |
69 | | /* Define the mapping from the Measure enumeration to points. */ |
70 | | static const double measure_to_points[] = pxeMeasure_to_points; |
71 | | |
72 | | /* ---------------- Internal procedures ---------------- */ |
73 | | |
74 | | /* system paper size string (same as pjl paper size) to pxl enumeration type */ |
75 | | static pxeMediaSize_t |
76 | | px_paper_string_to_media(pjl_envvar_t * paper_str) |
77 | 6.63k | { |
78 | | /* table to map pjl paper type strings to pxl enums */ |
79 | 6.63k | int i; |
80 | | |
81 | 13.6k | for (i = 0; i < countof(known_media); i++) { |
82 | 13.6k | if (!pjl_compare(paper_str, known_media[i].mname)) |
83 | 6.62k | return known_media[i].ms_enum; |
84 | 13.6k | } |
85 | | /* not found return letter */ |
86 | 10 | return eLetterPaper; |
87 | 6.63k | } |
88 | | |
89 | | /* return the default media set up in the XL state */ |
90 | | static px_media_t * |
91 | | px_get_default_media(px_state_t * pxs) |
92 | 2.40k | { |
93 | 2.40k | int i; |
94 | | |
95 | 4.81k | for (i = 0; i < countof(known_media); i++) |
96 | 4.81k | if (known_media[i].ms_enum == pxs->media_size) |
97 | 2.40k | return &known_media[i]; |
98 | | /* shouldn't get here but just in case we return letter. */ |
99 | 0 | return &known_media[1]; |
100 | 2.40k | } |
101 | | |
102 | | void |
103 | | px_get_default_media_size(px_state_t * pxs, gs_point * pt) |
104 | 2.40k | { |
105 | 2.40k | px_media_t *media = px_get_default_media(pxs); |
106 | | |
107 | 2.40k | pt->x = media->width * media_size_scale; |
108 | 2.40k | pt->y = media->height * media_size_scale; |
109 | 2.40k | } |
110 | | |
111 | | /* Finish putting one device parameter. */ |
112 | | static int |
113 | | px_put1(gx_device * dev, gs_c_param_list * plist, int ecode) |
114 | 15.8k | { |
115 | 15.8k | int code = ecode; |
116 | | |
117 | 15.8k | if (code >= 0) { |
118 | 15.8k | gs_c_param_list_read(plist); |
119 | 15.8k | code = gs_putdeviceparams(dev, (gs_param_list *) plist); |
120 | 15.8k | } |
121 | 15.8k | gs_c_param_list_release(plist); |
122 | 15.8k | return (code == 0 || code == gs_error_undefined ? ecode : code); |
123 | 15.8k | } |
124 | | |
125 | | /* Adjust one scale factor to an integral value if we can. */ |
126 | | static double |
127 | | px_adjust_scale(double value, double extent) |
128 | 7.03k | { |
129 | | /* If we can make the value an integer with a total error */ |
130 | | /* of less than 1/2 pixel over the entire page, we do it. */ |
131 | 7.03k | double int_value = floor(value + 0.5); |
132 | | |
133 | 7.03k | return (fabs((int_value - value) * extent) < 0.5 ? int_value : value); |
134 | 7.03k | } |
135 | | |
136 | | /* Clean up at the end of a page, but before rendering. */ |
137 | | static void |
138 | | px_end_page_cleanup(px_state_t * pxs) |
139 | 7.24k | { |
140 | 7.24k | px_dict_release(&pxs->page_pattern_dict); |
141 | | /* Clean up stray gstate information. */ |
142 | 7.34k | while (pxs->pxgs->stack_depth > 0) |
143 | 101 | pxPopGS(NULL, pxs); |
144 | | /* Pop an extra time to mirror the push in BeginPage. */ |
145 | 7.24k | pxs->pxgs->stack_depth++; |
146 | 7.24k | pxPopGS(NULL, pxs); |
147 | 7.24k | pxNewPath(NULL, pxs); |
148 | 7.24k | px_purge_pattern_cache(pxs, ePagePattern); |
149 | 7.24k | pxpcl_pagestatereset(pxs); |
150 | 7.24k | } |
151 | | |
152 | | /* Purge all */ |
153 | | static bool |
154 | | purge_all(const gs_memory_t * mem, cached_char * cc, void *dummy) |
155 | 15.5k | { |
156 | 15.5k | return true; |
157 | 15.5k | } |
158 | | |
159 | | /* clears the entire cache */ |
160 | | /* Clean up at the end of a session. */ |
161 | | static void |
162 | | px_end_session_cleanup(px_state_t * pxs) |
163 | 4.82k | { |
164 | 4.82k | if (pxs->data_source_open) |
165 | 1.78k | pxCloseDataSource(NULL, pxs); |
166 | 4.82k | px_purge_character_cache(pxs); |
167 | 4.82k | px_dict_release(&pxs->session_pattern_dict); |
168 | 4.82k | if (gstate_pattern_cache(pxs->pgs)) { |
169 | 0 | (gstate_pattern_cache(pxs->pgs)->free_all) |
170 | 0 | (gstate_pattern_cache(pxs->pgs)); |
171 | 0 | gs_free_object(pxs->memory, |
172 | 0 | gstate_pattern_cache(pxs->pgs)->tiles, |
173 | 0 | "px_end_session_cleanup(tiles)"); |
174 | 0 | gs_free_object(pxs->memory, |
175 | 0 | gstate_pattern_cache(pxs->pgs), |
176 | 0 | "px_end_session_cleanup(struct)"); |
177 | 0 | { |
178 | 0 | gs_gstate *pgs = pxs->pgs; |
179 | |
|
180 | 0 | while (pgs) { |
181 | 0 | gstate_set_pattern_cache(pgs, 0); |
182 | 0 | pgs = gs_gstate_saved(pgs); |
183 | 0 | } |
184 | 0 | } |
185 | 0 | } |
186 | | /* We believe that streams do *not* persist across sessions.... */ |
187 | 4.82k | px_dict_release(&pxs->stream_dict); |
188 | | /* delete downloaded fonts on end of session */ |
189 | 4.82k | px_dict_release(&pxs->font_dict); |
190 | 4.82k | pxpcl_release(pxs); |
191 | 4.82k | } |
192 | | |
193 | | /* ---------------- Non-operator procedures ---------------- */ |
194 | | |
195 | | /* Clean up after an error or UEL. */ |
196 | | void |
197 | | px_state_cleanup(px_state_t * pxs) |
198 | 4.81k | { |
199 | 4.81k | px_end_page_cleanup(pxs); |
200 | 4.81k | px_end_session_cleanup(pxs); |
201 | 4.81k | pxs->have_page = false; |
202 | 4.81k | } |
203 | | |
204 | | void |
205 | | px_purge_character_cache(px_state_t * pxs) |
206 | 4.82k | { |
207 | 4.82k | gx_purge_selected_cached_chars(pxs->font_dir, purge_all, pxs); |
208 | 4.82k | } |
209 | | |
210 | | /* ---------------- Operators ---------------- */ |
211 | | |
212 | | const byte apxBeginSession[] = { |
213 | | pxaMeasure, pxaUnitsPerMeasure, 0, |
214 | | pxaErrorReport, 0 |
215 | | }; |
216 | | int |
217 | | pxBeginSession(px_args_t * par, px_state_t * pxs) |
218 | 6.40k | { |
219 | 6.40k | pxs->measure = par->pv[0]->value.i; |
220 | 6.40k | pxs->units_per_measure.x = real_value(par->pv[1], 0); |
221 | 6.40k | pxs->units_per_measure.y = real_value(par->pv[1], 1); |
222 | | |
223 | 6.40k | pxs->stream_level = 0; |
224 | | |
225 | 6.40k | if (par->pv[2]) |
226 | 6.40k | pxs->error_report = par->pv[2]->value.i; |
227 | 0 | else |
228 | 0 | pxs->error_report = eNoReporting; |
229 | 6.40k | px_dict_init(&pxs->session_pattern_dict, pxs->memory, px_free_pattern); |
230 | | /* Set media parameters to device defaults, in case BeginPage */ |
231 | | /* doesn't specify valid ones. */ |
232 | | /* This is obviously device-dependent. */ |
233 | | /* get the pjl state */ |
234 | 6.40k | { |
235 | 6.40k | pjl_envvar_t *pjl_psize = pjl_proc_get_envvar(pxs->pjls, "paper"); |
236 | | |
237 | | /* NB. We are not sure about the interaction of pjl's |
238 | | wide a4 commands so we don't attempt to implement |
239 | | it. */ |
240 | | /* bool pjl_widea4 |
241 | | = pjl_proc_compare(pxs->pjls, pjl_proc_get_envvar(pxs->pjls, "widea4"), "no"); */ |
242 | 6.40k | int pjl_copies |
243 | 6.40k | = |
244 | 6.40k | pjl_proc_vartoi(pxs->pjls, |
245 | 6.40k | pjl_proc_get_envvar(pxs->pjls, "copies")); |
246 | 6.40k | bool pjl_duplex = |
247 | 6.40k | pjl_proc_compare(pxs->pjls, |
248 | 6.40k | pjl_proc_get_envvar(pxs->pjls, "duplex"), "off"); |
249 | 6.40k | bool pjl_bindshort = |
250 | 6.40k | pjl_proc_compare(pxs->pjls, |
251 | 6.40k | pjl_proc_get_envvar(pxs->pjls, "binding"), |
252 | 6.40k | "longedge"); |
253 | 6.40k | bool pjl_manualfeed = |
254 | 6.40k | pjl_proc_compare(pxs->pjls, |
255 | 6.40k | pjl_proc_get_envvar(pxs->pjls, "manualfeed"), |
256 | 6.40k | "off"); |
257 | 6.40k | pxs->media_size = px_paper_string_to_media(pjl_psize); |
258 | 6.40k | pxs->media_source = (pjl_manualfeed ? eManualFeed : eDefaultSource); |
259 | 6.40k | pxs->duplex = pjl_duplex; |
260 | 6.40k | pxs->duplex_page_mode = (pjl_bindshort ? eDuplexHorizontalBinding : |
261 | 6.40k | eDuplexVerticalBinding); |
262 | 6.40k | pxs->duplex_back_side = eFrontMediaSide; |
263 | 6.40k | pxs->copies = pjl_copies; |
264 | 6.40k | pxs->media_destination = eDefaultDestination; |
265 | 6.40k | pxs->media_type = eDefaultType; |
266 | | |
267 | 6.40k | if (!pjl_proc_compare |
268 | 6.40k | (pxs->pjls, pjl_proc_get_envvar(pxs->pjls, "orientation"), |
269 | 6.40k | "LANDSCAPE")) |
270 | 0 | pxs->orientation = eLandscapeOrientation; |
271 | 6.40k | if (!pjl_proc_compare |
272 | 6.40k | (pxs->pjls, pjl_proc_get_envvar(pxs->pjls, "orientation"), |
273 | 6.40k | "PORTRAIT")) |
274 | 6.40k | pxs->orientation = ePortraitOrientation; |
275 | | /* NB reverse orientations missing */ |
276 | | |
277 | | /* install the built in fonts */ |
278 | 6.40k | if (!pl_load_built_in_fonts |
279 | 6.40k | (pjl_proc_fontsource_to_path(pxs->pjls, "I"), pxs->memory, |
280 | 6.40k | &pxs->builtin_font_dict, pxs->font_dir, (int)pxfsInternal, |
281 | 6.40k | true /* use unicode key names */ )) { |
282 | 0 | errprintf(pxs->memory, "Fonts not found\n"); |
283 | 0 | return gs_error_Fatal; |
284 | |
|
285 | 0 | } |
286 | 6.40k | } |
287 | 6.40k | return 0; |
288 | 6.40k | } |
289 | | |
290 | | const byte apxEndSession[] = { 0, 0 }; |
291 | | int |
292 | | pxEndSession(px_args_t * par, px_state_t * pxs) |
293 | 3 | { |
294 | 3 | px_end_session_cleanup(pxs); |
295 | 3 | if (pxs->warning_length) |
296 | 0 | return_error(errorWarningsReported); |
297 | 3 | return 0; |
298 | 3 | } |
299 | | |
300 | | const byte apxBeginPage[] = { |
301 | | 0, pxaOrientation, |
302 | | pxaMediaSource, pxaMediaSize, pxaCustomMediaSize, pxaCustomMediaSizeUnits, |
303 | | pxaSimplexPageMode, pxaDuplexPageMode, pxaDuplexPageSide, |
304 | | pxaMediaDestination, pxaMediaType, 0 |
305 | | }; |
306 | | int |
307 | | pxBeginPage(px_args_t * par, px_state_t * pxs) |
308 | 1.75k | { |
309 | 1.75k | gs_gstate *pgs = pxs->pgs; |
310 | 1.75k | gx_device *dev = gs_currentdevice(pgs); |
311 | 1.75k | gs_point page_size_pixels; |
312 | 1.75k | gs_matrix points2device; |
313 | 1.75k | bool no_pv_2 = false; |
314 | 1.75k | int code; |
315 | | |
316 | | /* check for 2.1 no parameter special cases */ |
317 | 1.75k | { |
318 | 1.75k | int i; |
319 | 1.75k | bool have_params = false; |
320 | | |
321 | 1.75k | for (i = (par->pv[0] == 0 ? 0 : 1); |
322 | 1.77k | i < sizeof(par->pv) / sizeof(par->pv[0]); i++) { |
323 | 1.77k | if (par->pv[i]) { |
324 | 1.75k | have_params = true; |
325 | 1.75k | break; |
326 | 1.75k | } |
327 | 1.77k | } |
328 | 1.75k | if (have_params == false) { |
329 | 0 | if (par->pv[0]) { |
330 | 0 | int32_t orientation = par->pv[0]->value.i; |
331 | |
|
332 | 0 | if (orientation < 0 || orientation >= pxeOrientation_next) { |
333 | 0 | px_record_warning("IllegalOrientation", true, pxs); |
334 | 0 | orientation = ePortraitOrientation; |
335 | 0 | } |
336 | 0 | pxs->orientation = (pxeOrientation_t) orientation; |
337 | 0 | } |
338 | 0 | goto setd; |
339 | 0 | } |
340 | 1.75k | } |
341 | | /* Check parameter presence for legal combinations. */ |
342 | 1.75k | if (par->pv[2]) { |
343 | 1.75k | if (par->pv[3] || par->pv[4]) |
344 | 0 | return_error(errorIllegalAttributeCombination); |
345 | 1.75k | } else if (par->pv[3] && par->pv[4]) { |
346 | 0 | if (par->pv[2]) |
347 | 0 | return_error(errorIllegalAttributeCombination); |
348 | 4 | } else { |
349 | 4 | pxs->pm = px_get_default_media(pxs); |
350 | 4 | no_pv_2 = true; |
351 | 4 | } |
352 | 1.75k | if (par->pv[5]) { |
353 | 0 | if (par->pv[6] || par->pv[7]) |
354 | 0 | return_error(errorIllegalAttributeCombination); |
355 | 1.75k | } else if (par->pv[6]) { |
356 | 1 | if (par->pv[5]) |
357 | 0 | return_error(errorIllegalAttributeCombination); |
358 | 1 | } |
359 | | |
360 | | /* Copy parameters to the PCL XL state. */ |
361 | | /* For some reason, invalid Orientations only produces a warning. */ |
362 | 1.75k | if (par->pv[0]) { |
363 | 1.75k | int32_t orientation = par->pv[0]->value.i; |
364 | | |
365 | 1.75k | if (orientation < 0 || orientation >= pxeOrientation_next) { |
366 | 0 | px_record_warning("IllegalOrientation", true, pxs); |
367 | 0 | orientation = ePortraitOrientation; |
368 | 0 | } |
369 | 1.75k | pxs->orientation = (pxeOrientation_t) orientation; |
370 | 1.75k | } |
371 | | |
372 | 1.75k | if (par->pv[1]) |
373 | 1.74k | pxs->media_source = par->pv[1]->value.i; |
374 | 1.75k | if (par->pv[2]) { |
375 | | /* default to letter */ |
376 | 1.75k | pxeMediaSize_t ms_enum = eLetterPaper; |
377 | 1.75k | int i; |
378 | | |
379 | | /* could be an array or enumeration */ |
380 | 1.75k | if (par->pv[2]->type & pxd_array) { |
381 | | /* it's an array, so convert it to the associated |
382 | | enumeration */ |
383 | 226 | byte *str = gs_alloc_string(pxs->memory, |
384 | 226 | array_value_size(par->pv[2]) + 1, |
385 | 226 | "pxBeginPage"); |
386 | | |
387 | 226 | if (str == 0) |
388 | 0 | return_error(errorInsufficientMemory); |
389 | | /* null terminate */ |
390 | 226 | memcpy(str, par->pv[2]->value.array.data, |
391 | 226 | array_value_size(par->pv[2])); |
392 | 226 | str[array_value_size(par->pv[2])] = '\0'; |
393 | 226 | ms_enum = |
394 | 226 | px_paper_string_to_media( /* NB */ (pjl_envvar_t *) str); |
395 | 226 | gs_free_string(pxs->memory, str, array_value_size(par->pv[2]) + 1, |
396 | 226 | "pxBeginPage"); |
397 | | |
398 | 1.52k | } else if (par->pv[2]->value.i) { /* it's an enumeration */ |
399 | 6 | ms_enum = par->pv[2]->value.i; |
400 | 6 | } |
401 | 1.75k | if (ms_enum == eDefaultPaperSize) { |
402 | 0 | pxs->pm = px_get_default_media(pxs); |
403 | 1.75k | } else { |
404 | 1.75k | bool found_media = false; |
405 | | |
406 | 3.51k | for (pxs->pm = known_media, i = 0; i < countof(known_media); |
407 | 1.76k | ++pxs->pm, ++i) |
408 | 3.51k | if (pxs->pm->ms_enum == ms_enum) { |
409 | 1.75k | found_media = true; |
410 | 1.75k | break; |
411 | 1.75k | } |
412 | 1.75k | if (!found_media) { /* No match, select default media. */ |
413 | 0 | pxs->pm = px_get_default_media(pxs); |
414 | 0 | px_record_warning("IllegalMediaSize", false, pxs); |
415 | 0 | } |
416 | 1.75k | } |
417 | 1.75k | media:pxs->media_size = pxs->pm->ms_enum; |
418 | 1.75k | pxs->media_dims.x = pxs->pm->width * media_size_scale; |
419 | 1.75k | pxs->media_dims.y = pxs->pm->height * media_size_scale; |
420 | 1.75k | pxs->media_height = pxs->pm->height; |
421 | 1.75k | pxs->media_width = pxs->pm->width; |
422 | 1.75k | } else if (no_pv_2) { |
423 | 4 | goto media; |
424 | 4 | } else { /* custom (!par->pv[2]) */ |
425 | 0 | double scale = measure_to_points[par->pv[4]->value.i]; |
426 | |
|
427 | 0 | pxs->media_dims.x = real_value(par->pv[3], 0) * scale; |
428 | 0 | pxs->media_dims.y = real_value(par->pv[3], 1) * scale; |
429 | | /* |
430 | | * Assume the unprintable margins for custom media are the same |
431 | | * as for the default media. This may not be right. |
432 | | */ |
433 | 0 | pxs->pm = px_get_default_media(pxs); |
434 | 0 | pxs->media_height = (short)(pxs->media_dims.y / media_size_scale); |
435 | 0 | pxs->media_width = (short)(pxs->media_dims.x / media_size_scale); |
436 | 0 | } |
437 | 1.75k | if (par->pv[5]) { |
438 | 0 | pxs->duplex = false; |
439 | 1.75k | } else if (par->pv[6]) { |
440 | 1 | pxs->duplex = true; |
441 | 1 | pxs->duplex_page_mode = par->pv[6]->value.i; |
442 | 1 | if (par->pv[7]) |
443 | 0 | pxs->duplex_back_side = (par->pv[7]->value.i == eBackMediaSide); |
444 | 1 | } |
445 | 1.75k | if (par->pv[8]) |
446 | 3 | pxs->media_destination = par->pv[8]->value.i; |
447 | 1.75k | if (par->pv[9]) |
448 | 0 | pxs->media_type = par->pv[9]->value.i; |
449 | | |
450 | | /* Pass the media parameters to the device. */ |
451 | 1.75k | setd:{ |
452 | 1.75k | gs_memory_t *mem = pxs->memory; |
453 | 1.75k | gs_c_param_list list; |
454 | 15.8k | #define plist ((gs_param_list *)&list) |
455 | 1.75k | gs_param_float_array fa; |
456 | 1.75k | float fv[4]; |
457 | 1.75k | int iv; |
458 | 1.75k | bool bv; |
459 | 1.75k | int ecode = 0; |
460 | 1.75k | int page_spot_colors = 0; |
461 | | |
462 | 1.75k | fa.data = fv; |
463 | 1.75k | fa.persistent = false; |
464 | | |
465 | 1.75k | gs_c_param_list_write(&list, mem); |
466 | 1.75k | iv = pxs->orientation; /* might not be an int */ |
467 | 1.75k | ecode = param_write_int(plist, "Orientation", &iv); |
468 | 1.75k | ecode = px_put1(dev, &list, ecode); |
469 | 1.75k | if (ecode < 0) |
470 | 0 | return ecode; |
471 | | |
472 | | /* PXL never has spot colors on the page */ |
473 | 1.75k | gs_c_param_list_write(&list, mem); |
474 | 1.75k | ecode = param_write_int(plist, "PageSpotColors", &(page_spot_colors)); |
475 | 1.75k | ecode = px_put1(dev, &list, ecode); |
476 | 1.75k | if (ecode < 0) |
477 | 0 | return ecode; |
478 | | |
479 | 1.75k | gs_c_param_list_write(&list, mem); |
480 | 1.75k | fv[0] = pxs->media_dims.x; |
481 | 1.75k | fv[1] = pxs->media_dims.y; |
482 | 1.75k | fa.size = 2; |
483 | 1.75k | ecode = param_write_float_array(plist, ".MediaSize", &fa); |
484 | 1.75k | ecode = px_put1(dev, &list, ecode); |
485 | 1.75k | if (ecode < 0) |
486 | 0 | return ecode; |
487 | | |
488 | 1.75k | iv = pxs->media_source; /* might not be an int */ |
489 | 1.75k | if (iv < 0 || iv >= pxeMediaSource_next) |
490 | 3 | px_record_warning("IllegalMediaSource", false, pxs); |
491 | 1.75k | else { |
492 | 1.75k | gs_c_param_list_write(&list, mem); |
493 | 1.75k | ecode = param_write_int(plist, ".MediaSource", &iv); |
494 | 1.75k | ecode = px_put1(dev, &list, ecode); |
495 | 1.75k | if (ecode < 0) |
496 | 0 | return ecode; |
497 | 1.75k | } |
498 | | |
499 | 1.75k | gs_c_param_list_write(&list, mem); |
500 | 1.75k | ecode = param_write_bool(plist, "Duplex", &pxs->duplex); |
501 | 1.75k | ecode = px_put1(dev, &list, ecode); |
502 | 1.75k | if (ecode < 0) |
503 | 0 | return ecode; |
504 | | |
505 | 1.75k | gs_c_param_list_write(&list, mem); |
506 | 1.75k | bv = pxs->duplex_page_mode == eDuplexHorizontalBinding; |
507 | 1.75k | ecode = param_write_bool(plist, "Tumble", &bv); |
508 | 1.75k | ecode = px_put1(dev, &list, ecode); |
509 | 1.75k | if (ecode < 0) |
510 | 0 | return ecode; |
511 | | |
512 | 1.75k | gs_c_param_list_write(&list, mem); |
513 | 1.75k | bv = !pxs->duplex_back_side; |
514 | 1.75k | ecode = param_write_bool(plist, "FirstSide", &bv); |
515 | 1.75k | ecode = px_put1(dev, &list, ecode); |
516 | 1.75k | if (ecode < 0) |
517 | 0 | return ecode; |
518 | | |
519 | 1.75k | gs_c_param_list_write(&list, mem); |
520 | 1.75k | iv = pxs->media_destination; /* might not be an int */ |
521 | 1.75k | ecode = param_write_int(plist, ".MediaDestination", &iv); |
522 | 1.75k | ecode = px_put1(dev, &list, ecode); |
523 | 1.75k | if (ecode < 0) |
524 | 0 | return ecode; |
525 | | |
526 | 1.75k | gs_c_param_list_write(&list, mem); |
527 | 1.75k | iv = pxs->media_type; /* might not be an int */ |
528 | 1.75k | ecode = param_write_int(plist, ".MediaType", &iv); |
529 | 1.75k | ecode = px_put1(dev, &list, ecode); |
530 | 1.75k | if (ecode < 0) |
531 | 0 | return ecode; |
532 | | |
533 | | /* |
534 | | * We aren't sure what to do if the device rejects the parameter |
535 | | * value.... |
536 | | */ |
537 | 1.75k | switch (ecode) { |
538 | 0 | case 1: |
539 | 0 | code = gs_setdevice(pgs, dev); |
540 | 0 | if (code < 0) |
541 | 0 | return code; |
542 | 1.75k | case 0: |
543 | 1.75k | break; |
544 | 0 | default: |
545 | 0 | return_error(errorIllegalAttributeValue); |
546 | 1.75k | } |
547 | 1.75k | #undef plist |
548 | 1.75k | } |
549 | 1.75k | if (!dev->is_open) { |
550 | 7 | code = gs_opendevice(dev); |
551 | 7 | if (code < 0) |
552 | 0 | return code; |
553 | 7 | } |
554 | 1.75k | { |
555 | 1.75k | code = px_initgraphics(pxs); |
556 | 1.75k | if (code < 0) return code; |
557 | 1.75k | gs_currentmatrix(pgs, &points2device); |
558 | 1.75k | gs_dtransform(pgs, pxs->media_dims.x, pxs->media_dims.y, |
559 | 1.75k | &page_size_pixels); |
560 | 1.75k | { /* |
561 | | * Put the origin at the upper left corner of the page; |
562 | | * also account for the orientation. |
563 | | */ |
564 | 1.75k | gs_matrix orient; |
565 | | |
566 | 1.75k | orient.xx = orient.xy = orient.yx = orient.yy = |
567 | 1.75k | orient.tx = orient.ty = 0; |
568 | 1.75k | switch (pxs->orientation) { |
569 | 0 | case eDefaultOrientation: |
570 | 1.75k | case ePortraitOrientation: |
571 | 1.75k | code = gs_translate(pgs, 0.0, pxs->media_dims.y); |
572 | 1.75k | orient.xx = 1, orient.yy = -1; |
573 | 1.75k | break; |
574 | 0 | case eLandscapeOrientation: |
575 | 0 | code = 0; |
576 | 0 | orient.xy = 1, orient.yx = 1; |
577 | 0 | break; |
578 | 0 | case eReversePortrait: |
579 | 0 | code = gs_translate(pgs, pxs->media_dims.x, 0); |
580 | 0 | orient.xx = -1, orient.yy = 1; |
581 | 0 | break; |
582 | 0 | case eReverseLandscape: |
583 | 0 | code = |
584 | 0 | gs_translate(pgs, pxs->media_dims.x, |
585 | 0 | pxs->media_dims.y); |
586 | 0 | orient.xy = -1, orient.yx = -1; |
587 | 0 | break; |
588 | 0 | default: /* can't happen */ |
589 | 0 | return_error(errorIllegalAttributeValue); |
590 | 1.75k | } |
591 | 1.75k | if (code < 0 || (code = gs_concat(pgs, &orient)) < 0) |
592 | 0 | return code; |
593 | 1.75k | } |
594 | 1.75k | { /* Scale according to session parameters. */ |
595 | | /* If we can make the scale integral safely, we do. */ |
596 | 1.75k | double scale = measure_to_points[pxs->measure]; |
597 | 1.75k | gs_matrix mat; |
598 | | |
599 | 1.75k | if ((code = gs_scale(pgs, scale / pxs->units_per_measure.x, |
600 | 1.75k | scale / pxs->units_per_measure.y)) < 0) |
601 | 0 | return code; |
602 | 1.75k | gs_currentmatrix(pgs, &mat); |
603 | 1.75k | mat.xx = px_adjust_scale(mat.xx, page_size_pixels.x); |
604 | 1.75k | mat.xy = px_adjust_scale(mat.xy, page_size_pixels.y); |
605 | 1.75k | mat.yx = px_adjust_scale(mat.yx, page_size_pixels.x); |
606 | 1.75k | mat.yy = px_adjust_scale(mat.yy, page_size_pixels.y); |
607 | 1.75k | gs_setmatrix(pgs, &mat); |
608 | 1.75k | pxs->initial_matrix = mat; |
609 | 1.75k | } |
610 | 1.75k | } |
611 | 0 | { /* |
612 | | * Set the default halftone method. We have to do this here, |
613 | | * rather than earlier, so that the origin is set correctly. |
614 | | */ |
615 | 1.75k | px_args_t args = { 0 }; |
616 | 1.75k | px_value_t device_matrix; |
617 | | |
618 | 1.75k | args.pv[1] = &device_matrix; /* DeviceMatrix */ |
619 | 1.75k | device_matrix.type = pxd_scalar | pxd_ubyte; |
620 | 1.75k | device_matrix.value.i = eDeviceBest; |
621 | 1.75k | code = pxSetHalftoneMethod(&args, pxs); |
622 | 1.75k | if (code < 0) return code; |
623 | 1.75k | } |
624 | | /* Initialize other parts of the PCL XL state. */ |
625 | 1.75k | px_dict_init(&pxs->page_pattern_dict, pxs->memory, px_free_pattern); |
626 | 1.75k | code = gs_erasepage(pgs); |
627 | 1.75k | if (code < 0) return code; |
628 | 1.75k | pxs->have_page = false; |
629 | | /* Make sure there is a legitimate halftone installed. */ |
630 | 1.75k | { |
631 | 1.75k | code = px_set_halftone(pxs); |
632 | | |
633 | 1.75k | if (code < 0) |
634 | 0 | return code; |
635 | 1.75k | } |
636 | | /* |
637 | | * Do a gsave so we can be sure to get rid of all page-related |
638 | | * state at the end of the page, but make sure PopGS doesn't pop |
639 | | * this state from the stack. |
640 | | */ |
641 | 1.75k | { |
642 | 1.75k | code = pxPushGS(NULL, pxs); |
643 | | |
644 | 1.75k | if (code < 0) |
645 | 0 | return code; |
646 | 1.75k | pxs->pxgs->stack_depth--; |
647 | 1.75k | return code; |
648 | 1.75k | } |
649 | 1.75k | } |
650 | | |
651 | | int |
652 | | pxBeginPageFromPassthrough(px_state_t * pxs) |
653 | 0 | { |
654 | 0 | int code; |
655 | 0 | gs_gstate *pgs = pxs->pgs; |
656 | 0 | gs_point page_size_pixels; |
657 | 0 | gs_matrix points2device; |
658 | |
|
659 | 0 | code = px_initgraphics(pxs); |
660 | 0 | if (code < 0) return code; |
661 | 0 | gs_currentmatrix(pgs, &points2device); |
662 | 0 | gs_dtransform(pgs, pxs->media_dims.x, pxs->media_dims.y, |
663 | 0 | &page_size_pixels); |
664 | 0 | { |
665 | | /* |
666 | | * Put the origin at the upper left corner of the page; |
667 | | * also account for the orientation. |
668 | | */ |
669 | 0 | gs_matrix orient; |
670 | |
|
671 | 0 | orient.xx = orient.xy = orient.yx = orient.yy = |
672 | 0 | orient.tx = orient.ty = 0; |
673 | 0 | switch (pxs->orientation) { |
674 | 0 | case eDefaultOrientation: |
675 | 0 | case ePortraitOrientation: |
676 | 0 | code = gs_translate(pgs, 0.0, pxs->media_dims.y); |
677 | 0 | orient.xx = 1, orient.yy = -1; |
678 | 0 | break; |
679 | 0 | case eLandscapeOrientation: |
680 | 0 | code = 0; |
681 | 0 | orient.xy = 1, orient.yx = 1; |
682 | 0 | break; |
683 | 0 | case eReversePortrait: |
684 | 0 | code = gs_translate(pgs, pxs->media_dims.x, 0); |
685 | 0 | orient.xx = -1, orient.yy = 1; |
686 | 0 | break; |
687 | 0 | case eReverseLandscape: |
688 | 0 | code = |
689 | 0 | gs_translate(pgs, pxs->media_dims.x, pxs->media_dims.y); |
690 | 0 | orient.xy = -1, orient.yx = -1; |
691 | 0 | break; |
692 | 0 | default: /* can't happen */ |
693 | 0 | return_error(errorIllegalAttributeValue); |
694 | 0 | } |
695 | 0 | if (code < 0 || (code = gs_concat(pgs, &orient)) < 0) |
696 | 0 | return code; |
697 | 0 | } |
698 | 0 | { /* Scale according to session parameters. */ |
699 | | /* If we can make the scale integral safely, we do. */ |
700 | 0 | double scale = measure_to_points[pxs->measure]; |
701 | 0 | gs_matrix mat; |
702 | |
|
703 | 0 | if ((code = gs_scale(pgs, scale / pxs->units_per_measure.x, |
704 | 0 | scale / pxs->units_per_measure.y)) < 0) |
705 | 0 | return code; |
706 | 0 | gs_currentmatrix(pgs, &mat); |
707 | 0 | mat.xx = px_adjust_scale(mat.xx, page_size_pixels.x); |
708 | 0 | mat.xy = px_adjust_scale(mat.xy, page_size_pixels.y); |
709 | 0 | mat.yx = px_adjust_scale(mat.yx, page_size_pixels.x); |
710 | 0 | mat.yy = px_adjust_scale(mat.yy, page_size_pixels.y); |
711 | 0 | gs_setmatrix(pgs, &mat); |
712 | 0 | pxs->initial_matrix = mat; |
713 | 0 | } |
714 | 0 | pxs->have_page = true; |
715 | 0 | return 0; |
716 | 0 | } |
717 | | |
718 | | const byte apxEndPage[] = { |
719 | | 0, |
720 | | pxaPageCopies, 0 |
721 | | }; |
722 | | int |
723 | | pxEndPage(px_args_t * par, px_state_t * pxs) |
724 | 2.42k | { |
725 | 2.42k | px_end_page_cleanup(pxs); |
726 | 2.42k | (*pxs->end_page) (pxs, (par->pv[0] ? par->pv[0]->value.i : pxs->copies), |
727 | 2.42k | 1); |
728 | 2.42k | pxs->have_page = false; |
729 | 2.42k | if (pxs->duplex) |
730 | 5 | pxs->duplex_back_side = !pxs->duplex_back_side; |
731 | 2.41k | else |
732 | 2.41k | pxs->duplex_back_side = false; |
733 | 2.42k | return 0; |
734 | 2.42k | } |
735 | | /* The default end-page procedure just calls the device procedure. */ |
736 | | int |
737 | | px_default_end_page(px_state_t * pxs, int num_copies, int flush) |
738 | 0 | { |
739 | 0 | return gs_output_page(pxs->pgs, num_copies, flush); |
740 | 0 | } |
741 | | |
742 | | const byte apxVendorUnique[] = { |
743 | | pxaVUExtension, 0, pxaVUDataLength, pxaVUAttr1, pxaVUAttr2, pxaVUAttr3, |
744 | | pxaVUAttr4, pxaVUAttr5, pxaVUAttr6, pxaSourceWidth, pxaSourceHeight, |
745 | | pxaStartLine, pxaBlockHeight, 0 |
746 | | }; |
747 | | |
748 | | /** we do NOTHING with the vendor unique command. |
749 | | * it is undocumented, but appears that it contains the sames color commands as the |
750 | | * XL 2.1 spec. This is based on only finding it in hpclj 4500 driver output. |
751 | | * of course HP denys that the 4500 supports XL. |
752 | | */ |
753 | | int |
754 | | pxVendorUnique(px_args_t * par, px_state_t * pxs) |
755 | 0 | { |
756 | 0 | int code = 0; |
757 | |
|
758 | 0 | if (par->pv[1]) { |
759 | 0 | ulong len = par->pv[1]->value.i; |
760 | 0 | ulong copy = min(len - par->source.position, |
761 | 0 | par->source.available); |
762 | 0 | par->source.data += copy; |
763 | 0 | par->source.available -= copy; |
764 | 0 | par->source.position += copy; |
765 | 0 | if (par->source.position == len) |
766 | 0 | code = 0; |
767 | 0 | else |
768 | 0 | code = pxNeedData; |
769 | 0 | } |
770 | 0 | return code; |
771 | 0 | } |
772 | | |
773 | | const byte apxComment[] = { |
774 | | 0, |
775 | | pxaCommentData, 0 |
776 | | }; |
777 | | int |
778 | | pxComment(px_args_t * par, px_state_t * pxs) |
779 | 74 | { |
780 | 74 | return 0; |
781 | 74 | } |
782 | | |
783 | | const byte apxOpenDataSource[] = { |
784 | | pxaSourceType, pxaDataOrg, 0, 0 |
785 | | }; |
786 | | int |
787 | | pxOpenDataSource(px_args_t * par, px_state_t * pxs) |
788 | 1.79k | { |
789 | 1.79k | if (pxs->data_source_open) |
790 | 0 | return_error(errorDataSourceNotClosed); |
791 | 1.79k | pxs->data_source_open = true; |
792 | 1.79k | pxs->data_source_big_endian = par->pv[1]->value.i == eBinaryHighByteFirst; |
793 | 1.79k | return 0; |
794 | 1.79k | } |
795 | | |
796 | | const byte apxCloseDataSource[] = { 0, 0 }; |
797 | | int |
798 | | pxCloseDataSource(px_args_t * par, px_state_t * pxs) |
799 | 1.81k | { |
800 | 1.81k | pxs->data_source_open = false; |
801 | 1.81k | return 0; |
802 | 1.81k | } |