1 /* Copyright (C) 1989, 1992, 1994, 1996 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gdevsun.c,v 1.2.6.1.2.1 2003/01/17 00:49:01 giles Exp $*/
20 /* SunView driver */
21 #include "gx.h"			/* for gx_bitmap; includes std.h */
22 
23 #include <suntool/sunview.h>
24 #include <suntool/canvas.h>
25 #include <sunwindow/cms_mono.h>
26 #include <stdio.h>
27 
28 #include "gscdefs.h"
29 #include "gsmatrix.h"			/* needed for gxdevice.h */
30 #include "gxdevice.h"
31 #include "malloc_.h"
32 
33 #ifndef DEFAULT_DPI
34 #  define DEFAULT_DPI 75		/* Sun standard monitor */
35 #endif
36 
37 #ifdef A4
38 #  define PAPER_X 8.27			/* A4 paper */
39 #  define PAPER_Y 11.69
40 #endif
41 
42 #ifndef PAPER_X
43 #  define PAPER_X 8.5			/* US letter paper */
44 #  define PAPER_Y 11
45 #endif
46 /* Procedures */
47 dev_proc_open_device(sun_open);
48 dev_proc_sync_output(sun_sync);
49 dev_proc_close_device(sun_close);
50 dev_proc_map_rgb_color(sun_map_rgb_color);
51 dev_proc_map_color_rgb(sun_map_color_rgb);
52 dev_proc_fill_rectangle(sun_fill_rectangle);
53 dev_proc_copy_mono(sun_copy_mono);
54 dev_proc_copy_color(sun_copy_color);
55 dev_proc_draw_line(sun_draw_line);
56 
57 /* The device descriptor */
58 private gx_device_procs sun_procs = {
59 	sun_open,
60 	NULL,			/* get_initial_matrix */
61 	sun_sync,
62 	NULL,			/* output_page */
63 	sun_close,
64 	sun_map_rgb_color,
65 	sun_map_color_rgb,
66 	sun_fill_rectangle,
67 	NULL,			/* tile_rectangle */
68 	sun_copy_mono,
69 	sun_copy_color,
70 	sun_draw_line
71 };
72 
73 #define CMSNAME	"GHOSTVIEW"		/* SunView colormap name */
74 
75 /* Define the SunView device */
76 typedef struct gx_device_sun {
77 	gx_device_common;
78 	Frame frame;
79 	Canvas canvas;
80 	Pixwin *pw;
81 	struct mpr_data mpr;
82 	Pixrect	pr;
83 	int truecolor;			/* use truecolor mapping */
84 	int freecols;			/* unallocated colors */
85 	byte *red, *green, *blue;	/* colormap */
86 	char cmsname[sizeof(CMSNAME)+9];/* color map name */
87 #if !arch_is_big_endian			/* need to swap bits & bytes */
88 #  define BUF_WIDTH_BYTES (((int)(8.5*DEFAULT_DPI)+15)/16*2)
89 	byte swap_buf[BUF_WIDTH_BYTES];
90 #endif
91 } gx_device_sun;
92 
93 #if !arch_is_big_endian
94 /* Define a table for reversing bit order. */
95 static byte reverse_bits[256] = {
96   0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
97   8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
98   4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
99   12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
100   2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
101   10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
102   6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
103   14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
104   1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
105   9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
106   5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
107   13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
108   3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
109   11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
110   7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
111   15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
112 };
113 #endif
114 
115 /* The instance is public. */
116 gx_device_sun far_data gs_sunview_device = {
117 	std_device_std_body(gx_device_sun, &sun_procs, "sunview",
118 	  (int)(PAPER_X*DEFAULT_DPI), (int)(PAPER_Y*DEFAULT_DPI),	/* x and y extent */
119 	  DEFAULT_DPI, DEFAULT_DPI	/* x and y density */
120 	),	/* fill in color_info later from display depth */
121 	 { 0 },			/* std_procs */
122  	0,			/* connection not initialized */
123 };
124 
125 /* Macro for casting gx_device argument */
126 #define xdev ((gx_device_sun *)dev)
127 
128 /*
129  * The macros below define the colormap configuration used on 8-bit
130  * pseudo-color displays.
131  */
132 /*
133  * The following macros define the number of bits used to represent rgb colors.
134  * The total must not exceed the display depth.
135  * Note that the RGB dimensions could have an uneven number of bits assigned
136  * to them, but that will cause dithering to not work very well, since
137  * gs assumes the dither ramp is the same for all 3 color dimensions.
138  *
139  * Setting RED_BITS to n will pre-allocate a color-cube of 2^(3n) entries.
140  * The remaining entries are allocated on demand for colors requested by
141  * sun_map_rgb_color(), until the color map is full. At that point gs will
142  * fall back onto dithering using the pre-allocated colors.
143  * As a special case, if RED_BITS = GREEN_BITS = BLUE_BITS = 0, only
144  * black and white are pre-allocated.
145  */
146 #define RED_BITS	2		/* everything depends on this one */
147 #define GREEN_BITS	RED_BITS
148 #define BLUE_BITS	RED_BITS
149 #define DEPTH		8		/* don't change this */
150 #define RGB_BITS	(RED_BITS + GREEN_BITS + BLUE_BITS)
151 /*
152  * Smallest # bits per dimension
153  */
154 #define MAX_BITS	RED_BITS
155 #if (GREEN_BITS > MAX_BITS)
156 #undef MAX_BITS
157 #define MAX_BITS	GREEN_BITS
158 #endif
159 #if (BLUE_BITS > MAX_BITS)
160 #undef MAX_BITS
161 #define MAX_BITS	BLUE_BITS
162 #endif
163 /*
164  * masks to pull out rgb components
165  */
166 #define BLUE_MASK	((1 << BLUE_BITS) - 1)
167 #define GREEN_MASK	((1 << (BLUE_BITS + GREEN_BITS)) - 1 - BLUE_MASK)
168 #define RED_MASK	((1 << (BLUE_BITS + GREEN_BITS + RED_BITS)) - 1 \
169 			 - BLUE_MASK - GREEN_MASK)
170 /*
171  * number of colors on rgb dimensions
172  */
173 #define RED_COLS	(1 << RED_BITS)
174 #define GREEN_COLS	(1 << GREEN_BITS)
175 #define BLUE_COLS	(1 << BLUE_BITS)
176 #define RGB_COLS	(RED_COLS * GREEN_COLS * BLUE_COLS)
177 #define MAX_COLS	(1 << MAX_BITS)
178 /*
179  * maximum number of colors in map
180  */
181 #define ALL_COLS	(1 << DEPTH)	/* 256 */
182 #define CMS_SIZE	ALL_COLS	/* cut down to 64 or 128 for
183 					   more cooperative behaviour */
184 
185 #if (RGB_COLS > CMS_SIZE)		/* one is reserved for the scrollbar */
186 CMS_SIZE_too_small_for_color_cube
187 #endif
188 #if (RGB_BITS < 0) || (RGB_BITS > DEPTH)
189 Display_does_not_support_this_many_colors
190 #endif
191 
192 /*
193  * The macros below define the color mapping used on 24-bit true-color
194  * displays.
195  * FAKE_TRUE_COLOR is used for debugging only.  It simulates a true-color
196  * type mapping on an 8-bit pseudo-color display.
197 #define FAKE_TRUE_COLOR
198  */
199 #ifdef FAKE_TRUE_COLOR
200 # define TRUE_RED_BITS	3		/* everything depends on this one */
201 # define TRUE_GREEN_BITS 2
202 # define TRUE_BLUE_BITS	(DEPTH - TRUE_RED_BITS - TRUE_GREEN_BITS)
203 #else
204 # define TRUE_RED_BITS	8		/* everything depends on this one */
205 # define TRUE_GREEN_BITS TRUE_RED_BITS
206 # define TRUE_BLUE_BITS	TRUE_RED_BITS
207 #endif ./* FAKE_TRUE_COLOR */
208 #define TRUE_DEPTH	(TRUE_RED_BITS + TRUE_GREEN_BITS + TRUE_BLUE_BITS)
209 /*
210  * Masks to pull out rgb components.  Note that the bit order is BGR from
211  * high to low order bits.
212  */
213 #define TRUE_RED_MASK	((1 << TRUE_RED_BITS) - 1)
214 #define TRUE_GREEN_MASK	((1 << (TRUE_RED_BITS + TRUE_GREEN_BITS)) - 1 \
215 			 - TRUE_RED_MASK)
216 #define TRUE_BLUE_MASK	((1 << (TRUE_RED_BITS + TRUE_GREEN_BITS \
217 				+ TRUE_BLUE_BITS)) - 1 \
218 			 - TRUE_GREEN_MASK - TRUE_RED_MASK)
219 /*
220  * number of colors on rgb dimensions
221  */
222 #define TRUE_RED_COLS	(1 << TRUE_RED_BITS)
223 #define TRUE_GREEN_COLS	(1 << TRUE_GREEN_BITS)
224 #define TRUE_BLUE_COLS	(1 << TRUE_BLUE_BITS)
225 
226 /* Initialize the device. */
227 private Notify_value destroy_func();
228 int
sun_open(register gx_device * dev)229 sun_open(register gx_device *dev)
230 {
231 #ifdef gs_DEBUG
232 if ( gs_debug['X'] )
233 	{ extern int _Xdebug;
234 	  _Xdebug = 1;
235 	}
236 #endif
237 	if (xdev->frame == (Frame)0)
238 	    xdev->frame =
239 		window_create(NULL, FRAME, FRAME_LABEL, gs_product,
240 			WIN_WIDTH, min(xdev->width + 24, 900),
241 			WIN_HEIGHT, min(xdev->height + 36, 900),
242 			WIN_Y, 0,
243 			WIN_X, 200,
244 			0);
245 	if (xdev->frame == (Frame)0)
246 	    return -1;
247 	xdev->canvas = window_create(xdev->frame, CANVAS,
248 			CANVAS_AUTO_EXPAND,		FALSE,
249 			CANVAS_AUTO_SHRINK,		FALSE,
250 			CANVAS_WIDTH,			xdev->width,
251 			CANVAS_HEIGHT,			xdev->height,
252 #ifndef PRE_IBIS	/* try to use 24-bit visual if OS supports it */
253 			CANVAS_COLOR24,			TRUE,
254 #endif
255 			CANVAS_RETAINED,		FALSE,
256 		0);
257 	xdev->pw = canvas_pixwin(xdev->canvas);
258 
259 	switch (xdev->pw->pw_pixrect->pr_depth) {
260 	     static gx_device_color_info mono_ci =
261 		dci_black_and_white;
262 	     /*
263 	      * If the pre-allocated color cube leaves room for spare entries,
264 	      * tell gs we can render colors exactly.  Otherwise admit our
265 	      * limitations.
266 	      */
267 	     static gx_device_color_info color_ci =
268 #if (RGB_COLS < CMS_SIZE)
269 		dci_color(DEPTH, 31, MAX_COLS);
270 #else
271 		dci_color(DEPTH, MAX_COLS - 1, MAX_COLS);
272 #endif
273 	     static gx_device_color_info truecolor_ci =
274 		dci_color(TRUE_DEPTH,31,4);
275 	case 1:
276 	     /* mono display */
277 	     xdev->color_info = mono_ci;
278 	     break;
279 #ifndef FAKE_TRUE_COLOR
280 	case DEPTH:
281 	     /* pseudo-color display */
282 	     xdev->color_info = color_ci;
283 	     xdev->truecolor = 0;
284 	     break;
285 #endif /* FAKE_TRUE_COLOR */
286 	case TRUE_DEPTH:
287 	case TRUE_DEPTH+8:	/* I'm not sure whether the XBGR frame buffer
288 				   returns depth 24 or 32. */
289 	     /* pseudo-color display */
290 	     xdev->color_info = truecolor_ci;
291 	     xdev->truecolor = 1;
292 	     break;
293 	default:
294 	     eprintf1("gs: Cannot handle display of depth %d.\n",
295 	              xdev->pw->pw_pixrect->pr_depth);
296 	     return -1;
297 	}
298 
299 	if ( gx_device_has_color(xdev)
300 #ifndef FAKE_TRUE_COLOR
301 	     && !xdev->truecolor
302 #endif
303 	   )
304 	   {
305 		int j;
306 		int color;
307 
308 		/*
309 		 * Create the pre-allocated colorcube.
310 		 */
311 		xdev->red = (byte *)malloc(CMS_SIZE);
312 		xdev->green = (byte *)malloc(CMS_SIZE);
313 		xdev->blue = (byte *)malloc(CMS_SIZE);
314 		if (!xdev->red || !xdev->green || !xdev->blue) {
315 			eprintf("gs: no memory for colormap\n");
316 			return -1;
317 		}
318 
319 #ifdef FAKE_TRUE_COLOR
320 		/*
321 		 * Fit the largest possible color cube into the colormap.
322 		 */
323 		for ( j = 0; j < ALL_COLS; j++ ) {
324 		   xdev->blue[j] =
325 			(double)((j & TRUE_BLUE_MASK)
326 			         >> (TRUE_GREEN_BITS + TRUE_RED_BITS))
327 			/ (TRUE_BLUE_COLS - 1)
328 			* (ALL_COLS - 1);
329 		   xdev->green[j] =
330 			(double)((j & TRUE_GREEN_MASK) >> TRUE_RED_BITS)
331 			/ (TRUE_GREEN_COLS - 1)
332 			* (ALL_COLS - 1);
333 		   xdev->red[j] =
334 			(double)((j & TRUE_RED_MASK))
335 			/ (TRUE_RED_COLS - 1)
336 			* (ALL_COLS - 1);
337 		}
338 
339 		xdev->freecols = 0;
340 #else /* !FAKE_TRUE_COLOR */
341 		/*
342 		 * Black and white are allocated in the last two slots,
343 		 * so as to be compatible with the monochrome colormap.
344 		 * This prevents most text etc. to go technicolor as focus
345 		 * changes into the window.
346 		 *
347 	         * The requirement that these two entries be at the end
348 		 * of the colormap makes it most convenient to allocate
349 		 * the remmaining entries from back to the front as well.
350 		 * Therefore xdev->freecols is the minimal allocated
351 		 * color index, and decreases as new ones are allocated.
352 		 */
353 		j = CMS_SIZE - 2;
354 		cms_monochromeload(xdev->red + j,
355 		                   xdev->green + j,
356 				   xdev->blue + j);
357 
358 		/*
359 		 * The remaining slots down to CMS_SIZE - RGB_COLS are filled
360 		 * with evenly spaced points from the colorcube.
361 		 */
362 		for ( color = 1; color < RGB_COLS - 1; color++ ) {
363 		   j--;
364 		   xdev->red[j] =
365 			(double)((color & RED_MASK) >> (GREEN_BITS + BLUE_BITS))
366 			/ (RED_COLS - 1)
367 			* (ALL_COLS - 1);
368 		   xdev->green[j] =
369 			(double)((color & GREEN_MASK) >> BLUE_BITS)
370 			/ (GREEN_COLS - 1)
371 			* (ALL_COLS - 1);
372 		   xdev->blue[j] =
373 			(double)((color & BLUE_MASK))
374 			/ (BLUE_COLS - 1)
375 			* (ALL_COLS - 1);
376 		}
377 
378 
379 		/*
380 		 * Set the low-water mark to the beginning of the colorcube.
381 		 */
382 		xdev->freecols = j;
383 
384 		/*
385 		 * The unused entries are filled so that the last entry is
386 		 * always different from the 0th entry.  This is a requirement
387 		 * for SunWindows.
388 		 */
389 		for (j-- ; j >= 0 ; j--) {
390 		   xdev->red[j] = xdev->green[j] = xdev->blue[j] =
391 			~xdev->red[CMS_SIZE - 1];
392 		}
393 #endif /* FAKE_TRUE_COLOR */
394 
395 		/*
396 		 * Install the colormap.
397 		 */
398 		sprintf(xdev->cmsname, "%s-%d", CMSNAME, getpid());
399 		pw_setcmsname(xdev->pw, xdev->cmsname);
400 		pw_putcolormap(xdev->pw, 0, CMS_SIZE,
401 		               xdev->red, xdev->green, xdev->blue);
402 	   }
403 	else {
404 		xdev->freecols = 0;
405 		xdev->red = (byte *)0;
406 		xdev->green = (byte *)0;
407 		xdev->blue = (byte *)0;
408 	}
409 
410 	/*
411 	 * Reset to retained after colormap length is changed
412 	 */
413 	window_set(xdev->canvas,
414 		CANVAS_RETAINED, 		TRUE,
415 		WIN_VERTICAL_SCROLLBAR,		scrollbar_create(0),
416 		WIN_HORIZONTAL_SCROLLBAR,	scrollbar_create(0),
417 		0);
418 	window_set(xdev->frame, WIN_SHOW, TRUE, 0);
419 	/* Interpose a destroy function to keep the driver bookkeeping */
420 	/* machinery from getting confused if the user closes the window. */
421 	notify_interpose_destroy_func(xdev->frame, destroy_func);
422 	(void) notify_do_dispatch();
423 	(void) notify_dispatch();
424 	return 0;
425 }
426 /* Prevent the user from closing the window. */
427 private Notify_value
destroy_func(Frame frame,Destroy_status status)428 destroy_func(Frame frame, Destroy_status status)
429 {	if ( status == DESTROY_CHECKING )
430 	   {	notify_veto_destroy(frame);
431 		return (NOTIFY_DONE);
432 	   }
433 	return (notify_next_destroy_func(frame, status));
434 }
435 
436 /* Close the device. */
437 int
sun_close(gx_device * dev)438 sun_close(gx_device *dev)
439 {	window_destroy(xdev->frame);
440 	xdev->frame = (Frame)0;
441 	xdev->canvas = (Canvas)0;
442 	xdev->pw = (Pixwin *)0;
443 	xdev->freecols = 0;
444 	if (xdev->red)
445 	    free(xdev->red);
446 	if (xdev->green)
447 	    free(xdev->green);
448 	if (xdev->blue)
449 	    free(xdev->blue);
450 	return 0;
451 }
452 
453 /* Synchronize the display with the commands already given */
454 int
sun_sync(register gx_device * dev)455 sun_sync(register gx_device *dev)
456 {	(void) notify_dispatch();
457 	return 0;
458 }
459 
460 /* Map RGB to color number -
461 	Look for existing entry in colormap, or create a new one, or
462 	give up if no free colormap entries (requesting dithering).
463  */
464 gx_color_index
sun_map_rgb_color(gx_device * dev,unsigned short red,unsigned short green,unsigned short blue)465 sun_map_rgb_color(gx_device *dev, unsigned short red,
466 	unsigned short green, unsigned short blue)
467 {	if ( !xdev->frame || !gx_device_has_color(dev) )
468 		/*
469 		 * Invert default color index to match mono display
470 		 * pixel values (black = 1, white = 0).
471 		 */
472 		return !gx_default_map_rgb_color(dev, red, green, blue);
473 	else if ( !xdev->truecolor ) {
474 		byte red_val, green_val, blue_val;
475 		int i;
476 		static int warn = 1;
477 
478 		/*
479 		 * Determine the RGB values at display resolution we
480 		 * ideally would want this color to be mapped into.
481 		 */
482 		red_val = (double)red/gx_max_color_value * (ALL_COLS - 1);
483 		green_val = (double)green/gx_max_color_value * (ALL_COLS - 1);
484 		blue_val = (double)blue/gx_max_color_value * (ALL_COLS - 1);
485 
486 		/*
487 		 * Look for an exact match among the colors already allocated.
488 		 * This includes the pre-allocated default color cube.
489 		 */
490 		for (i = CMS_SIZE - 1; i >= xdev->freecols; i--) {
491 			if (xdev->red[i] == red_val &&
492 			    xdev->green[i] == green_val &&
493 			    xdev->blue[i] == blue_val) {
494 				return i;
495 			}
496 		}
497 
498 		/*
499 		 * If we run out of space in the color map, let gs know.
500 		 * It will call us again to request colors to do the
501 		 * dithering, and hopefully request only RGB values that
502 		 * match the colorcube entries. IF NOT, WE WILL LOOP
503 		 * FOREVER!
504 		 * NOTE: Leave the zero'th colormap entry alone lest the
505 		 * scrollbar be colored.
506 		 */
507 		if (xdev->freecols <= 1) {
508 		    if (warn) {
509 			eprintf("gs: last spare color map entry allocated\n");
510 			warn = 0;
511 		    }
512 		    return gx_no_color_index;
513 		}
514 
515 		/*
516 		 * Allocate new color in map.
517 		 */
518 		xdev->red[i] = red_val;
519 		xdev->green[i] = green_val;
520 		xdev->blue[i] = blue_val;
521 		pw_setcmsname(xdev->pw, xdev->cmsname);
522 		pw_putcolormap(xdev->pw, i, 1,
523 		               &xdev->red[i], &xdev->green[i], &xdev->blue[i]);
524 
525 		xdev->freecols = i;
526 		return i;
527 	}
528 	else {	/* true color mapping --
529 			color index encodes all 3 RGB values */
530 		return ((blue >> (gx_color_value_bits - TRUE_BLUE_BITS))
531 			<< (TRUE_GREEN_BITS + TRUE_RED_BITS)) |
532 		       ((green >> (gx_color_value_bits - TRUE_GREEN_BITS))
533 			<< TRUE_RED_BITS) |
534 		       (red >> (gx_color_value_bits - TRUE_RED_BITS));
535 	}
536 }
537 
538 /* Map color number back to RGB values  - see sun_map_rgb_color(), above */
539 int
sun_map_color_rgb(gx_device * dev,gx_color_index color,unsigned short rgb[3])540 sun_map_color_rgb(gx_device *dev, gx_color_index color,
541 	unsigned short rgb[3])
542 {	if ( !xdev->frame || !gx_device_has_color(dev) )
543 		return gx_default_map_color_rgb(dev, !color, rgb);
544 	else if ( !xdev->truecolor ) {
545 		/*
546 		 * We just use the colormap to map back to rgb values.
547 		 */
548 		if (color < xdev->freecols || color >= CMS_SIZE) {
549 			eprintf1("gs: attempt to get RGB values for unallocated color index %d\n", (int)color);
550 			return -1;
551 		}
552 		rgb[0] = (double)xdev->red[color] / (ALL_COLS - 1)
553 			 * gx_max_color_value;
554 		rgb[1] = (double)xdev->green[color] / (ALL_COLS - 1)
555 			 * gx_max_color_value;
556 		rgb[2] = (double)xdev->blue[color] / (ALL_COLS - 1)
557 			 * gx_max_color_value;
558 		return 0;
559 	}
560 	else {	/* true color mapping */
561 		rgb[0] = (double)((unsigned short)(color & TRUE_RED_MASK))
562 			 / (TRUE_RED_COLS - 1)
563 			 * gx_max_color_value;
564 		rgb[1] = (double)((unsigned short)(color & TRUE_GREEN_MASK)
565 			  >> TRUE_RED_BITS)
566 			 / (TRUE_GREEN_COLS - 1)
567 			 * gx_max_color_value;
568 		rgb[2] = (double)((unsigned short)(color & TRUE_BLUE_MASK)
569 			  >> (TRUE_GREEN_BITS + TRUE_RED_BITS))
570 			 / (TRUE_BLUE_COLS - 1)
571 			 * gx_max_color_value;
572 		return 0;
573 	}
574 }
575 
576 /* Fill a rectangle with a color. */
577 int
sun_fill_rectangle(register gx_device * dev,int x,int y,int w,int h,gx_color_index color)578 sun_fill_rectangle(register gx_device *dev,
579   int x, int y, int w, int h, gx_color_index color)
580 {	fit_fill(dev, x, y, w, h);
581 
582 	pw_write(xdev->pw, x, y, w, h, PIX_SRC | PIX_COLOR((int)(color)),
583 		 (Pixrect *)0, 0, 0);
584 	(void) notify_dispatch();
585 	return 0;
586 }
587 
588 /* Copy a monochrome bitmap. */
589 int
sun_copy_mono(register gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)590 sun_copy_mono(register gx_device *dev,
591   const byte *base, int sourcex, int raster, gx_bitmap_id id,
592   int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
593 {
594 /* We define a non-const pointer to the data so we can invert it or */
595 /* byte-swap it in place temporarily (we restore it at the end). */
596 /* Yes, this is a bad and wicked thing to do! */
597 #define non_const_base ((byte *)base)
598 
599 	register int i;
600 	int nbytes;
601 	extern struct pixrectops mem_ops;
602 #if !arch_is_big_endian			/* need to swap bits & bytes */
603 #  define BUF_WIDTH_BYTES (((int)(8.5*DEFAULT_DPI)+15)/16*2)
604 	byte swap_buf[BUF_WIDTH_BYTES];
605 #endif
606 
607 	fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
608 	nbytes = h * raster;
609 
610 	xdev->pr.pr_ops = &mem_ops;
611 	xdev->pr.pr_width = w + sourcex + 8;
612 	xdev->pr.pr_height = h;
613 	xdev->pr.pr_depth = 1;
614 	xdev->pr.pr_data = (caddr_t)&(xdev->mpr);
615 	xdev->mpr.md_linebytes = raster;
616 	xdev->mpr.md_image = (short *)((ulong)base & ~1);
617 #if !arch_is_big_endian
618 	/* Reverse the bit order in each byte. */
619 	for ( i = 0; i < nbytes; i++ )
620 		non_const_base[i] = reverse_bits[base[i]];
621 #endif
622 	pw_batch_on(xdev->pw);
623 	if (one != gx_no_color_index)
624 	{	pw_stencil(xdev->pw, x, y, w, h,
625 			PIX_SRC | PIX_COLOR(one), &(xdev->pr),
626 			((int)base & 1) ? sourcex + 8 : sourcex, 0,
627 			(Pixrect *)0, 0, 0);
628 	}
629 	if (zero != gx_no_color_index)
630 	{	for (i = 0; i < nbytes; i++)
631 			non_const_base[i] = ~base[i];
632 		pw_stencil(xdev->pw, x, y, w, h,
633 			PIX_SRC | PIX_COLOR(zero), &(xdev->pr),
634 			((int)base & 1) ? sourcex + 8 : sourcex, 0,
635 			(Pixrect *)0, 0, 0);
636 		for (i = 0; i < nbytes; i++)
637 			non_const_base[i] = ~base[i];
638 	}
639 	pw_batch_off(xdev->pw);
640 #if !arch_is_big_endian
641 	/* Reverse the bits back again. */
642 	for ( i = 0; i < nbytes; i++ )
643 		non_const_base[i] = reverse_bits[base[i]];
644 #endif
645 	(void) notify_dispatch();
646 	return 0;
647 }
648 
649 /* Copy a color bitmap. */
650 int
sun_copy_color(register gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)651 sun_copy_color(register gx_device *dev,
652   const byte *base, int sourcex, int raster, gx_bitmap_id id,
653   int x, int y, int w, int h)
654 {
655 	extern struct pixrectops mem_ops;
656 
657 	if ( !gx_device_has_color(dev) )
658 		return sun_copy_mono(dev, base, sourcex, raster, id,
659 				     x, y, w, h,
660 				     (gx_color_index)0, (gx_color_index)1);
661 
662 	fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
663 
664 	xdev->pr.pr_ops = &mem_ops;
665 	xdev->pr.pr_width = w + sourcex + 8;
666 	xdev->pr.pr_height = h;
667 	xdev->pr.pr_depth = 8;
668 	xdev->pr.pr_data = (caddr_t)&(xdev->mpr);
669 	xdev->mpr.md_linebytes = raster;
670 	xdev->mpr.md_image = (short *)((ulong)base & ~1);
671 	pw_write(xdev->pw, x, y, w, h,
672 		 PIX_SRC, &(xdev->pr),
673 		 (((int)base & 1) ? sourcex + 8 : sourcex), 0);
674 	(void) notify_dispatch();
675 	return 0;
676 }
677 
678 /* Draw a line */
679 int
sun_draw_line(register gx_device * dev,int x0,int y0,int x1,int y1,gx_color_index color)680 sun_draw_line(register gx_device *dev,
681   int x0, int y0, int x1, int y1, gx_color_index color)
682 {	pw_vector(xdev->pw, x0, y0, x1, y1, PIX_SRC, color);
683 	(void) notify_dispatch();
684 	return 0;
685 }
686