1 /* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /* PLanar Interlaced Banded device */
17 #include "gdevprn.h"
18 #include "gscdefs.h"
19 #include "gscspace.h" /* For pnm_begin_typed_image(..) */
20 #include "gxgetbit.h"
21 #include "gxlum.h"
22 #include "gxiparam.h" /* For pnm_begin_typed_image(..) */
23 #include "gdevmpla.h"
24 #include "gdevplnx.h"
25 #include "gdevppla.h"
26 #include "gdevplib.h" /* Band donor functions */
27 #include "gdevmem.h"
28 
29 /* This file defines 5 different devices:
30  *
31  *  plib   24 bit RGB (8 bits per channel)
32  *  plibg   8 bit Grayscale
33  *  plibm   1 bit Monochrome
34  *  plibc  32 bit CMYK (8 bits per channel)
35  *  plibk   4 bit CMYK (1 bit per channel)
36  *
37  * It is intended that this device will be built on top of a 'Band Donor'
38  * that will be responsible for allocating and pass us band buffers for us
39  * to fill, and to process them as it wishes on completion.
40  *
41  * For debugging/QA purposes this file can be built with the following
42  * define enabled, and stub versions of these band donor functions will
43  * be included here.
44  */
45 #define TESTING_WITH_NO_BAND_DONOR
46 
47 /* Define DEBUG_PRINT to enable some debugging printfs. */
48 #undef DEBUG_PRINT
49 
50 /* Define DEBUG_DUMP to dump the data to the output stream. */
51 #define DEBUG_DUMP
52 
53 /* Define HT_RAW_DUMP to store the output as a raw CMYK buffer with the
54    data size packed into the file name.  Photoshop does not handle pam
55    cmyk properly so we resort to this for debugging */
56 #define HT_RAW_DUMP
57 
58 /* Define SHORTSTOP_MEMCPY_ETC to enable braindead implementations of memcpy
59  * and memset etc in this file. This serves to help profiling on some
60  * systems, though it should be noted that our implementations here are NOT
61  * anywhere near as efficient as typical C libraries ones. */
62 #undef SHORTSTOP_MEMCPY_ETC
63 
64 #ifdef SHORTSTOP_MEMCPY_ETC
65 
memset(void * s_,int c,size_t n)66 void *memset(void *s_, int c, size_t n)
67 {
68   byte *s = (byte *)s_;
69   while (n--)
70     *s++ = (unsigned char)c;
71   return s;
72 }
73 
__aebi_memset8(void * dest,size_t n,int c)74 void __aebi_memset8(void *dest, size_t n, int c)
75 {
76   memset(dest, c,n);
77 }
__aebi_memset4(void * dest,size_t n,int c)78 void __aebi_memset4(void *dest, size_t n, int c)
79 {
80   memset(dest, c,n);
81 }
__aebi_memset(void * dest,size_t n,int c)82 void __aebi_memset(void *dest, size_t n, int c)
83 {
84   memset(dest, c,n);
85 }
86 
__aebi_memclr8(void * dest,size_t n)87 void __aebi_memclr8(void *dest, size_t n)
88 {
89   memset(dest, 0,n);
90 }
__aebi_memclr4(void * dest,size_t n)91 void __aebi_memclr4(void *dest, size_t n)
92 {
93   memset(dest, 0,n);
94 }
__aebi_memclr(void * dest,size_t n)95 void __aebi_memclr(void *dest, size_t n)
96 {
97   memset(dest, 0,n);
98 }
99 
memcpy(void * s_,const void * t_,size_t n)100 void *memcpy(void *s_, const void *t_, size_t n)
101 {
102   byte *s = (byte *)s_;
103   const byte *t = (const byte *)t_;
104   while (n--)
105     *s++ = *t++;
106   return s;
107 }
108 
__aebi_memcpy8(void * dest,const void * src,size_t n)109 void __aebi_memcpy8(void *dest, const void *src, size_t n)
110 {
111   memcpy(dest, src,n);
112 }
__aebi_memcpy4(void * dest,const void * src,size_t n)113 void __aebi_memcpy4(void *dest, const void *src, size_t n)
114 {
115   memcpy(dest, src,n);
116 }
__aebi_memcpy(void * dest,const void * src,size_t n)117 void __aebi_memcpy(void *dest, const void *src, size_t n)
118 {
119   memcpy(dest, src,n);
120 }
121 
memmove(void * s_,const void * t_,size_t n)122 void *memmove(void *s_, const void *t_, size_t n)
123 {
124   byte *s = (byte *)s_;
125   const byte *t = (const byte *)t_;
126 
127   if (s < t) {
128     while (n--)
129       *s++ = *t++;
130   } else {
131     s += n;
132     t += n;
133     while (n--)
134       *--s = *--t;
135   }
136   return s;
137 }
138 
__aebi_memmove8(void * dest,const void * src,size_t n)139 void __aebi_memmove8(void *dest, const void *src, size_t n)
140 {
141   memmove(dest, src,n);
142 }
__aebi_memcmove4(void * dest,const void * src,size_t n)143 void __aebi_memcmove4(void *dest, const void *src, size_t n)
144 {
145   memmove(dest, src,n);
146 }
__aebi_memmove(void * dest,const void * src,size_t n)147 void __aebi_memmove(void *dest, const void *src, size_t n)
148 {
149   memmove(dest, src,n);
150 }
151 
152 #endif
153 
154 #ifdef  TESTING_WITH_NO_BAND_DONOR
155 
156 #if !defined(__FreeBSD__) && !defined(__DragonFly__)
157 #include <malloc.h>
158 #else
159 #include <stdlib.h>
160 #endif
161 
162 static void *my_buffer;
163 
gs_band_donor_init(void ** opaque,gs_memory_t * mem)164 int gs_band_donor_init(void        **opaque,
165                        gs_memory_t  *mem)
166 {
167 #ifdef DEBUG_PRINT
168     eprintf("gs_band_donor_init\n");
169 #endif
170     *opaque = NULL;
171     return 0;
172 }
173 
gs_band_donor_band_get(void * opaque,uint uWidth,uint uHeight,uint uBitDepth,uint uComponents,uint uStride,uint uBandHeight)174 void *gs_band_donor_band_get(void *opaque,
175                              uint  uWidth,
176                              uint  uHeight,
177                              uint  uBitDepth,
178                              uint  uComponents,
179                              uint  uStride,
180                              uint  uBandHeight)
181 {
182 #ifdef DEBUG_PRINT
183     eprintf6("gs_band_donor_band_get[%dx%dx%dx%d (stride=%d bandHeight=%d)]\n",
184              uWidth, uHeight, uBitDepth, uComponents, uStride, uBandHeight);
185 #endif
186     my_buffer = (void *)malloc(uStride * uComponents * uBandHeight);
187 
188 #ifdef DEBUG_PRINT
189     q = my_buffer;
190     for (y = uBandHeight; y > 0; y--) {
191         for (p = 0; p < uComponents; p++) {
192             memset(q, 0x10+p, uStride);
193             q += uStride;
194         }
195     }
196 #endif
197     return my_buffer;
198 }
199 
gs_band_donor_band_full(void * opaque,uint nLines)200 int gs_band_donor_band_full(void *opaque, uint nLines)
201 {
202 #ifdef DEBUG_PRINT
203     eprintf1("gs_band_donor_band_full[%d]\n", nLines);
204 #endif
205     return 0;
206 }
207 
gs_band_donor_band_release(void * opaque)208 int gs_band_donor_band_release(void *opaque)
209 {
210 #ifdef DEBUG_PRINT
211     eprintf("gs_band_donor_band_release\n");
212 #endif
213     free(my_buffer);
214     my_buffer = NULL;
215     return 0;
216 }
217 
gs_band_donor_fin(void * opaque)218 void gs_band_donor_fin(void *opaque)
219 {
220 #ifdef DEBUG_PRINT
221     eprintf("gs_band_donor_fin\n");
222 #endif
223 }
224 #endif
225 
226 /* Sanit requires us to work in bands of at least 200 lines */
227 #define MINBANDHEIGHT 200
228 
229 /* Structure for plib devices, which extend the generic printer device. */
230 
231 struct gx_device_plib_s {
232     gx_device_common;
233     gx_prn_device_common;
234     /* Additional state for plib device */
235     void *opaque;
236 };
237 typedef struct gx_device_plib_s gx_device_plib;
238 
239 /* ------ The device descriptors ------ */
240 
241 /*
242  * Default X and Y resolution.
243  */
244 #define X_DPI 600
245 #define Y_DPI 600
246 
247 /* For all but mono, we need our own color mapping and alpha procedures. */
248 static dev_proc_decode_color(plib_decode_color);
249 static dev_proc_encode_color(plibg_encode_color);
250 static dev_proc_decode_color(plibg_decode_color);
251 static dev_proc_decode_color(plibc_decode_color);
252 static dev_proc_encode_color(plibc_encode_color);
253 static dev_proc_map_color_rgb(plibc_map_color_rgb);
254 
255 static dev_proc_open_device(plib_open);
256 static dev_proc_close_device(plib_close);
257 
258 static dev_proc_get_params(plib_get_params);
259 static dev_proc_put_params(plib_put_params);
260 
261 static  dev_proc_dev_spec_op(plib_dev_spec_op);
262 
263 /* And of course we need our own print-page routines. */
264 static dev_proc_print_page(plib_print_page);
265 
266 static int plib_print_page(gx_device_printer * pdev, FILE * pstream);
267 static int plibm_print_page(gx_device_printer * pdev, FILE * pstream);
268 static int plibg_print_page(gx_device_printer * pdev, FILE * pstream);
269 static int plibc_print_page(gx_device_printer * pdev, FILE * pstream);
270 static int plibk_print_page(gx_device_printer * pdev, FILE * pstream);
271 
272 /* The device procedures */
273 
274 /* See gdevprn.h for the template for the following. */
275 #define pgpm_procs(p_color_rgb, p_encode_color, p_decode_color) {\
276         plib_open,\
277         NULL, /* get_initial_matrix */ \
278         NULL, /* sync output */ \
279         gdev_prn_output_page, \
280         plib_close,\
281         NULL, /* map_rgb_color */ \
282         p_color_rgb, /* map_color_rgb */ \
283         NULL, /* fill_rectangle */ \
284         NULL, /* tile_rectangle */ \
285         NULL, /* copy_mono */ \
286         NULL, /* copy_color */ \
287         NULL, /* draw_line */ \
288         NULL, /* get_bits */ \
289         gdev_prn_get_params, \
290         plib_put_params,\
291         NULL, /* map_cmyk_color */ \
292         NULL, /* get_xfont_procs */ \
293         NULL, /* get_xfont_device */ \
294         NULL, /* map_rgb_alpha_color */ \
295         gx_page_device_get_page_device, \
296         NULL,   /* get_alpha_bits */\
297         NULL,   /* copy_alpha */\
298         NULL,   /* get_band */\
299         NULL,   /* copy_rop */\
300         NULL,   /* fill_path */\
301         NULL,   /* stroke_path */\
302         NULL,   /* fill_mask */\
303         NULL,   /* fill_trapezoid */\
304         NULL,   /* fill_parallelogram */\
305         NULL,   /* fill_triangle */\
306         NULL,   /* draw_thin_line */\
307         NULL,   /* begin_image */\
308         NULL,   /* image_data */\
309         NULL,   /* end_image */\
310         NULL,   /* strip_tile_rectangle */\
311         NULL,   /* strip_copy_rop */\
312         NULL,   /* get_clipping_box */\
313         NULL,   /* begin_typed_image */\
314         NULL,   /* get_bits_rectangle */\
315         NULL,   /* map_color_rgb_alpha */\
316         NULL,   /* create_compositor */\
317         NULL,   /* get_hardware_params */\
318         NULL,   /* text_begin */\
319         NULL,   /* finish_copydevice */\
320         NULL,   /* begin_transparency_group */\
321         NULL,   /* end_transparency_group */\
322         NULL,   /* begin_transparency_mask */\
323         NULL,   /* end_transparency_mask */\
324         NULL,   /* discard_transparency_layer */\
325         NULL,   /* get_color_mapping_procs */\
326         NULL,   /* get_color_comp_index */\
327         p_encode_color, /* encode_color */\
328         p_decode_color, /* decode_color */\
329         NULL,   /* pattern_manage */\
330         NULL,   /* fill_rectangle_hl_color */\
331         NULL,   /* include_color_space */\
332         NULL,   /* fill_linear_color_scanline */\
333         NULL,   /* fill_linear_color_trapezoid */\
334         NULL,   /* fill_linear_color_triangle */\
335         NULL,	/* update spot */\
336         NULL,   /* DevN params */\
337         NULL,   /* fill page */\
338         NULL,   /* push_transparency_state */\
339         NULL,   /* pop_transparency_state */\
340         NULL,   /* put_image */\
341         NULL    /* dev_spec_op */\
342 }
343 
344 static const gx_device_procs plibm_procs =
345   pgpm_procs(NULL, gdev_prn_map_rgb_color, gdev_prn_map_color_rgb);
346 static const gx_device_procs plibg_procs =
347   pgpm_procs(NULL, plibg_encode_color, plibg_decode_color);
348 static const gx_device_procs plib_procs =
349   pgpm_procs(NULL, gx_default_rgb_map_rgb_color, plib_decode_color);
350 static const gx_device_procs plibc_procs =
351   pgpm_procs(plibc_map_color_rgb, plibc_encode_color, plibc_decode_color);
352 static const gx_device_procs plibk_procs =
353   pgpm_procs(plibc_map_color_rgb, plibc_encode_color, plibc_decode_color);
354 
355 /* Macro for generating device descriptors. */
356 /* Ideally we'd use something like:
357  * #define plib_prn_device(procs, dev_name, num_comp, depth, max_gray, max_rgb, print_page) \
358  * {       prn_device_body(gx_device_plib, procs, dev_name,\
359  *          DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI,\
360  *          0, 0, 0, 0,\
361  *          num_comp, depth, max_gray, max_rgb, max_gray + 1, max_rgb + 1,\
362  *          print_page)\
363  * }
364  * But that doesn't let us override the band space params. So we have to do
365  * it the large way.
366  */
367 #define plib_prn_device(procs, dev_name, num_comp, depth, max_gray, max_rgb, print_page) \
368 {       std_device_full_body_type(gx_device_plib, &procs, dev_name, &st_device_printer,\
369           (int)((float)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10 + 0.5),\
370           (int)((float)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10 + 0.5),\
371           X_DPI, Y_DPI,\
372           num_comp, depth, max_gray, max_rgb, max_gray + 1, max_rgb + 1,\
373           (float)(0), (float)(0),\
374           (float)(0), (float)(0),\
375           (float)(0), (float)(0)\
376         ),\
377          { 0 },         /* std_procs */\
378          { 0 },         /* skip */\
379          { print_page,\
380            gx_default_print_page_copies,\
381            { gx_default_create_buf_device,\
382              gx_default_size_buf_device,\
383              gx_default_setup_buf_device,\
384              gx_default_destroy_buf_device\
385            },\
386            gdev_prn_default_get_space_params,\
387            gx_default_start_render_thread,\
388            gx_default_open_render_device,\
389            gx_default_close_render_device,\
390            gx_default_buffer_page\
391          },\
392          { PRN_MAX_BITMAP, PRN_BUFFER_SPACE,\
393              { 0, /* page_uses_transparency */\
394                0, /* Bandwidth */\
395                MINBANDHEIGHT, /* BandHeight */\
396                0 /* BandBufferSpace */},\
397            0/*false*/,  /* params_are_read_only */\
398            BandingAlways        /* banding_type */\
399          },\
400          { 0 },         /* fname */\
401         0/*false*/,     /* OpenOutputFile */\
402         0/*false*/,     /* ReopenPerPage */\
403         0/*false*/,     /* page_uses_transparency */\
404         0/*false*/, -1, /* Duplex[_set] */\
405         0/*false*/, 0, 0, 0, /* file_is_new ... buf */\
406         0, 0, 0, 0, 0/*false*/, 0, 0, /* buffer_memory ... clist_dis'_mask */\
407         0,              /* num_render_threads_requested */\
408         { 0 },  /* save_procs_while_delaying_erasepage */\
409         { 0 }   /* ... orig_procs */}
410 
411 /* The device descriptors themselves */
412 const gx_device_plib gs_plib_device =
413   plib_prn_device(plib_procs, "plib", 3, 24, 255, 255, plib_print_page);
414 const gx_device_plib gs_plibg_device =
415   plib_prn_device(plibg_procs, "plibg", 1, 8, 255, 0, plibg_print_page);
416 const gx_device_plib gs_plibm_device =
417   plib_prn_device(plibm_procs, "plibm", 1, 1, 1, 0, plibm_print_page);
418 const gx_device_plib gs_plibk_device =
419   plib_prn_device(plibk_procs, "plibk", 4, 4, 1, 1, plibk_print_page);
420 const gx_device_plib gs_plibc_device =
421   plib_prn_device(plibc_procs, "plibc", 4, 32, 255, 255, plibc_print_page);
422 
423 /* ------ Initialization ------ */
424 
425 /*
426  * We need to create custom memory buffer devices that just point into the
427  * bandBuffer we've got from the digicolor system.
428  */
429 static byte *bandBufferBase = NULL;
430 static int   bandBufferStride = 0;
431 
432 #ifdef DEBUG_DUMP
433 static int dump_w;
434 static int dump_nc;
435 static int dump_l2bits;
436 
dump_start(int w,int h,int num_comps,int log2bits,FILE * dump_file)437 static void dump_start(int w, int h, int num_comps, int log2bits,
438                        FILE *dump_file)
439 {
440     if ((num_comps == 3) && (log2bits == 3)) {
441         /* OK */
442     } else if ((num_comps == 1) && (log2bits == 0)) {
443         /* OK */
444     } else if ((num_comps == 1) && (log2bits == 3)) {
445         /* OK */
446     } else if ((num_comps == 4) && (log2bits == 0)) {
447         /* OK */
448     } else if ((num_comps == 4) && (log2bits == 3)) {
449         /* OK */
450     } else
451         return;
452     dump_nc = num_comps;
453     dump_l2bits = log2bits;
454     if (dump_file == NULL)
455         return;
456     if (dump_nc == 3)
457         fprintf(dump_file, "P6 %d %d 255\n", w, h);
458     else if (dump_nc == 4) {
459         if (log2bits == 0)
460             fprintf(dump_file, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\n"
461                     "MAXVAL 255\nTUPLTYPE CMYK\nENDHDR\n", w, h);
462         else
463             fprintf(dump_file, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\n"
464                     "MAXVAL 255\nTUPLTYPE CMYK\nENDHDR\n", w, h);
465     } else if (log2bits == 0)
466         fprintf(dump_file, "P4 %d %d\n", w, h);
467     else
468         fprintf(dump_file, "P5 %d %d 255\n", w, h);
469     dump_w = w;
470 }
471 
dump_band(int y,FILE * dump_file)472 static void dump_band(int y, FILE *dump_file)
473 {
474     byte *r = bandBufferBase;
475     byte *g = r + bandBufferStride;
476     byte *b = g + bandBufferStride;
477     byte *k = b + bandBufferStride;
478 
479     if (dump_file == NULL)
480         return;
481     if (dump_nc == 3) {
482          while (y--) {
483             int w = dump_w;
484             while (w--) {
485                 fputc(*r++, dump_file);
486                 fputc(*g++, dump_file);
487                 fputc(*b++, dump_file);
488             }
489             r += bandBufferStride*3-dump_w;
490             g += bandBufferStride*3-dump_w;
491             b += bandBufferStride*3-dump_w;
492         }
493     } else if (dump_nc == 4) {
494         if (dump_l2bits == 0) {
495             while (y--) {
496                 int w = dump_w;
497                 while (w) {
498                     byte C = *r++;
499                     byte M = *g++;
500                     byte Y = *b++;
501                     byte K = *k++;
502                     int s;
503                     for (s=7; s>=0; s--) {
504                         fputc(255*((C>>s)&1), dump_file);
505                         fputc(255*((M>>s)&1), dump_file);
506                         fputc(255*((Y>>s)&1), dump_file);
507                         fputc(255*((K>>s)&1), dump_file);
508                         w--;
509                         if (w == 0) break;
510                     }
511                 }
512                 r += bandBufferStride*4-((dump_w+7)>>3);
513                 g += bandBufferStride*4-((dump_w+7)>>3);
514                 b += bandBufferStride*4-((dump_w+7)>>3);
515                 k += bandBufferStride*4-((dump_w+7)>>3);
516             }
517         } else {
518             while (y--) {
519                 int w = dump_w;
520                 while (w--) {
521                     fputc(*r++, dump_file);
522                     fputc(*g++, dump_file);
523                     fputc(*b++, dump_file);
524                     fputc(*k++, dump_file);
525                 }
526                 r += bandBufferStride*4-dump_w;
527                 g += bandBufferStride*4-dump_w;
528                 b += bandBufferStride*4-dump_w;
529                 k += bandBufferStride*4-dump_w;
530             }
531         }
532     } else {
533         if (dump_l2bits == 0) {
534             while (y--) {
535                 int w = (dump_w+7)>>3;
536                 while (w--) {
537                     fputc(*r++, dump_file);
538                 }
539                 r += bandBufferStride - ((dump_w+7)>>3);
540             }
541         } else {
542             while (y--) {
543                 int w = dump_w;
544                 while (w--) {
545                     fputc(*r++, dump_file);
546                 }
547                 r += bandBufferStride - dump_w;
548             }
549         }
550     }
551 }
552 #endif
553 
554 int
plib_put_params(gx_device * pdev,gs_param_list * plist)555 plib_put_params(gx_device * pdev, gs_param_list * plist)
556 {
557     int ecode = 0;
558     int code;
559     gx_device_printer * const ppdev = (gx_device_printer *)pdev;
560 
561     /* Assumed to be valid on entry - remember it */
562     int bandHeight = ppdev->space_params.band.BandHeight;
563 
564     code = gdev_prn_put_params(pdev, plist);
565     if (ppdev->space_params.band.BandHeight < MINBANDHEIGHT)
566     {
567         eprintf1("Must have a BandHeight of at least %d\n", MINBANDHEIGHT);
568 
569         ecode = gs_error_rangecheck;
570 
571         /* Restore to our valid value */
572         ppdev->space_params.band.BandHeight = bandHeight;
573     }
574     if (ecode >= 0)
575         ecode = code;
576     return ecode;
577 }
578 
579 /*
580  * Set up the scan line pointers of a memory device.
581  * See gxdevmem.h for the detailed specification.
582  * Sets or uses line_ptrs, base, raster; uses width, color_info.depth,
583  * num_planes, plane_depths, plane_depth.
584  */
585 static int
set_line_ptrs(gx_device_memory * mdev,byte * base,int raster,byte ** line_ptrs,int setup_height)586 set_line_ptrs(gx_device_memory * mdev, byte * base, int raster,
587               byte **line_ptrs, int setup_height)
588 {
589     int num_planes = mdev->num_planes;
590     gx_render_plane_t plane1;
591     const gx_render_plane_t *planes;
592     int pi;
593 
594     if (num_planes) {
595         if (base && !mdev->plane_depth)
596             return_error(gs_error_rangecheck);
597         planes = mdev->planes;
598     } else {
599         planes = &plane1;
600         plane1.depth = mdev->color_info.depth;
601         num_planes = 1;
602     }
603 
604     for (pi = 0; pi < num_planes; ++pi) {
605         byte **pend = line_ptrs + setup_height;
606         byte *scan_line = base;
607 
608         while (line_ptrs < pend) {
609             *line_ptrs++ = scan_line;
610             scan_line += raster * num_planes;
611         }
612         base += raster;
613     }
614 
615     return 0;
616 }
617 
618 static int
plib_setup_buf_device(gx_device * bdev,byte * buffer,int bytes_per_line,byte ** line_ptrs,int y,int setup_height,int full_height)619 plib_setup_buf_device(gx_device *bdev, byte *buffer, int bytes_per_line,
620                         byte **line_ptrs, int y, int setup_height,
621                         int full_height)
622 {
623     gx_device_memory *mdev = (gx_device_memory *)bdev;
624     int code;
625 
626     /* buffer is the buffer used by clist writing. We could use that as the
627      * page buffer, but we'd rather use the buffer given to us by the
628      * digicolor code. b */
629 
630     if (line_ptrs == NULL) {
631         /* Free any existing line pointers array */
632         if (mdev->line_ptrs != NULL)
633             gs_free_object(mdev->line_pointer_memory, mdev->line_ptrs,
634                        "mem_close");
635         /*
636          * Allocate line pointers now; free them when we close the device.
637          * Note that for multi-planar devices, we have to allocate using
638          * full_height rather than setup_height.
639          */
640         line_ptrs = (byte **)
641             gs_alloc_byte_array(mdev->memory,
642                                 (mdev->num_planes ?
643                                  full_height * mdev->num_planes :
644                                  setup_height),
645                                 sizeof(byte *), "setup_buf_device");
646         if (line_ptrs == 0)
647             return_error(gs_error_VMerror);
648         mdev->line_pointer_memory = mdev->memory;
649         mdev->foreign_line_pointers = false;
650         mdev->line_ptrs = line_ptrs;
651         mdev->raster = bandBufferStride * mdev->num_planes;
652     }
653     mdev->height = full_height;
654     code = set_line_ptrs(mdev,
655                          bandBufferBase + bandBufferStride*mdev->num_planes*y,
656                          bandBufferStride,
657                          line_ptrs,
658                          setup_height);
659     mdev->height = setup_height;
660     bdev->height = setup_height; /* do here in case mdev == bdev */
661     return code;
662 }
663 
664 static int
plib_get_bits_rectangle_mem(gx_device * pdev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** pprect)665 plib_get_bits_rectangle_mem(gx_device *pdev, const gs_int_rect *prect,
666                             gs_get_bits_params_t *params, gs_int_rect **pprect)
667 {
668     gx_device_memory *mdev = (gx_device_memory *)pdev;
669     int x = prect->p.x, w = prect->q.x - x, y = prect->p.y, h = prect->q.y - y;
670     /* First off, see if we can satisfy get_bits_rectangle with just returning
671      * pointers to the existing data. */
672     {
673         gs_get_bits_params_t copy_params;
674         byte **base = &scan_line_base(mdev, y);
675         int code;
676 
677         copy_params.options =
678             GB_COLORS_NATIVE | GB_PACKING_PLANAR | GB_ALPHA_NONE |
679             (mdev->raster ==
680              bitmap_raster(mdev->width * mdev->color_info.depth) ?
681              GB_RASTER_STANDARD : GB_RASTER_SPECIFIED);
682         copy_params.raster = mdev->raster;
683         code = gx_get_bits_return_pointer(pdev, x, h, params,
684                                           &copy_params, base);
685         if (code >= 0)
686             return code;
687     }
688     return mem_get_bits_rectangle(pdev, prect, params, pprect);
689 }
690 
691 static int
plib_create_buf_device(gx_device ** pbdev,gx_device * target,int y,const gx_render_plane_t * render_plane,gs_memory_t * mem,gx_band_complexity_t * band_complexity)692 plib_create_buf_device(gx_device **pbdev, gx_device *target, int y,
693    const gx_render_plane_t *render_plane, gs_memory_t *mem,
694    gx_band_complexity_t *band_complexity)
695 {
696     int code = gdev_prn_create_buf_planar(pbdev, target, y, render_plane,
697                                           mem, band_complexity);
698     if (code < 0)
699         return code;
700     if ((*pbdev)->procs.get_bits_rectangle == mem_get_bits_rectangle)
701         (*pbdev)->procs.get_bits_rectangle = plib_get_bits_rectangle_mem;
702     return 0;
703 }
704 
705 static int
plib_size_buf_device(gx_device_buf_space_t * space,gx_device * target,const gx_render_plane_t * render_plane,int height,bool for_band)706 plib_size_buf_device(gx_device_buf_space_t *space, gx_device *target,
707                        const gx_render_plane_t *render_plane,
708                        int height, bool for_band)
709 {
710     return gdev_prn_size_buf_planar(space, target, render_plane,
711                                     height, for_band);
712 }
713 
714 /*
715  * Define a special open procedure that changes create_buf_device to use
716  * a planar device.
717  */
718 static int
plib_open(gx_device * pdev)719 plib_open(gx_device * pdev)
720 {
721     gx_device_plib * const bdev = (gx_device_plib *)pdev;
722     int code;
723 
724 #ifdef DEBUG_PRINT
725     eprintf("plib_open\n");
726 #endif
727     bdev->printer_procs.buf_procs.create_buf_device = plib_create_buf_device;
728     bdev->printer_procs.buf_procs.setup_buf_device = plib_setup_buf_device;
729     bdev->printer_procs.buf_procs.size_buf_device = plib_size_buf_device;
730 
731     /* You might expect us to call gdev_prn_open_planar rather than
732      * gdev_prn_open, but if we do that, it overwrites the 2 function
733      * pointers we've just overwritten! */
734     code = gdev_prn_open(pdev);
735     if (code < 0)
736         return code;
737     pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
738     set_linear_color_bits_mask_shift(pdev);
739 
740     /* Start the actual job. */
741 #ifdef DEBUG_PRINT
742     eprintf("calling job_begin\n");
743 #endif
744     code = gs_band_donor_init(&bdev->opaque, pdev->memory);
745 #ifdef DEBUG_PRINT
746     eprintf("called\n");
747 #endif
748 
749     return code;
750 }
751 
752 static int
plib_close(gx_device * pdev)753 plib_close(gx_device *pdev)
754 {
755     gx_device_plib *pldev = (gx_device_plib *)pdev;
756 
757 #ifdef DEBUG_PRINT
758     eprintf("plib_close\n");
759 #endif
760     gs_band_donor_fin(pldev->opaque);
761     pldev->opaque = NULL;
762 
763     return gdev_prn_close(pdev);
764 }
765 
766 /* ------ Color mapping routines ------ */
767 
768 /* Map an RGB color to a gray value. */
769 static gx_color_index
plibg_encode_color(gx_device * pdev,const gx_color_value cv[])770 plibg_encode_color(gx_device * pdev, const gx_color_value cv[])
771 {                               /* We round the value rather than truncating it. */
772     gx_color_value gray;
773     gx_color_value r, g, b;
774 
775     r = cv[0]; g = cv[0]; b = cv[0];
776     gray = ((r * (ulong) lum_red_weight) +
777      (g * (ulong) lum_green_weight) +
778      (b * (ulong) lum_blue_weight) +
779      (lum_all_weights / 2)) / lum_all_weights
780     * pdev->color_info.max_gray / gx_max_color_value;
781 
782     return gray;
783 }
784 
785 /* Map a gray value back to an RGB color. */
786 static int
plibg_decode_color(gx_device * dev,gx_color_index color,gx_color_value prgb[3])787 plibg_decode_color(gx_device * dev, gx_color_index color,
788                    gx_color_value prgb[3])
789 {
790     gx_color_value gray =
791     color * gx_max_color_value / dev->color_info.max_gray;
792 
793     prgb[0] = gray;
794     prgb[1] = gray;
795     prgb[2] = gray;
796     return 0;
797 }
798 
799 /* Map an rgb color tuple back to an RGB color. */
800 static int
plib_decode_color(gx_device * dev,gx_color_index color,gx_color_value prgb[3])801 plib_decode_color(gx_device * dev, gx_color_index color,
802                   gx_color_value prgb[3])
803 {
804     uint bitspercolor = dev->color_info.depth / 3;
805     uint colormask = (1 << bitspercolor) - 1;
806     uint max_rgb = dev->color_info.max_color;
807 
808     prgb[0] = ((color >> (bitspercolor * 2)) & colormask) *
809         (ulong) gx_max_color_value / max_rgb;
810     prgb[1] = ((color >> bitspercolor) & colormask) *
811         (ulong) gx_max_color_value / max_rgb;
812     prgb[2] = (color & colormask) *
813         (ulong) gx_max_color_value / max_rgb;
814     return 0;
815 }
816 
817 /* Map a cmyk color tuple back to CMYK colorants. */
818 static int
plibc_decode_color(gx_device * dev,gx_color_index color,gx_color_value prgb[4])819 plibc_decode_color(gx_device * dev, gx_color_index color,
820                    gx_color_value prgb[4])
821 {
822     uint bitspercolor = dev->color_info.depth / 4;
823     uint colormask = (1 << bitspercolor) - 1;
824     uint max_cmyk = dev->color_info.max_color;
825     uint c, m, y, k;
826 
827 #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / colormask))
828 
829     k = color & colormask;
830     color >>= bitspercolor;
831     y = color & colormask;
832     color >>= bitspercolor;
833     m = color & colormask;
834     c = color >> bitspercolor;
835     prgb[0] = cvalue(c);
836     prgb[1] = cvalue(m);
837     prgb[2] = cvalue(y);
838     prgb[3] = cvalue(k);
839     return 0;
840 }
841 
842 /* Map CMYK to color. */
843 static gx_color_index
plibc_encode_color(gx_device * dev,const gx_color_value cv[])844 plibc_encode_color(gx_device * dev, const gx_color_value cv[])
845 {
846     int bpc = dev->color_info.depth / 4;
847     gx_color_index color;
848     COLROUND_VARS;
849 
850     COLROUND_SETUP(bpc);
851     color = ((((((COLROUND_ROUND(cv[0]) << bpc) +
852                  COLROUND_ROUND(cv[1])) << bpc) +
853                COLROUND_ROUND(cv[2])) << bpc) +
854              COLROUND_ROUND(cv[3]));
855 
856     /* The bitcmyk device does this:
857      * return (color == gx_no_color_index ? color ^ 1 : color);
858      * But I don't understand why.
859      */
860     return color;
861 }
862 
863 /* Map a cmyk color back to an rgb tuple. */
864 static int
plibc_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])865 plibc_map_color_rgb(gx_device * dev, gx_color_index color,
866                     gx_color_value prgb[3])
867 {
868     uint bitspercolor = dev->color_info.depth / 4;
869     uint colormask = (1 << bitspercolor) - 1;
870     uint max_cmyk = dev->color_info.max_color;
871     uint c, m, y, k;
872 
873 #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / colormask))
874 
875     k = color & colormask;
876     color >>= bitspercolor;
877     y = color & colormask;
878     color >>= bitspercolor;
879     m = color & colormask;
880     c = color >> bitspercolor;
881     k = colormask - k;
882     prgb[0] = cvalue((colormask - c) * k / colormask);
883     prgb[1] = cvalue((colormask - m) * k / colormask);
884     prgb[2] = cvalue((colormask - y) * k / colormask);
885     return 0;
886 }
887 
888 /* ------ Internal routines ------ */
889 
890 /* Print a page using a given row printing routine. */
891 static int
plib_print_page_loop(gx_device_printer * pdev,int log2bits,int numComps,FILE * pstream)892 plib_print_page_loop(gx_device_printer * pdev, int log2bits, int numComps,
893                      FILE *pstream)
894 {
895     gx_device_plib *pldev = (gx_device_plib *)pdev;
896     int lnum;
897     int code = 0;
898     byte *buffer;
899     int stride = bitmap_raster(pdev->width * (1<<log2bits));
900     int bandHeight = pdev->space_params.band.BandHeight;
901 
902 #ifdef DEBUG_PRINT
903     eprintf("Calling page_begin\n");
904 #endif
905     buffer = gs_band_donor_band_get(pldev->opaque,
906                                     pdev->width,
907                                     pdev->height,
908                                     1<<log2bits,
909                                     numComps,
910                                     stride,
911                                     bandHeight);
912 #ifdef DEBUG_PRINT
913     eprintf1("Called page_begin %x\n", buffer);
914 #endif
915     if (buffer == NULL)
916         return_error(gs_error_VMerror);
917 
918     /* Write these into the globals here so the setup_buf_device code can
919      * find it later. Nasty. */
920     bandBufferBase = buffer;
921     bandBufferStride = stride;
922 
923 #ifdef DEBUG_DUMP
924     dump_start(pdev->width, pdev->height, numComps, log2bits, pstream);
925 #endif
926     for (lnum = 0; lnum < pdev->height; lnum += bandHeight) {
927         gs_int_rect *unread, rect;
928         gs_get_bits_params_t params;
929 
930         rect.p.x = 0;
931         rect.p.y = lnum;
932         rect.q.x = pdev->width;
933         rect.q.y = lnum+bandHeight;
934         if (rect.q.y > pdev->height)
935                 rect.q.y = pdev->height;
936         memset(&params, 0, sizeof(params));
937         params.options = GB_ALIGN_ANY |
938                          GB_RETURN_POINTER |
939                          GB_OFFSET_0 |
940                          GB_RASTER_STANDARD |
941                          GB_PACKING_PLANAR |
942                          GB_COLORS_NATIVE |
943                          GB_ALPHA_NONE;
944         params.x_offset = 0;
945         code = (*dev_proc(pdev, get_bits_rectangle))((gx_device *)pdev, &rect, &params,&unread);
946         if (code < 0)
947             break;
948 #ifdef DEBUG_DUMP
949         dump_band(rect.q.y-rect.p.y, pstream);
950 #endif
951 #ifdef DEBUG_PRINT
952         eprintf3("Calling band_full (%d->%d) of %d\n", rect.p.y, rect.q.y,
953                  pdev->height);
954 #endif
955         gs_band_donor_band_full(pldev->opaque, rect.q.y-rect.p.y);
956 #ifdef DEBUG_PRINT
957         eprintf("Called band_full\n");
958 #endif
959     }
960 #ifdef DEBUG_PRINT
961     eprintf("Calling band_release\n");
962 #endif
963     gs_band_donor_band_release(pldev->opaque);
964 #ifdef DEBUG_PRINT
965     eprintf("Called band_release\n");
966 #endif
967     return (code < 0 ? code : 0);
968 }
969 
970 /* ------ Individual page printing routines ------ */
971 
972 /* Print a monobit page. */
973 static int
plibm_print_page(gx_device_printer * pdev,FILE * pstream)974 plibm_print_page(gx_device_printer * pdev, FILE * pstream)
975 {
976 #ifdef DEBUG_PRINT
977     eprintf("plibm_print_page\n");
978 #endif
979     return plib_print_page_loop(pdev, 0, 1, pstream);
980 }
981 
982 /* Print a gray-mapped page. */
983 static int
plibg_print_page(gx_device_printer * pdev,FILE * pstream)984 plibg_print_page(gx_device_printer * pdev, FILE * pstream)
985 {
986 #ifdef DEBUG_PRINT
987     eprintf("plibg_print_page\n");
988 #endif
989     return plib_print_page_loop(pdev, 3, 1, pstream);
990 }
991 
992 /* Print a color-mapped page. */
993 static int
plib_print_page(gx_device_printer * pdev,FILE * pstream)994 plib_print_page(gx_device_printer * pdev, FILE * pstream)
995 {
996 #ifdef DEBUG_PRINT
997     eprintf("plibc_print_page\n");
998 #endif
999     return plib_print_page_loop(pdev, 3, 3, pstream);
1000 }
1001 
1002 /* Print a 1 bit CMYK page. */
1003 static int
plibk_print_page(gx_device_printer * pdev,FILE * pstream)1004 plibk_print_page(gx_device_printer * pdev, FILE * pstream)
1005 {
1006 #ifdef DEBUG_PRINT
1007     eprintf("plibk_print_page\n");
1008 #endif
1009     return plib_print_page_loop(pdev, 0, 4, pstream);
1010 }
1011 
1012 /* Print an 8bpc CMYK page. */
1013 static int
plibc_print_page(gx_device_printer * pdev,FILE * pstream)1014 plibc_print_page(gx_device_printer * pdev, FILE * pstream)
1015 {
1016 #ifdef DEBUG_PRINT
1017     eprintf("plibc_print_page\n");
1018 #endif
1019     return plib_print_page_loop(pdev, 3, 4, pstream);
1020 }
1021