1 /* Copyright (C) 2001-2006 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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gdevppla.c 8528 2008-02-17 22:32:15Z leonardo $ */
15 /* Support for printer devices with planar buffering. */
16 #include "gdevprn.h"
17 #include "gdevmpla.h"
18 #include "gdevppla.h"
19 
20 
21 /* Set the buf_procs in a printer device to planar mode. */
22 int
gdev_prn_set_procs_planar(gx_device * dev)23 gdev_prn_set_procs_planar(gx_device *dev)
24 {
25     gx_device_printer * const pdev = (gx_device_printer *)dev;
26 
27     pdev->printer_procs.buf_procs.create_buf_device =
28 	gdev_prn_create_buf_planar;
29     pdev->printer_procs.buf_procs.size_buf_device =
30 	gdev_prn_size_buf_planar;
31     return 0;
32 }
33 
34 /* Open a printer device, conditionally setting it to be planar. */
35 int
gdev_prn_open_planar(gx_device * dev,bool upb)36 gdev_prn_open_planar(gx_device *dev, bool upb)
37 {
38     if (upb)
39 	gdev_prn_set_procs_planar(dev);
40     return gdev_prn_open(dev);
41 }
42 
43 /* Augment get/put_params to add UsePlanarBuffer. */
44 int
gdev_prn_get_params_planar(gx_device * pdev,gs_param_list * plist,bool * pupb)45 gdev_prn_get_params_planar(gx_device * pdev, gs_param_list * plist,
46 			   bool *pupb)
47 {
48     int ecode = gdev_prn_get_params(pdev, plist);
49 
50     if (ecode < 0)
51 	return ecode;
52     return param_write_bool(plist, "UsePlanarBuffer", pupb);
53 }
54 int
gdev_prn_put_params_planar(gx_device * pdev,gs_param_list * plist,bool * pupb)55 gdev_prn_put_params_planar(gx_device * pdev, gs_param_list * plist,
56 			   bool *pupb)
57 {
58     bool upb = *pupb;
59     int ecode = 0, code;
60 
61     if (pdev->color_info.num_components > 1)
62 	ecode = param_read_bool(plist, "UsePlanarBuffer", &upb);
63     code = gdev_prn_put_params(pdev, plist);
64     if (ecode >= 0)
65 	ecode = code;
66     if (ecode >= 0)
67 	*pupb = upb;
68     return ecode;
69 }
70 
71 /* Set the buffer device to planar mode. */
72 static int
gdev_prn_set_planar(gx_device_memory * mdev,const gx_device * tdev)73 gdev_prn_set_planar(gx_device_memory *mdev, const gx_device *tdev)
74 {
75     int num_comp = tdev->color_info.num_components;
76     gx_render_plane_t planes[4];
77     int depth = tdev->color_info.depth / num_comp;
78 
79     if (num_comp < 3 || num_comp > 4)
80 	return_error(gs_error_rangecheck);
81     /* Round up the depth per plane to a power of 2. */
82     while (depth & (depth - 1))
83 	--depth, depth = (depth | (depth >> 1)) + 1;
84     planes[3].depth = planes[2].depth = planes[1].depth = planes[0].depth =
85 	depth;
86     /* We want the most significant plane to come out first. */
87     planes[0].shift = depth * (num_comp - 1);
88     planes[1].shift = planes[0].shift - depth;
89     planes[2].shift = planes[1].shift - depth;
90     planes[3].shift = 0;
91     return gdev_mem_set_planar(mdev, num_comp, planes);
92 }
93 
94 /* Create a planar buffer device. */
95 int
gdev_prn_create_buf_planar(gx_device ** pbdev,gx_device * target,int y,const gx_render_plane_t * render_plane,gs_memory_t * mem,gx_band_complexity_t * for_band)96 gdev_prn_create_buf_planar(gx_device **pbdev, gx_device *target, int y,
97 			   const gx_render_plane_t *render_plane,
98 			   gs_memory_t *mem, gx_band_complexity_t *for_band)
99 {
100     int code = gx_default_create_buf_device(pbdev, target, y, render_plane, mem,
101 					    for_band);
102 
103     if (code < 0)
104 	return code;
105     if (gs_device_is_memory(*pbdev) /* == render_plane->index < 0 */) {
106 	code = gdev_prn_set_planar((gx_device_memory *)*pbdev, *pbdev);
107     }
108     return code;
109 }
110 
111 /* Determine the space needed by a planar buffer device. */
112 int
gdev_prn_size_buf_planar(gx_device_buf_space_t * space,gx_device * target,const gx_render_plane_t * render_plane,int height,bool for_band)113 gdev_prn_size_buf_planar(gx_device_buf_space_t *space, gx_device *target,
114 			 const gx_render_plane_t *render_plane,
115 			 int height, bool for_band)
116 {
117     gx_device_memory mdev;
118 
119     if (render_plane && render_plane->index >= 0)
120 	return gx_default_size_buf_device(space, target, render_plane,
121 					  height, for_band);
122     mdev.color_info = target->color_info;
123     gdev_prn_set_planar(&mdev, target);
124     if (gdev_mem_bits_size(&mdev, target->width, height, &(space->bits)) < 0)
125 	return_error(gs_error_VMerror);
126     space->line_ptrs = gdev_mem_line_ptrs_size(&mdev, target->width, height);
127     space->raster = bitmap_raster(target->width * mdev.planes[0].depth);
128     return 0;
129 }
130