/src/ghostpdl/pcl/pcl/pcpatrn.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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 | | /* pcpatrn.c - code for PCL and GL/2 patterns, including color */ |
18 | | |
19 | | #include "gx.h" |
20 | | #include "gsuid.h" |
21 | | #include "gsmatrix.h" |
22 | | #include "gspcolor.h" |
23 | | #include "gxdcolor.h" |
24 | | #include "gxpcolor.h" |
25 | | #include "gxstate.h" |
26 | | #include "pccid.h" |
27 | | #include "pcfont.h" |
28 | | #include "pcpalet.h" |
29 | | #include "pcfrgrnd.h" |
30 | | #include "pcht.h" |
31 | | #include "pcwhtidx.h" |
32 | | #include "pcpatrn.h" |
33 | | #include "pcbiptrn.h" |
34 | | #include "pcuptrn.h" |
35 | | #include "pcpatxfm.h" |
36 | | #include "gzstate.h" /* for gstate */ |
37 | | |
38 | | /* |
39 | | * The base color space for setting the color white. Unlike all other color |
40 | | * spaces in PCL, this uses the DeviceGray color space in the graphic library. |
41 | | * |
42 | | * A copy of the default halftone is also maintained for setting the color |
43 | | * "white". Since the halftone carries the device-specific color lookup tables, |
44 | | * a non-standard halftone might end up mapping white to black (definitely |
45 | | * undesirable). |
46 | | */ |
47 | | static const gs_paint_color white_paint = { {1.0, 0.0, 0.0, 0.0} }; |
48 | | |
49 | | /* RC routines */ |
50 | | gs_private_st_simple(st_ccolor_t, pcl_ccolor_t, "PCL client color"); |
51 | | |
52 | | /* |
53 | | * Convert a color value specified as a three-element byte array, or an index |
54 | | * to a palette, into a gs_paint_color structure. |
55 | | */ |
56 | | static void |
57 | | convert_color_to_paint(const byte * pcomp, gs_paint_color * ppaint) |
58 | 10.5M | { |
59 | 10.5M | ppaint->values[0] = (float)pcomp[0] / 255.0; |
60 | 10.5M | ppaint->values[1] = (float)pcomp[1] / 255.0; |
61 | 10.5M | ppaint->values[2] = (float)pcomp[2] / 255.0; |
62 | 10.5M | ppaint->values[3] = 0.0; |
63 | 10.5M | } |
64 | | |
65 | | static void |
66 | | convert_index_to_paint(int indx, gs_paint_color * ppaint) |
67 | 3.32M | { |
68 | 3.32M | ppaint->values[0] = (float)indx; |
69 | 3.32M | ppaint->values[1] = 0.0; |
70 | 3.32M | ppaint->values[2] = 0.0; |
71 | 3.32M | ppaint->values[3] = 0.0; |
72 | 3.32M | } |
73 | | |
74 | | /* |
75 | | * Free a PCL client color structure. |
76 | | */ |
77 | | static void |
78 | | free_ccolor(gs_memory_t * pmem, void *pvccolor, client_name_t cname) |
79 | 241k | { |
80 | 241k | pcl_ccolor_t *pccolor = (pcl_ccolor_t *) pvccolor; |
81 | | |
82 | 241k | pcl_pattern_data_release(pccolor->ppat_data); |
83 | 241k | pcl_cs_indexed_release(pccolor->pindexed); |
84 | 241k | pcl_cs_base_release(pccolor->pbase); |
85 | 241k | if (pccolor->prast != 0) |
86 | 0 | gs_free_object(pmem, (void *)pccolor->prast, cname); |
87 | 241k | gs_pattern_reference(&(pccolor->ccolor), -1); |
88 | 241k | gs_free_object(pmem, pvccolor, cname); |
89 | 241k | } |
90 | | |
91 | | /* |
92 | | * Make a unique copy of a PCL client color structure. This function also |
93 | | * serves as the allocator function. |
94 | | * |
95 | | * Because the byte array pointed to by the prast structure is not reference |
96 | | * counted, the "copy" of the client color created this procedure will always |
97 | | * have this pointer set to NULL. This is unfortunate and ugly, as it implies |
98 | | * the copy cannot be used immediately as a client color, but it causes no |
99 | | * trouble in the current context because: |
100 | | * |
101 | | * prast is non-null only for colored patterns |
102 | | * the client color for a colored pattern would only be unshared |
103 | | * if it was about to be rendered, in which case the prast |
104 | | * array would need to be recreated. |
105 | | * |
106 | | * Newly created colors are solid white. |
107 | | */ |
108 | | static int |
109 | | unshare_ccolor(pcl_state_t * pcs, |
110 | | pcl_ccolor_t ** ppccolor, gs_memory_t * pmem) |
111 | 283k | { |
112 | 283k | pcl_ccolor_t *pold = *ppccolor; |
113 | 283k | pcl_ccolor_t *pnew = 0; |
114 | | |
115 | 283k | if ((pold != NULL) && (pold->rc.ref_count == 1)) { |
116 | 41.8k | if (pold->prast != 0) |
117 | 0 | gs_free_object(pmem, |
118 | 41.8k | (void *)pold->prast, "unshared PCL client color"); |
119 | 41.8k | pold->prast = 0; |
120 | 41.8k | return 0; |
121 | 41.8k | } |
122 | 241k | rc_decrement(pold, "unshare PCL client color object"); |
123 | | |
124 | 241k | rc_alloc_struct_1(pnew, |
125 | 241k | pcl_ccolor_t, |
126 | 241k | &st_ccolor_t, |
127 | 241k | pmem, return e_Memory, "allocate PCL client color"); |
128 | 241k | pnew->rc.free = free_ccolor; |
129 | 241k | pnew->prast = 0; |
130 | | |
131 | 241k | if (pold != 0) { |
132 | 226k | pnew->type = pold->type; |
133 | 226k | pcl_pattern_data_init_from(pnew->ppat_data, pold->ppat_data); |
134 | 226k | pcl_cs_indexed_init_from(pnew->pindexed, pold->pindexed); |
135 | 226k | pcl_cs_base_init_from(pnew->pbase, pold->pbase); |
136 | 226k | pnew->ccolor = pold->ccolor; |
137 | 226k | gs_pattern_reference(&(pnew->ccolor), 1); |
138 | 226k | } else { |
139 | 14.8k | int code = 0; |
140 | | |
141 | 14.8k | pnew->type = pcl_ccolor_unpatterned; |
142 | 14.8k | pnew->ppat_data = 0; |
143 | 14.8k | pnew->pindexed = 0; |
144 | | |
145 | | /* set the color space to pure white */ |
146 | 14.8k | pnew->pbase = 0; |
147 | 14.8k | code = pcl_cs_base_build_white_cspace(pcs, &(pnew->pbase), pmem); |
148 | 14.8k | if (code < 0) { |
149 | 0 | gs_free_object(pmem, pnew, "allocate PCL client color"); |
150 | 0 | return code; |
151 | 0 | } |
152 | 14.8k | pnew->ccolor.paint = white_paint; |
153 | 14.8k | pnew->ccolor.pattern = 0; |
154 | 14.8k | } |
155 | | |
156 | 241k | *ppccolor = pnew; |
157 | 241k | return 0; |
158 | 241k | } |
159 | | |
160 | | /* |
161 | | * Set a solid color (unpattered) color. This is handled separately from |
162 | | * patterns as it will usually not be necessary to build a PCL client color |
163 | | * structure in this case. |
164 | | * |
165 | | * Exactly one of the pair of operands pbase and pindex shoud be non-null. |
166 | | */ |
167 | | static int |
168 | | set_unpatterned_color(pcl_state_t * pcs, |
169 | | pcl_cs_indexed_t * pindexed, |
170 | | pcl_cs_base_t * pbase, const gs_paint_color * ppaint) |
171 | 13.6M | { |
172 | 13.6M | pcl_ccolor_t *pcur = pcs->pids->pccolor; |
173 | 13.6M | int code = 0; |
174 | 13.6M | pcl_ccolor_type_t type; |
175 | | |
176 | 13.6M | if_debug3m('c', pcs->memory, "[c]set unpatterned color %f %f %f\n", |
177 | 13.6M | ppaint->values[0], ppaint->values[1], ppaint->values[2]); |
178 | | |
179 | 13.6M | if (pcur != 0) |
180 | 13.6M | type = pcur->type; |
181 | 10.1k | else |
182 | 10.1k | type = pcl_ccolor_unpatterned; |
183 | | |
184 | 13.6M | if ((pcur != 0) && |
185 | 13.6M | (type == pcl_ccolor_unpatterned) && |
186 | 13.4M | (pcur->pindexed == pindexed) && |
187 | 13.4M | (pcur->pbase == pbase) && |
188 | 13.3M | (pcur->ccolor.paint.values[0] == ppaint->values[0]) && |
189 | 13.3M | (pcur->ccolor.paint.values[1] == ppaint->values[1]) && |
190 | 13.3M | (pcur->ccolor.paint.values[2] == ppaint->values[2])) |
191 | 13.3M | return 0; |
192 | | |
193 | 277k | if ((code = unshare_ccolor(pcs, &(pcs->pids->pccolor), pcs->memory)) < 0) |
194 | 0 | return code; |
195 | 277k | pcur = pcs->pids->pccolor; |
196 | | |
197 | 277k | pcur->type = pcl_ccolor_unpatterned; |
198 | 277k | if (pcur->ppat_data != 0) { |
199 | 191k | pcl_pattern_data_release(pcur->ppat_data); |
200 | 191k | pcur->ppat_data = 0; |
201 | 191k | } |
202 | | |
203 | 277k | if (pindexed != 0) { |
204 | 226k | if ((type != pcl_ccolor_unpatterned) || (pcur->pindexed != pindexed)) |
205 | 196k | code = pcl_cs_indexed_install(&pindexed, pcs); |
206 | 226k | } else { /* pbase != 0 */ |
207 | 51.0k | if ((type != pcl_ccolor_unpatterned) || (pcur->pbase != pbase)) |
208 | 51.0k | code = pcl_cs_base_install(&pbase, pcs); |
209 | 51.0k | } |
210 | 277k | if (code < 0) |
211 | 0 | return code; |
212 | 277k | pcl_cs_indexed_copy_from(pcur->pindexed, pindexed); |
213 | 277k | pcl_cs_base_copy_from(pcur->pbase, pbase); |
214 | | |
215 | 277k | gs_pattern_reference(&(pcur->ccolor), -1); |
216 | 277k | pcur->ccolor.pattern = 0; |
217 | 277k | pcur->ccolor.paint = *ppaint; |
218 | 277k | return gs_setcolor(pcs->pgs, &(pcur->ccolor)); |
219 | 277k | } |
220 | | |
221 | | /* |
222 | | * Set a patterned color space. Note that this is a substantially different |
223 | | * operation from setting a solid (unpatterned) color. |
224 | | */ |
225 | | static int |
226 | | set_patterned_color(pcl_state_t * pcs, pcl_ccolor_t * pnew) |
227 | 235k | { |
228 | 235k | pcl_ccolor_t *pcur = pcs->pids->pccolor; |
229 | 235k | int code = 0; |
230 | | |
231 | | /* check if already set */ |
232 | 235k | if (pcur == pnew) |
233 | 38.8k | return 0; |
234 | | |
235 | | /* set a base color space for the pattern, if necessary */ |
236 | 196k | if (pnew->type == pcl_ccolor_mask_pattern) { |
237 | | |
238 | 5.07k | if ((pnew->pindexed != 0) && |
239 | 2.06k | ((pcur == 0) || (pcur->pindexed != pnew->pindexed))) |
240 | 364 | code = pcl_cs_indexed_install(&(pnew->pindexed), pcs); |
241 | | |
242 | 5.07k | if (code < 0) |
243 | 0 | return code; |
244 | | |
245 | 5.07k | if ((pnew->pbase != 0) && |
246 | 3.01k | ((pcur == 0) || (pcur->pbase != pnew->pbase))) |
247 | 1.78k | code = pcl_cs_base_install(&(pnew->pbase), pcs); |
248 | 5.07k | } |
249 | 196k | if (code < 0) |
250 | 0 | return code; |
251 | | |
252 | | /* set the pattern instance */ |
253 | 196k | if ((code = gs_setpattern(pcs->pgs, &(pnew->ccolor))) >= 0) |
254 | 196k | pcl_ccolor_copy_from(pcs->pids->pccolor, pnew); |
255 | 196k | return code; |
256 | 196k | } |
257 | | |
258 | | /* |
259 | | * Check if the pattern pointed to by pptrn has a rendering and, if so, whether |
260 | | * or not that rendering is appropriate for the curren environment. |
261 | | * |
262 | | * If the rendering is appropriate, install the conrresponding color; otherwise |
263 | | * return false. |
264 | | * |
265 | | * The case of GL uncolored patterns rendered with patterns opaque is unique. |
266 | | * In this case the pattern must be generated as a colored pattern (mask |
267 | | * patterns are always transparent), with a specially generated 2-entry |
268 | | * indexed color space. The cache_id field identifies the palette that gave |
269 | | * rise to this pattern, but not the entry from that palette that was used |
270 | | * as the foreground color. Hence, for this case alone there must be a match |
271 | | * on the pen number key. To avoid the need for a much qualified check in this |
272 | | * case, we use the convention that the pen number field is zero in all but |
273 | | * this case. |
274 | | * |
275 | | * Note that a difference in the paint color does not require re-rendering; |
276 | | * these fields are ignored for colored patterns, and for mask patterns changes |
277 | | * only require another call to gs_setpattern. |
278 | | */ |
279 | | static bool |
280 | | check_pattern_rendering(pcl_state_t * pcs, pcl_pattern_t * pptrn, bool use_frgrnd, /* else use palette */ |
281 | | uint pen_num, |
282 | | bool colored, const gs_paint_color * ppaint) |
283 | 235k | { |
284 | 235k | pcl_ccolor_t *pccolor = 0; |
285 | | |
286 | | /* check the common parameters first */ |
287 | 235k | if ((pptrn == NULL) || |
288 | 235k | (pptrn->orient != pcs->pat_orient) || |
289 | 232k | (pptrn->ref_pt.x != pcs->pat_ref_pt.x) || |
290 | 230k | (pptrn->ref_pt.y != pcs->pat_ref_pt.y)) |
291 | 5.03k | return false; |
292 | | |
293 | 230k | if (colored) { |
294 | 205k | pcl_gsid_t cache_id = (use_frgrnd ? pcs->pfrgrnd->id |
295 | 205k | : pcs->ppalet->id); |
296 | | |
297 | | /* check that there is a rendering in the appropriate environment */ |
298 | 205k | if (((pccolor = pptrn->pcol_ccolor) == 0) || |
299 | 205k | (pptrn->transp != pcs->pattern_transparent) || |
300 | 205k | (pptrn->cache_id != cache_id) || (pptrn->pen != pen_num)) |
301 | 26 | return false; |
302 | | |
303 | 205k | } else { /* mask pattern */ |
304 | 24.8k | pcl_cs_indexed_t *pindexed = (use_frgrnd ? 0 : pcs->ppalet->pindexed); |
305 | 24.8k | pcl_cs_base_t *pbase = (use_frgrnd ? pcs->pfrgrnd->pbase : 0); |
306 | | |
307 | | /* check if there is a rendering */ |
308 | 24.8k | if ((pccolor = pptrn->pmask_ccolor) == 0) |
309 | 6 | return false; |
310 | | |
311 | | /* handle changes in the "foreground" color or color space */ |
312 | 24.8k | if ((pccolor->ccolor.paint.values[0] != ppaint->values[0]) || |
313 | 24.8k | (pccolor->ccolor.paint.values[1] != ppaint->values[1]) || |
314 | 24.8k | (pccolor->ccolor.paint.values[2] != ppaint->values[2]) || |
315 | 24.8k | (pccolor->pindexed != pindexed) || (pccolor->pbase != pbase)) { |
316 | | |
317 | | /* get a unique copy, and update the painting information */ |
318 | 43 | if (unshare_ccolor(pcs, &(pptrn->pmask_ccolor), pcs->memory) < 0) |
319 | 0 | return false; |
320 | 43 | pccolor = pptrn->pmask_ccolor; |
321 | | |
322 | 43 | pcl_cs_indexed_copy_from(pccolor->pindexed, pindexed); |
323 | 43 | pcl_cs_base_copy_from(pccolor->pbase, pbase); |
324 | 43 | pccolor->ccolor.paint = *ppaint; |
325 | 43 | } |
326 | 24.8k | } |
327 | | |
328 | 230k | return (set_patterned_color(pcs, pccolor) == 0); |
329 | 230k | } |
330 | | |
331 | | /* |
332 | | * Render and set a pattern. |
333 | | * |
334 | | * In a somewhat unfortunate division of labor, this code sets some but not |
335 | | * all of the cache keys in the pattern. The fields set are transparency, |
336 | | * orientation, and reference point. The caller is responsible for setting |
337 | | * the cache_id and pen number. |
338 | | * |
339 | | * If this routine is called, it may be assumed that the pattern needs to be |
340 | | * rendered. |
341 | | * |
342 | | */ |
343 | | static int |
344 | | render_pattern(pcl_state_t * pcs, |
345 | | pcl_pattern_t * pptrn, |
346 | | pcl_ccolor_type_t type, |
347 | | pcl_cs_indexed_t * pindexed, |
348 | | pcl_cs_base_t * pbase, |
349 | | const gs_paint_color * ppaint, int wht_indx, bool remap) |
350 | 5.06k | { |
351 | 5.06k | int code = 0; |
352 | 5.06k | pcl_ccolor_t *pccolor = 0; |
353 | 5.06k | gs_color_space *pcspace; |
354 | 5.06k | gs_matrix mat; |
355 | 5.06k | gs_depth_bitmap pixinfo; |
356 | | |
357 | | /* |
358 | | * If the orientation or reference point has changed, discard both |
359 | | * renderings. Otherwise, just discard the one being modified. |
360 | | * |
361 | | * Note that the unshare function doubles as an allocator. |
362 | | */ |
363 | 5.06k | if ((pptrn->orient != pcs->pat_orient) || |
364 | 1.86k | (pptrn->ref_pt.x != pcs->pat_ref_pt.x) || |
365 | 5.03k | (pptrn->ref_pt.y != pcs->pat_ref_pt.y)) { |
366 | 5.03k | if (type == pcl_ccolor_mask_pattern) { |
367 | 2.09k | pcl_ccolor_release(pptrn->pcol_ccolor); |
368 | 2.09k | pptrn->pcol_ccolor = 0; |
369 | 2.93k | } else { /* type == pcl_ccolor_colored_pattern */ |
370 | 2.93k | pcl_ccolor_release(pptrn->pmask_ccolor); |
371 | 2.93k | pptrn->pmask_ccolor = 0; |
372 | 2.93k | } |
373 | 5.03k | } |
374 | | |
375 | | /* un-share, or allocate, the appropriate client color */ |
376 | 5.06k | if (type == pcl_ccolor_mask_pattern) { |
377 | 2.10k | code = unshare_ccolor(pcs, &(pptrn->pmask_ccolor), pcs->memory); |
378 | 2.10k | pccolor = pptrn->pmask_ccolor; |
379 | 2.10k | pcspace = 0; |
380 | 2.96k | } else { /* type == pcl_ccolor_colored_pattern */ |
381 | 2.96k | code = unshare_ccolor(pcs, &(pptrn->pcol_ccolor), pcs->memory); |
382 | 2.96k | pccolor = pptrn->pcol_ccolor; |
383 | 2.96k | pcspace = pindexed->pcspace; |
384 | 2.96k | pptrn->transp = pcs->pattern_transparent; |
385 | 2.96k | } |
386 | 5.06k | if (code < 0) |
387 | 0 | return code; |
388 | | |
389 | | /* discard the existing pattern instance */ |
390 | 5.06k | gs_pattern_reference(&(pccolor->ccolor), -1); |
391 | 5.06k | pccolor->ccolor.pattern = 0; |
392 | | |
393 | | /* initialize the pattern data, if the client color is newly allocated */ |
394 | 5.06k | pccolor->type = type; |
395 | 5.06k | pcl_pattern_data_copy_from(pccolor->ppat_data, pptrn->ppat_data); |
396 | | |
397 | | /* set up the transformation and transparency information */ |
398 | 5.06k | pcl_xfm_get_pat_xfm(pcs, pptrn, &mat); |
399 | | |
400 | | /* set up the white index and remap as necessary */ |
401 | 5.06k | if (remap) { |
402 | 0 | code = pcl_cmap_map_raster(pindexed, |
403 | 0 | &wht_indx, |
404 | 0 | &(pptrn->ppat_data->pixinfo), |
405 | 0 | &pixinfo, true, pcs->memory); |
406 | 0 | if (code < 0) |
407 | 0 | return code; |
408 | 0 | pcspace = pindexed->pcspace; |
409 | 0 | if (pixinfo.data != pptrn->ppat_data->pixinfo.data) |
410 | 0 | pccolor->prast = pixinfo.data; |
411 | 0 | } else |
412 | 5.06k | pixinfo = pptrn->ppat_data->pixinfo; |
413 | | |
414 | 5.06k | if (pcspace != 0) |
415 | 2.96k | code = pcl_cs_indexed_install(&pindexed, pcs); |
416 | 5.06k | if (code < 0) |
417 | 0 | return code; |
418 | | |
419 | | /* the following is placed here until we have time to properly |
420 | | address this. The makepixmappattern() procedure detects a |
421 | | pattern as opaque if the white index is the number of entries |
422 | | in the current palette (the index of an invalid color). |
423 | | The motivation for this is the white index has no purpose for |
424 | | opaque patterns. Upon remapping (see above) the white index |
425 | | may be set to a white value in the palette, a valid color. We |
426 | | restore the invariant here, if necessary. */ |
427 | 5.06k | if ((type == pcl_ccolor_colored_pattern) && !pcs->pattern_transparent) |
428 | 2.96k | wht_indx = pindexed->num_entries; |
429 | | |
430 | 5.06k | code = gs_makepixmappattern(&(pccolor->ccolor), |
431 | 5.06k | &pixinfo, |
432 | 5.06k | (pcspace == 0), |
433 | 5.06k | &mat, |
434 | 5.06k | no_UniqueID, |
435 | 5.06k | pcspace, wht_indx, pcs->pgs, pcs->memory); |
436 | | |
437 | | /* if all is OK, install the pattern; otherwise clear the pattern */ |
438 | 5.06k | if (code >= 0) { |
439 | 5.06k | pcl_cs_indexed_copy_from(pccolor->pindexed, pindexed); |
440 | 5.06k | pcl_cs_base_copy_from(pccolor->pbase, pbase); |
441 | 5.06k | if (type == pcl_ccolor_mask_pattern) |
442 | 2.10k | pccolor->ccolor.paint = *ppaint; |
443 | 5.06k | code = set_patterned_color(pcs, pccolor); |
444 | 5.06k | } |
445 | 5.06k | return code; |
446 | 5.06k | } |
447 | | |
448 | | /* |
449 | | * Set a pattern using the foreground parameters. |
450 | | * |
451 | | * The for-image boolean indicates if the foreground is being set to render |
452 | | * a PCL raster. If so, and if the halftone/CRD combination for the foreground |
453 | | * is not the same as for the palette, a colored pattern must be generated. |
454 | | * This is because the CRD/halftone combination for the palette will be |
455 | | * current at the time the pattern is loaded into the cache, and thus the |
456 | | * color would be evaluated in the wrong context. |
457 | | * |
458 | | * Returns 0 on success, < 0 in the event of an error. |
459 | | */ |
460 | | static int |
461 | | set_frgrnd_pattern(pcl_state_t * pcs, pcl_pattern_t * pptrn, bool for_image) |
462 | 3.19k | { |
463 | 3.19k | pcl_frgrnd_t *pfrgrnd = pcs->pfrgrnd; |
464 | 3.19k | pcl_cs_base_t *pbase = pfrgrnd->pbase; |
465 | 3.19k | pcl_cs_indexed_t *pindexed = 0; |
466 | 3.19k | pcl_ccolor_type_t type = pcl_ccolor_mask_pattern; |
467 | 3.19k | gs_paint_color paint; |
468 | 3.19k | bool colored = false; |
469 | 3.19k | int code = 0; |
470 | 3.19k | int wht_indx = (pcs->pattern_transparent ? 0 : 2); |
471 | | |
472 | 3.19k | if (pfrgrnd->pht == pcs->ppalet->pht) |
473 | 3.19k | for_image = false; |
474 | | |
475 | 3.19k | colored = (for_image || !pcs->pattern_transparent); |
476 | | |
477 | 3.19k | convert_color_to_paint(pfrgrnd->color, &paint); |
478 | 3.19k | if (check_pattern_rendering(pcs, pptrn, true, 0, colored, &paint)) |
479 | 2.39k | return 0; |
480 | | |
481 | | /* build the two-entry palette if necessary */ |
482 | 797 | if (colored) { |
483 | 37 | code = pcl_cs_indexed_build_special(&pindexed, |
484 | 37 | pbase, |
485 | 37 | pfrgrnd->color, pcs->memory); |
486 | 37 | if (code < 0) |
487 | 0 | return code; |
488 | 37 | pbase = 0; |
489 | 37 | type = pcl_ccolor_colored_pattern; |
490 | 37 | } |
491 | | |
492 | 797 | code = render_pattern(pcs, |
493 | 797 | pptrn, |
494 | 797 | type, pindexed, pbase, &paint, wht_indx, false); |
495 | | |
496 | | /* release the extra reference to the indexed color space */ |
497 | 797 | if (colored) { |
498 | 37 | pcl_cs_indexed_release(pindexed); |
499 | 37 | if (code >= 0) { |
500 | 37 | pptrn->pen = 0; |
501 | 37 | pptrn->cache_id = pfrgrnd->id; |
502 | 37 | } |
503 | 37 | } |
504 | | |
505 | 797 | return code; |
506 | 797 | } |
507 | | |
508 | | /* |
509 | | * Set an uncolored pattern using the palette parameters and indicated pen |
510 | | * number. |
511 | | * |
512 | | * Returns 0 on success, < 0 in the event of an error. |
513 | | */ |
514 | | static int |
515 | | set_uncolored_palette_pattern(pcl_state_t * pcs, |
516 | | pcl_pattern_t * pptrn, int pen) |
517 | 232k | { |
518 | 232k | pcl_cs_indexed_t *pindexed = pcs->ppalet->pindexed; |
519 | 232k | pcl_ccolor_type_t type = pcl_ccolor_mask_pattern; |
520 | 232k | gs_paint_color paint; |
521 | 232k | bool colored = !pcs->pattern_transparent; |
522 | 232k | int code = 0; |
523 | | |
524 | 232k | convert_index_to_paint(pen, &paint); |
525 | 232k | if (check_pattern_rendering(pcs, pptrn, false, pen, colored, &paint)) |
526 | 228k | return 0; |
527 | | |
528 | | /* build the two-entry palette if necessary */ |
529 | 4.27k | if (colored) { |
530 | 2.92k | code = pcl_cs_indexed_build_special(&pindexed, |
531 | 2.92k | pindexed->pbase, |
532 | 2.92k | &(pindexed->palette. |
533 | 2.92k | data[3 * pen]), pcs->memory); |
534 | 2.92k | if (code < 0) |
535 | 0 | return code; |
536 | 2.92k | type = pcl_ccolor_colored_pattern; |
537 | 2.92k | } |
538 | | |
539 | 4.27k | code = render_pattern(pcs, pptrn, type, pindexed, NULL, &paint, 2, false); |
540 | | |
541 | | /* release the extra reference to the indexed color space */ |
542 | 4.27k | if (colored) { |
543 | 2.92k | pcl_cs_indexed_release(pindexed); |
544 | 2.92k | if (code >= 0) { |
545 | 2.92k | pptrn->pen = pen; |
546 | 2.92k | pptrn->cache_id = pcs->ppalet->id; |
547 | 2.92k | } |
548 | 2.92k | } |
549 | | |
550 | 4.27k | return code; |
551 | 4.27k | } |
552 | | |
553 | | /* |
554 | | * Set a colored pattern. |
555 | | * |
556 | | * Returns 0 on success, < 0 in the event of an error. |
557 | | */ |
558 | | static int |
559 | | set_colored_pattern(pcl_state_t * pcs, pcl_pattern_t * pptrn) |
560 | 0 | { |
561 | 0 | pcl_cs_indexed_t *pindexed = pcs->ppalet->pindexed; |
562 | 0 | pcl_gsid_t cache_id = pcs->ppalet->id; |
563 | 0 | int code = 0; |
564 | |
|
565 | 0 | if (check_pattern_rendering(pcs, pptrn, false, 0, true, NULL)) |
566 | 0 | return 0; |
567 | | |
568 | | /* note we always remap the white point. The remapping procedure |
569 | | serves the dual purpose of remapping the white point which may |
570 | | be necessary in the transparent case and resizing the palette |
571 | | which may be needed for either transparent or opaque |
572 | | patterns. */ |
573 | 0 | code = render_pattern(pcs, pptrn, pcl_ccolor_colored_pattern, pindexed, NULL, &white_paint, 0, true /* remap */ |
574 | 0 | ); |
575 | 0 | if (code >= 0) { |
576 | 0 | pptrn->pen = 0; |
577 | 0 | pptrn->cache_id = cache_id; |
578 | 0 | } |
579 | |
|
580 | 0 | return code; |
581 | 0 | } |
582 | | |
583 | | /* |
584 | | * Routines to set the current color space to a specific pattern. Since patterns |
585 | | * have different sources, each with its own system of identifiers, there are |
586 | | * several such routines. Each routine takes the current PCL state (including |
587 | | * the GL/2 state) as an operand; the additional operands, if any, vary by |
588 | | * routine type. |
589 | | * |
590 | | * pattern_set_white No additional operands. This routine |
591 | | * will set the color space to DeviceRGB, the |
592 | | * color to white, but will not override the |
593 | | * source or pattern transparency. A special |
594 | | * halftone with a null transfer function is used, |
595 | | * to avoid possible re-mapping of white to some |
596 | | * other color. |
597 | | * |
598 | | * pattern_set_pen Two additional operand: the pen number and a flag |
599 | | * to suppress use of unsolid patterns. GL pens Use |
600 | | * the indexed color space from the current palette |
601 | | * as the color space, and the pen number operand as |
602 | | * the index into this palette. The halftone and color |
603 | | * rendering dictionaries are taken from the current |
604 | | * palette. |
605 | | * |
606 | | * This routine is also used to set up the color to |
607 | | * be used for PCL rasters. This is necessary because, |
608 | | * while images in the graphic library carry their |
609 | | * own color space, this space must be installed in |
610 | | * a graphic state at least once inorder to be used |
611 | | * (specifically, CIE color spaces have this |
612 | | * requirement). In this situation, the use of the |
613 | | * "unsolid pattern" for transparency, which is |
614 | | * specific to GL, must be suppressed. |
615 | | * |
616 | | * Note that this routine does NOT set the current |
617 | | * line width (it does not have sufficient |
618 | | * information to convert the dimensions). |
619 | | * |
620 | | * pattern_set_frgrnd One additional operands. Sets currect base |
621 | | * color space as the color space, and the |
622 | | * foreground color as the current color. |
623 | | * The third (NOT second) operand indicates if the |
624 | | * foreground is being set to render a PCL raster. |
625 | | * The latter case involves special considerations; |
626 | | * see the paragraphs at the bottom of this comment |
627 | | * for additional information. |
628 | | * |
629 | | * pattern_set_shade_pcl |
630 | | * Two additional operands, the shade indensity |
631 | | * value and whether or not the shade pattern is |
632 | | * being set to render a PCL raster. |
633 | | * |
634 | | * This procedure is intended to be used by PCL. |
635 | | * It generates the shade as a colored pattern from |
636 | | * a two-element color palette consisting of the |
637 | | * canonical white for the current base color space |
638 | | * and the foreground color. The color space in the |
639 | | * graphic state is set to Pattern color space and |
640 | | * the current color is set to be the generated |
641 | | * pattern. The halftone and color rendering dictionary |
642 | | * objects are also taken from the current |
643 | | * foreground. |
644 | | * |
645 | | * Special considerations apply if the pattern is |
646 | | * being set to render a PCL raster. See the |
647 | | * paragraphs at the bottom of this comment for |
648 | | * additional information. |
649 | | * |
650 | | * pattern_set_shade_gl Two additional operands; the first provides |
651 | | * the pattern intensity, the latter the pen |
652 | | * number to be be used as the foreground color. |
653 | | * This routine generates the pattern using a two |
654 | | * entry palette consisting of canonical white in |
655 | | * the current base color space, and the operand |
656 | | * pen color from the current palette as the |
657 | | * second. The color space in the graphic state |
658 | | * is set to Pattern color space and the current |
659 | | * color is set to the generated pattern. The |
660 | | * halftone and color rendering dictionary objects |
661 | | * are taken from the current palette. |
662 | | * |
663 | | * pattern_set_hatch_pcl |
664 | | * Two additional operands, the index of the cross |
665 | | * hatch pattern and an indication of whether or not |
666 | | * the pattern is being set to render a PCL raster. |
667 | | * |
668 | | * Similar to pcl_pattern_set_shade_pcl, but for |
669 | | * cross-hatch patterns. |
670 | | * |
671 | | * pattern_set_hatch_gl Two additional operands; the first provides |
672 | | * the index of the cross hatch pattern, the |
673 | | * latter the pen number to be used as the |
674 | | * foreground color. Similar to |
675 | | * pcl_pattern_set_shade_gl, but for cross hatch |
676 | | * patterns. |
677 | | * |
678 | | * pattern_set_user_pcl |
679 | | * Two additional operands, the user pattern id. and |
680 | | * and indicator of whether or not the pattern is being |
681 | | * set to render a PCL raster. |
682 | | * |
683 | | * Handling is based on whether the pattern is |
684 | | * colored or uncolored. |
685 | | * |
686 | | * For uncolored patterns, handling is similar |
687 | | * to pcl_pattern_set_shade_pcl. The special |
688 | | * consideration for rasters apply only in this case. |
689 | | * |
690 | | * For colored patterns, the pattern is generated |
691 | | * using the indexed color space in the current |
692 | | * color palette. The color space in the graphic |
693 | | * state is set to Pattern color space, the current |
694 | | * color is set to the generated pattern, and the |
695 | | * halftone and color rendering dictionary objects |
696 | | * are taken from the current palette. |
697 | | * |
698 | | * pattern_set_user_gl Two additional operands. The first provides the |
699 | | * PCL user-defined pattern id. The second is the |
700 | | * current pen. Handling is base on whether the |
701 | | * pattern is colored or uncolored. |
702 | | * |
703 | | * For uncolored patterns, handling is similar |
704 | | * to pcl_pattern_set_shade_gl. |
705 | | * |
706 | | * For colored patterns, handling is similar to |
707 | | * pcl_pattern_set_user_pcl. |
708 | | * |
709 | | * pattern_set_gl_RF Two additional operands, the index of the |
710 | | * GL/2 user defined pattern (created with the |
711 | | * RF command), and the current pen number. The |
712 | | * latter is used only for unoclored RF patterns. |
713 | | * |
714 | | * To keep life interesting, HP inserted a very |
715 | | * odd feature into the behavior of uncolored |
716 | | * RF patterns. Generally, the applicable SV or |
717 | | * FT command determines whether the current pen |
718 | | * or pen 1 is to be used for the foreground pixels. |
719 | | * However, if the reference pattern does not exist, |
720 | | * the current pen is always used. |
721 | | * |
722 | | * To accommodate this behavior within the current |
723 | | * scheme, the current pen is passed as a negative |
724 | | * number if pen 1 is for a pattern that exists. |
725 | | * |
726 | | * All procedures return 0 on success, < 0 in the event of an error. |
727 | | * |
728 | | * If that did not seem to make things complex enough, some additional |
729 | | * complications arise for transparency in GL/2 and for PCL rasters. |
730 | | * |
731 | | * GL/2 has a concept of transparency similar to PCL's, though what GL terms |
732 | | * "source" transparency corresponds to PCL's pattern transparency (all GL/2 |
733 | | * objects are mask; hence, they have neither color nor background, so the |
734 | | * PCL concept of source transparency is irrelevant for them). Unlike PCL, |
735 | | * however, uncolored patterns in GL/2 are fully transparent if the current |
736 | | * pen is white. The normal code for uncolored patterns is not equipped to |
737 | | * handle this situation, and it make little sense to modify it for what is |
738 | | * not a particular useful case. Hence, a special "unsolid" uncolored pattern |
739 | | * is provided. This pattern has only background, and thus is fully transparent. |
740 | | * |
741 | | * The difficulty with PCL rasters is that, being colored objects, they make |
742 | | * use of a CRD and a halftone to render. Rasters may also interact with the |
743 | | * current color, which may be using a different CRD and halftone. |
744 | | * |
745 | | * The CRD and halftone to be used with rasters are taken from the current |
746 | | * PCL palette. If the current pattern is either solid foreground (the most |
747 | | * typical case) or an uncolored pattern, the current "texture" is generated |
748 | | * using the CRD and halftone from the PCL foreground. The two may not be the |
749 | | * same, and unfortunately there is room for only one of each in the graphic |
750 | | * state. |
751 | | * |
752 | | * The solution is to make use of an additional graphic state. Patterns in the |
753 | | * graphic library have their own graphic state. Hence, but converting a solid |
754 | | * foreground into an uncolored pattern which happens to be "on" everywhere, it |
755 | | * is possible to achieve the desired result. For performance reasons, this |
756 | | * should be done only when necessary. |
757 | | */ |
758 | | |
759 | | static int |
760 | | pattern_set_white(pcl_state_t * pcs, int arg1, /* ignored */ |
761 | | int arg2 /* ignored */ |
762 | | ) |
763 | 30.0k | { |
764 | 30.0k | int code = 0; |
765 | 30.0k | pcl_cs_base_t *pwhite_cs = 0; |
766 | 30.0k | pcl_ht_t *pdflt_ht = 0; |
767 | | |
768 | 30.0k | if_debug0m('c', pcs->memory, "[c]pattern_set_white\n"); |
769 | | |
770 | | /* build the pure white color space and default halftone if necessary */ |
771 | 30.0k | if ((code = |
772 | 30.0k | pcl_cs_base_build_white_cspace(pcs, &pwhite_cs, pcs->memory)) >= 0) |
773 | 30.0k | code = pcl_ht_build_default_ht(pcs, &pdflt_ht, pcs->memory); |
774 | | |
775 | | /* set the halftone and color space */ |
776 | 30.0k | if (code >= 0) { |
777 | 30.0k | code = pcl_ht_set_halftone(pcs); |
778 | 30.0k | pcl_ht_release(pdflt_ht); /* decrement reference to local ptr */ |
779 | 30.0k | } |
780 | | |
781 | 30.0k | if (code >= 0) |
782 | 30.0k | code = set_unpatterned_color(pcs, NULL, pwhite_cs, &white_paint); |
783 | 30.0k | pcl_cs_base_release(pwhite_cs); |
784 | 30.0k | return code; |
785 | 30.0k | } |
786 | | |
787 | | static int pattern_set_shade_gl(pcl_state_t * pcs, int inten, /* intensity value */ |
788 | | int pen /* pen number for foreground */ |
789 | | ); |
790 | | |
791 | | static int |
792 | | pattern_set_pen(pcl_state_t * pcs, int pen, int for_pcl_raster) |
793 | 3.29M | { |
794 | 3.29M | pcl_cs_indexed_t *pindexed = pcs->ppalet->pindexed; |
795 | 3.29M | int num_entries = pindexed->num_entries; |
796 | 3.29M | int code = 0; |
797 | | |
798 | 3.29M | if_debug3m('c', pcs->memory, |
799 | 3.29M | "[c]pattern_set_pen pen=%d, for raster=%d entries=%d\n", pen, |
800 | 3.29M | for_pcl_raster, num_entries); |
801 | | |
802 | | /* put the pen number in the proper range */ |
803 | 3.29M | if ((pen >= num_entries) && |
804 | 0 | ((pen = (pen % num_entries) + 1) == num_entries)) |
805 | 0 | pen = 1; |
806 | | |
807 | | /* check if the current pen is white; if so, use the "unsolid" pattern */ |
808 | | |
809 | 3.29M | if (!for_pcl_raster && pcl_cs_indexed_is_white(pindexed, pen)) { |
810 | | /* Optimization for a special case where we don't need the |
811 | | unsolid pattern, drawing an opaque white rectangle with |
812 | | simple rops (we only check for 2 common rops). */ |
813 | 220k | if (!pcs->g.source_transparent && |
814 | 204k | (pcs->logical_op == rop3_default || pcs->logical_op == rop3_T)) |
815 | 15.5k | goto skip_unsolid; |
816 | 204k | else { |
817 | 204k | code = pattern_set_shade_gl(pcs, 1, pen); |
818 | 204k | if (code >= 0) { |
819 | 204k | code = gx_set_dev_color(pcs->pgs); |
820 | 204k | if (code == gs_error_Remap_Color) { |
821 | 0 | code = pixmap_high_level_pattern(pcs->pgs); |
822 | 0 | if (code < 0) |
823 | 0 | return code; |
824 | 0 | return pattern_set_shade_gl(pcs, 1, pen); |
825 | 0 | } |
826 | 204k | } |
827 | 204k | return code; |
828 | 204k | } |
829 | 220k | } |
830 | | |
831 | | /* set halftone and crd from the palette */ |
832 | 3.08M | skip_unsolid: |
833 | 3.08M | { |
834 | 3.08M | gs_paint_color paint = { {0, 0, 0, 0} |
835 | 3.08M | }; |
836 | | |
837 | 3.08M | convert_index_to_paint(pen, &paint); |
838 | 3.08M | code = set_unpatterned_color(pcs, pindexed, NULL, &paint); |
839 | 3.08M | } |
840 | 3.08M | return code; |
841 | 3.29M | } |
842 | | |
843 | | static int |
844 | | pattern_set_frgrnd(pcl_state_t * pcs, int arg1, /* ignored */ |
845 | | int for_image) |
846 | 10.5M | { |
847 | 10.5M | pcl_frgrnd_t *pfrgrnd = pcs->pfrgrnd; |
848 | 10.5M | pcl_palette_t *ppalet = pcs->ppalet; |
849 | 10.5M | int code = 0; |
850 | | |
851 | 10.5M | if_debug1m('c', pcs->memory, "[c]pattern_set_frgrnd for image=%d\n", |
852 | 10.5M | for_image); |
853 | | |
854 | | /* check if a solid pattern should be substituted */ |
855 | 10.5M | if (for_image) { |
856 | 6.34k | if (pfrgrnd->pht != ppalet->pht) { |
857 | 0 | code = |
858 | 0 | set_frgrnd_pattern(pcs, pcl_pattern_get_solid_pattern(pcs), |
859 | 0 | true); |
860 | 0 | return code; |
861 | 0 | } else |
862 | 6.34k | if ((ppalet->pindexed->original_cspace == 1 && !pfrgrnd->is_cmy) |
863 | 6.34k | || (ppalet->pindexed->original_cspace != 1 |
864 | 6.34k | && pfrgrnd->is_cmy)) { |
865 | 0 | const byte blk[] = { 0, 0, 0 }; |
866 | 0 | gs_paint_color paint; |
867 | | |
868 | | /* NB: HP forces black foreground, as they can't handle different |
869 | | * colorspaces in foreground and raster palette |
870 | | */ |
871 | 0 | convert_color_to_paint(blk, &paint); |
872 | 0 | code = set_unpatterned_color(pcs, NULL, pfrgrnd->pbase, &paint); |
873 | 0 | return code; |
874 | 0 | } |
875 | 6.34k | } |
876 | 10.5M | { |
877 | 10.5M | gs_paint_color paint; |
878 | | |
879 | 10.5M | convert_color_to_paint(pfrgrnd->color, &paint); |
880 | 10.5M | code = set_unpatterned_color(pcs, NULL, pfrgrnd->pbase, &paint); |
881 | 10.5M | } |
882 | | |
883 | 10.5M | return code; |
884 | 10.5M | } |
885 | | |
886 | | static int |
887 | | pattern_set_shade_pcl(pcl_state_t * pcs, int inten, /* intensity value */ |
888 | | int for_image) |
889 | 53.6k | { |
890 | 53.6k | pcl_pattern_t *pptrn = pcl_pattern_get_shade(pcs, inten); |
891 | | |
892 | 53.6k | if_debug2m('c', pcs->memory, |
893 | 53.6k | "[c]pattern_set_shade_pcl intensity=%d, for raster=%d\n", |
894 | 53.6k | inten, for_image); |
895 | 53.6k | if (pptrn == 0) |
896 | 51.1k | return (inten > 0 ? pattern_set_frgrnd(pcs, 0, for_image) |
897 | 51.1k | : pattern_set_white(pcs, 0, 0)); |
898 | 2.56k | else { |
899 | 2.56k | pcl_xfm_pcl_set_pat_ref_pt(pcs); |
900 | 2.56k | return set_frgrnd_pattern(pcs, pptrn, for_image); |
901 | 2.56k | } |
902 | 53.6k | } |
903 | | |
904 | | static int |
905 | | pattern_set_shade_gl(pcl_state_t * pcs, int inten, /* intensity value */ |
906 | | int pen /* pen number for foreground */ |
907 | | ) |
908 | 205k | { |
909 | 205k | pcl_pattern_t *pptrn = pcl_pattern_get_shade(pcs, inten); |
910 | | |
911 | 205k | if_debug2m('c', pcs->memory, |
912 | 205k | "[c]pattern_set_shade_gl intensity=%d, pen=%d\n", inten, pen); |
913 | | |
914 | | /* check if the current pen is white or the pattern is transparent |
915 | | and the intensity is 0 (white) and if so use the unsolid |
916 | | pattern */ |
917 | 205k | if (pcl_cs_indexed_is_white(pcs->ppalet->pindexed, pen) || |
918 | 1.00k | (pcs->pattern_transparent && inten == 0)) |
919 | 204k | pptrn = pcl_pattern_get_unsolid_pattern(pcs); |
920 | | |
921 | 205k | if (pptrn == NULL) |
922 | 44 | return (inten > 0 ? pattern_set_pen(pcs, pen, false) |
923 | 44 | : pattern_set_white(pcs, 0, 0)); |
924 | | |
925 | 205k | pcl_xfm_gl_set_pat_ref_pt(pcs); |
926 | 205k | return set_uncolored_palette_pattern(pcs, pptrn, pen); |
927 | 205k | } |
928 | | |
929 | | static int |
930 | | pattern_set_hatch_pcl(pcl_state_t * pcs, int indx, /* cross-hatch pattern index */ |
931 | | int for_image) |
932 | 630 | { |
933 | 630 | pcl_pattern_t *pptrn = pcl_pattern_get_cross(pcs, indx); |
934 | | |
935 | 630 | if_debug2m('c', pcs->memory, |
936 | 630 | "[c]pattern_set_hatch_pcl index=%d, for raster=%d\n", indx, |
937 | 630 | for_image); |
938 | | |
939 | 630 | if (pptrn == 0) |
940 | 0 | return pattern_set_frgrnd(pcs, 0, for_image); |
941 | 630 | else { |
942 | 630 | pcl_xfm_pcl_set_pat_ref_pt(pcs); |
943 | 630 | return set_frgrnd_pattern(pcs, pptrn, for_image); |
944 | 630 | } |
945 | 630 | } |
946 | | |
947 | | static int |
948 | | pattern_set_hatch_gl(pcl_state_t * pcs, int indx, /* cross-hatch pattern index */ |
949 | | int pen /* pen number for foreground */ |
950 | | ) |
951 | 0 | { |
952 | 0 | pcl_pattern_t *pptrn = pcl_pattern_get_cross(pcs, indx); |
953 | |
|
954 | 0 | if_debug2m('c', pcs->memory, "[c]pattern_set_hatch_gl index=%d pen=%d\n", |
955 | 0 | indx, pen); |
956 | | /* check if the current pen is white; if so, use the "unsolid" pattern */ |
957 | 0 | if (pcl_cs_indexed_is_white(pcs->ppalet->pindexed, pen)) |
958 | 0 | pptrn = pcl_pattern_get_unsolid_pattern(pcs); |
959 | |
|
960 | 0 | if (pptrn == NULL) |
961 | 0 | return pattern_set_pen(pcs, pen, false); |
962 | | |
963 | 0 | pcl_xfm_gl_set_pat_ref_pt(pcs); |
964 | 0 | return set_uncolored_palette_pattern(pcs, pptrn, pen); |
965 | 0 | } |
966 | | |
967 | | static int |
968 | | pattern_set_user_pcl(pcl_state_t * pcs, int id, /* pattern id. */ |
969 | | int for_image) |
970 | 0 | { |
971 | 0 | pcl_pattern_t *pptrn = pcl_pattern_get_pcl_uptrn(pcs, id); |
972 | |
|
973 | 0 | if_debug2m('c', pcs->memory, "[c]pattern_set_user_pcl id=%d raster=%d\n", |
974 | 0 | id, for_image); |
975 | |
|
976 | 0 | if (pptrn == 0) |
977 | 0 | return pattern_set_frgrnd(pcs, 0, for_image); |
978 | 0 | else { |
979 | 0 | pcl_xfm_pcl_set_pat_ref_pt(pcs); |
980 | 0 | if (pptrn->ppat_data->type == pcl_pattern_uncolored) |
981 | 0 | return set_frgrnd_pattern(pcs, pptrn, for_image); |
982 | 0 | else |
983 | 0 | return set_colored_pattern(pcs, pptrn); |
984 | 0 | } |
985 | 0 | } |
986 | | |
987 | | static int |
988 | | pattern_set_user_gl(pcl_state_t * pcs, int id, /* pattern id. */ |
989 | | int pen /* pen to use for foreground */ |
990 | | ) |
991 | 0 | { |
992 | 0 | pcl_pattern_t *pptrn = pcl_pattern_get_pcl_uptrn(pcs, id); |
993 | |
|
994 | 0 | if_debug2m('c', pcs->memory, "[c]pattern_set_user_gl id=%d, pen=%d\n", id, |
995 | 0 | pen); |
996 | |
|
997 | 0 | if (pptrn == 0) |
998 | 0 | return pattern_set_pen(pcs, 0, false); |
999 | 0 | else { |
1000 | |
|
1001 | 0 | pcl_xfm_gl_set_pat_ref_pt(pcs); |
1002 | 0 | if (pptrn->ppat_data->type == pcl_pattern_uncolored) { |
1003 | | |
1004 | | /* check if the current pen is white */ |
1005 | 0 | if (pcl_cs_indexed_is_white(pcs->ppalet->pindexed, pen)) { |
1006 | 0 | pptrn = pcl_pattern_get_unsolid_pattern(pcs); |
1007 | 0 | if (pptrn == NULL) return e_Memory; |
1008 | 0 | } |
1009 | 0 | return set_uncolored_palette_pattern(pcs, pptrn, pen); |
1010 | |
|
1011 | 0 | } else |
1012 | 0 | return set_colored_pattern(pcs, pptrn); |
1013 | 0 | } |
1014 | 0 | } |
1015 | | |
1016 | | static int |
1017 | | pattern_set_gl_RF(pcl_state_t * pcs, int indx, /* GL/2 RF pattern index */ |
1018 | | int pen /* used only for uncolored patterns */ |
1019 | | ) |
1020 | 31.8k | { |
1021 | 31.8k | pcl_pattern_t *pptrn = pcl_pattern_get_gl_uptrn(pcs, indx); |
1022 | | |
1023 | 31.8k | if_debug2m('c', pcs->memory, "[c]pattern_set_gl_RF index=%d pen=%d\n", |
1024 | 31.8k | indx, pen); |
1025 | | /* |
1026 | | * HACK - if pen 1 is to be use for actual uncolored RF patterns, the pen |
1027 | | * operand will be the opposite of the current pen number. This allows us |
1028 | | * to use the current pen if the pattern does not exist. |
1029 | | */ |
1030 | 31.8k | if (pptrn == 0) |
1031 | 5.10k | return pattern_set_pen(pcs, (pen < 0 ? -pen : pen), false); |
1032 | 26.7k | else { |
1033 | 26.7k | if (pen < 0) |
1034 | 0 | pen = 1; |
1035 | | |
1036 | 26.7k | pcl_xfm_gl_set_pat_ref_pt(pcs); |
1037 | 26.7k | if (pptrn != NULL && pptrn->ppat_data != NULL) { |
1038 | 26.7k | if (pptrn->ppat_data->type == pcl_pattern_uncolored) { |
1039 | | |
1040 | | /* check if the current pen is white */ |
1041 | 26.7k | if (pcl_cs_indexed_is_white(pcs->ppalet->pindexed, pen)) { |
1042 | 0 | pptrn = pcl_pattern_get_unsolid_pattern(pcs); |
1043 | 0 | if (pptrn == NULL) return e_Memory; |
1044 | 0 | } |
1045 | 26.7k | return set_uncolored_palette_pattern(pcs, pptrn, pen); |
1046 | | |
1047 | 26.7k | } else |
1048 | 0 | return set_colored_pattern(pcs, pptrn); |
1049 | 26.7k | } else |
1050 | 0 | return e_Syntax; |
1051 | 26.7k | } |
1052 | 31.8k | } |
1053 | | |
1054 | | /* |
1055 | | * Return the appropriate "set" procedure, given a PCL pattern type. |
1056 | | */ |
1057 | | pcl_pattern_set_proc_t |
1058 | | pcl_pattern_get_proc_PCL(pcl_pattern_source_t pattern_source) |
1059 | 10.5M | { |
1060 | 10.5M | static const pcl_pattern_set_proc_t procs[] = { pattern_set_frgrnd, |
1061 | 10.5M | pattern_set_white, |
1062 | 10.5M | pattern_set_shade_pcl, |
1063 | 10.5M | pattern_set_hatch_pcl, |
1064 | 10.5M | pattern_set_user_pcl, |
1065 | 10.5M | 0, |
1066 | 10.5M | pattern_set_pen |
1067 | 10.5M | }; |
1068 | | |
1069 | 10.5M | return procs[(int)pattern_source]; |
1070 | 10.5M | } |
1071 | | |
1072 | | /* |
1073 | | * Returen the appropriate "set" procedure, given a GL fill type specification. |
1074 | | */ |
1075 | | pcl_pattern_set_proc_t |
1076 | | pcl_pattern_get_proc_FT(hpgl_FT_pattern_source_t pattern_source) |
1077 | 1.05M | { |
1078 | 1.05M | if ((pattern_source == hpgl_FT_pattern_solid_pen1) || |
1079 | 32.8k | (pattern_source == hpgl_FT_pattern_solid_pen2)) |
1080 | 1.02M | return pattern_set_pen; |
1081 | 32.8k | else if (pattern_source == hpgl_FT_pattern_shading) |
1082 | 1.00k | return pattern_set_shade_gl; |
1083 | 31.8k | else if (pattern_source == hpgl_FT_pattern_RF) |
1084 | 31.8k | return pattern_set_gl_RF; |
1085 | 11 | else if (pattern_source == hpgl_FT_pattern_cross_hatch) |
1086 | 0 | return pattern_set_hatch_gl; |
1087 | 11 | else if (pattern_source == hpgl_FT_pattern_user_defined) |
1088 | 0 | return pattern_set_user_gl; |
1089 | 11 | else |
1090 | 11 | return 0; |
1091 | 1.05M | } |
1092 | | |
1093 | | /* |
1094 | | * Returen the appropriate "set" procedure, given a GL screened vector |
1095 | | * specification. |
1096 | | */ |
1097 | | pcl_pattern_set_proc_t |
1098 | | pcl_pattern_get_proc_SV(hpgl_SV_pattern_source_t pattern_source) |
1099 | 2.26M | { |
1100 | 2.26M | if (pattern_source == hpgl_SV_pattern_solid_pen) |
1101 | 2.26M | return pattern_set_pen; |
1102 | 0 | else if (pattern_source == hpgl_SV_pattern_shade) |
1103 | 0 | return pattern_set_shade_gl; |
1104 | 0 | else if (pattern_source == hpgl_SV_pattern_RF) |
1105 | 0 | return pattern_set_gl_RF; |
1106 | 0 | else if (pattern_source == hpgl_SV_pattern_cross_hatch) |
1107 | 0 | return pattern_set_hatch_gl; |
1108 | 0 | else if (pattern_source == hpgl_SV_pattern_user_defined) |
1109 | 0 | return pattern_set_user_gl; |
1110 | 0 | else |
1111 | 0 | return 0; |
1112 | 2.26M | } |
1113 | | |
1114 | | /* |
1115 | | * ESC * c <#/id> G |
1116 | | * |
1117 | | * Set the pattern id. |
1118 | | */ |
1119 | | static int |
1120 | | set_pattern_id(pcl_args_t * pargs, pcl_state_t * pcs) |
1121 | 3.93k | { |
1122 | 3.93k | pcs->pattern_id = int_arg(pargs); |
1123 | 3.93k | return 0; |
1124 | 3.93k | } |
1125 | | |
1126 | | /* |
1127 | | * ESC * v <bool> N |
1128 | | * |
1129 | | * Set source transparency mode |
1130 | | */ |
1131 | | static int |
1132 | | set_source_transparency_mode(pcl_args_t * pargs, pcl_state_t * pcs) |
1133 | 1.59k | { |
1134 | 1.59k | int code = 0; |
1135 | 1.59k | uint i = uint_arg(pargs); |
1136 | | |
1137 | 1.59k | if (i <= 1) { |
1138 | 1.59k | code = pcl_break_underline(pcs); |
1139 | 1.59k | pcs->source_transparent = (i == 0); |
1140 | 1.59k | } |
1141 | 1.59k | return code; |
1142 | 1.59k | } |
1143 | | |
1144 | | /* |
1145 | | * ESC * v <bool> O |
1146 | | * |
1147 | | * Set pattern transparency mode. |
1148 | | */ |
1149 | | static int |
1150 | | set_pattern_transparency_mode(pcl_args_t * pargs, pcl_state_t * pcs) |
1151 | 3.41k | { |
1152 | 3.41k | int code = 0; |
1153 | 3.41k | uint i = uint_arg(pargs); |
1154 | | |
1155 | 3.41k | if (i <= 1) { |
1156 | 3.39k | code = pcl_break_underline(pcs); |
1157 | 3.39k | pcs->pcl_pattern_transparent = (i == 0); |
1158 | 3.39k | } |
1159 | 3.41k | return code; |
1160 | 3.41k | } |
1161 | | |
1162 | | /* |
1163 | | * ESC * v # T |
1164 | | * |
1165 | | * Set current pattern id. |
1166 | | */ |
1167 | | static int |
1168 | | select_current_pattern(pcl_args_t * pargs, pcl_state_t * pcs) |
1169 | 515 | { |
1170 | 515 | int code = 0; |
1171 | 515 | uint i = uint_arg(pargs); |
1172 | | |
1173 | 515 | if (i <= (int)pcl_pattern_user_defined) { |
1174 | 514 | code = pcl_break_underline(pcs); |
1175 | 514 | pcs->current_pattern_id = pcs->pattern_id; |
1176 | 514 | pcs->pattern_type = (pcl_pattern_source_t) i; |
1177 | 514 | } |
1178 | 515 | return code; |
1179 | 515 | } |
1180 | | |
1181 | | /* |
1182 | | * ESC * o # W |
1183 | | * |
1184 | | * Driver configuration command. A partial implementation to show |
1185 | | * that we are parsing the command correctly. The lightness and |
1186 | | * saturation parameters are not documented so we do not believe this |
1187 | | * command will be used by an application or driver. |
1188 | | * |
1189 | | */ |
1190 | | |
1191 | | typedef struct driver_configuration_s |
1192 | | { |
1193 | | byte device_id; |
1194 | | byte function_index; |
1195 | | char arguments; |
1196 | | } driver_configuration_t; |
1197 | | |
1198 | | static int |
1199 | | set_driver_configuration(pcl_args_t * pargs, /* ignored */ |
1200 | | pcl_state_t * pcs /* ignored */ |
1201 | | ) |
1202 | 0 | { |
1203 | 0 | uint count = uint_arg(pargs); |
1204 | |
|
1205 | 0 | driver_configuration_t *driver = |
1206 | 0 | (driver_configuration_t *) arg_data(pargs); |
1207 | |
|
1208 | | #ifdef DEBUG |
1209 | | if (gs_debug_c('i')) { |
1210 | | pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs)); |
1211 | | } |
1212 | | #endif |
1213 | |
|
1214 | 0 | if (pcs->personality == pcl5e) |
1215 | 0 | return 0; |
1216 | | |
1217 | 0 | if (count != sizeof(driver_configuration_t)) |
1218 | 0 | return e_Range; |
1219 | | |
1220 | | /* the only device known to support this command */ |
1221 | 0 | if ((driver->device_id < 6) /* 6 == hp color laserjet */ |
1222 | 0 | || /* 7 == hp clj 5 */ |
1223 | 0 | (driver->device_id > 8)) { /* 8 == hp 4500 - 4550 */ |
1224 | 0 | dmprintf1(pcs->memory, "unknown device id %d\n", driver->device_id); |
1225 | 0 | return e_Range; |
1226 | 0 | } |
1227 | | |
1228 | 0 | switch (driver->function_index) { |
1229 | 0 | case 0: /* lightness */ |
1230 | 0 | { |
1231 | 0 | int code; |
1232 | |
|
1233 | 0 | if (driver->arguments < -100 || driver->arguments > 100) |
1234 | 0 | return e_Range; |
1235 | | /* map -100..100 to gamma setting 0.05..4.05 */ |
1236 | 0 | code = |
1237 | 0 | pcl_palette_set_gamma(pcs, |
1238 | 0 | ((driver->arguments + |
1239 | 0 | 100.0) / 200.0) + 0.05); |
1240 | 0 | if (code < 0) |
1241 | 0 | return code; |
1242 | 0 | } |
1243 | 0 | break; |
1244 | 0 | case 1: /* saturation */ |
1245 | 0 | { |
1246 | 0 | int code; |
1247 | |
|
1248 | 0 | if (driver->arguments < -100 || driver->arguments > 100) |
1249 | 0 | return e_Range; |
1250 | | /* map -100..100 to gamma setting 0.05..4.05 */ |
1251 | 0 | code = |
1252 | 0 | pcl_palette_set_gamma(pcs, |
1253 | 0 | ((driver->arguments + |
1254 | 0 | 100.0) / 200.0) + 0.05); |
1255 | 0 | if (code < 0) |
1256 | 0 | return code; |
1257 | 0 | } |
1258 | 0 | break; |
1259 | 0 | case 4: |
1260 | | /* driver arguments 3 & 6 are parsed, but not implemented. In |
1261 | | our model where all data is treated as sRGB and color |
1262 | | conversion is expected to be done by the device, vivid |
1263 | | graphics (argument == 3) should set a device parameter to |
1264 | | disable color conversion. We don't think there is any |
1265 | | demand for this feature, and it is not currently |
1266 | | supported. */ |
1267 | 0 | if (driver->arguments == 3) { |
1268 | 0 | ; |
1269 | 0 | } else if (driver->arguments == 6) { |
1270 | 0 | ; |
1271 | 0 | } else |
1272 | 0 | return e_Range; |
1273 | 0 | break; |
1274 | 0 | default: |
1275 | 0 | return e_Range; |
1276 | 0 | } |
1277 | 0 | return 0; |
1278 | 0 | } |
1279 | | |
1280 | | /* |
1281 | | * Initialization and reset routines. |
1282 | | */ |
1283 | | static int |
1284 | | pattern_do_registration(pcl_parser_state_t * pcl_parser_state, |
1285 | | gs_memory_t * pmem) |
1286 | 11.0k | { |
1287 | 11.0k | DEFINE_CLASS('*') { |
1288 | 11.0k | 'c', 'G', |
1289 | 11.0k | PCL_COMMAND("Pattern ID", |
1290 | 11.0k | set_pattern_id, |
1291 | 11.0k | pca_neg_ignore | pca_big_ignore | pca_in_rtl) |
1292 | 11.0k | }, { |
1293 | 11.0k | 'v', 'N', |
1294 | 11.0k | PCL_COMMAND("Source Transparency Mode", |
1295 | 11.0k | set_source_transparency_mode, |
1296 | 11.0k | pca_neg_ignore | pca_big_ignore | pca_in_rtl | |
1297 | 11.0k | pca_dont_lockout_in_rtl) |
1298 | 11.0k | }, { |
1299 | 11.0k | 'v', 'O', |
1300 | 11.0k | PCL_COMMAND("Pattern Transparency Mode", |
1301 | 11.0k | set_pattern_transparency_mode, |
1302 | 11.0k | pca_neg_ignore | pca_big_ignore | pca_in_rtl) |
1303 | 11.0k | }, { |
1304 | 11.0k | 'v', 'T', |
1305 | 11.0k | PCL_COMMAND("Select Current Pattern", |
1306 | 11.0k | select_current_pattern, |
1307 | 11.0k | pca_neg_ignore | pca_big_ignore | pca_in_rtl) |
1308 | 11.0k | }, { |
1309 | 11.0k | 'o', 'W', |
1310 | 11.0k | PCL_COMMAND("Driver Configuration Command", |
1311 | 11.0k | set_driver_configuration, pca_bytes | pca_in_rtl) |
1312 | 11.0k | }, END_CLASS return 0; |
1313 | | |
1314 | 11.0k | } |
1315 | | |
1316 | | static int |
1317 | | pattern_do_reset(pcl_state_t * pcs, pcl_reset_type_t type) |
1318 | 44.0k | { |
1319 | 44.0k | static const uint mask = (pcl_reset_initial |
1320 | 44.0k | | pcl_reset_cold |
1321 | 44.0k | | pcl_reset_printer | pcl_reset_overlay); |
1322 | | |
1323 | 44.0k | if ((type & mask) != 0) { |
1324 | 44.0k | if ((type & pcl_reset_initial) != 0) |
1325 | 11.0k | pcl_pattern_init_bi_patterns(pcs); |
1326 | 44.0k | pcs->pcl_pattern_transparent = true; |
1327 | 44.0k | pcs->pattern_transparent = true; |
1328 | 44.0k | pcs->source_transparent = true; |
1329 | 44.0k | pcs->pattern_id = 0; |
1330 | 44.0k | pcs->current_pattern_id = 0; |
1331 | 44.0k | pcs->pattern_type = pcl_pattern_solid_frgrnd; |
1332 | 44.0k | } |
1333 | 44.0k | if (type & pcl_reset_permanent || type & pcl_reset_printer) { |
1334 | 33.0k | if (gstate_pattern_cache(pcs->pgs)) { |
1335 | 660 | gs_gstate *pgs = pcs->pgs; |
1336 | | |
1337 | 660 | (gstate_pattern_cache(pgs)->free_all) (gstate_pattern_cache(pgs)); |
1338 | 660 | gs_free_object(pcs->memory, |
1339 | 660 | gstate_pattern_cache(pgs)->tiles, |
1340 | 660 | "pattern_do_reset(tiles)"); |
1341 | 660 | gs_free_object(pcs->memory, |
1342 | 660 | gstate_pattern_cache(pgs), |
1343 | 660 | "pattern_do_reset(struct)"); |
1344 | 3.30k | while (pgs) { |
1345 | 2.64k | gstate_set_pattern_cache(pgs, 0); |
1346 | 2.64k | pgs = gs_gstate_saved(pgs); |
1347 | 2.64k | } |
1348 | 660 | } |
1349 | 33.0k | } |
1350 | 44.0k | return 0; |
1351 | 44.0k | } |
1352 | | |
1353 | | const pcl_init_t pcl_pattern_init = |
1354 | | { pattern_do_registration, pattern_do_reset, 0 }; |