1 /* Copyright (C) 1989-2005 artofcode LLC. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevpcfb.c,v 1.7 2005/08/09 20:23:07 giles Exp $ */
18 /* IBM PC frame buffer (EGA/VGA) drivers */
19 #include "memory_.h"
20 #include "gconfigv.h" /* for USE_ASM */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsparam.h"
24 #include "gxdevice.h"
25 #include "gdevpccm.h"
26 #include "gdevpcfb.h"
27
28 /* We may compile this in a non-segmented environment.... */
29 #ifndef _ss
30 #define _ss
31 #endif
32
33 /* Macro for casting gx_device argument */
34 #define fb_dev ((gx_device_ega *)dev)
35
36 /* Procedure record */
37 private dev_proc_map_rgb_color(ega0_map_rgb_color);
38 private dev_proc_map_rgb_color(ega1_map_rgb_color);
39 #define ega2_map_rgb_color pc_4bit_map_rgb_color
40 private dev_proc_map_color_rgb(ega01_map_color_rgb);
41 #define ega2_map_color_rgb pc_4bit_map_color_rgb
42 #if ega_bits_of_color == 0
43 # define ega_map_rgb_color ega0_map_rgb_color
44 # define ega_map_color_rgb ega01_map_color_rgb
45 #else
46 # if ega_bits_of_color == 1
47 # define ega_map_rgb_color ega1_map_rgb_color
48 # define ega_map_color_rgb ega01_map_color_rgb
49 # else
50 # define ega_map_rgb_color ega2_map_rgb_color
51 # define ega_map_color_rgb ega2_map_color_rgb
52 # endif
53 #endif
54 #define ega_std_procs(get_params, put_params)\
55 ega_open,\
56 NULL, /* get_initial_matrix */\
57 NULL, /* sync_output */\
58 NULL, /* output_page */\
59 ega_close,\
60 ega_map_rgb_color,\
61 ega_map_color_rgb,\
62 ega_fill_rectangle,\
63 ega_tile_rectangle,\
64 ega_copy_mono,\
65 ega_copy_color,\
66 NULL, /* draw_line */\
67 ega_get_bits,\
68 get_params,\
69 put_params,\
70 NULL, /* map_cmyk_color */\
71 NULL, /* get_xfont_procs */\
72 NULL, /* get_xfont_device */\
73 NULL, /* map_rgb_alpha_color */\
74 gx_page_device_get_page_device
75
76 private const gx_device_procs ega_procs =
77 {
78 ega_std_procs(NULL, NULL)
79 };
80
81 private dev_proc_get_params(svga16_get_params);
82 private dev_proc_put_params(svga16_put_params);
83 private const gx_device_procs svga16_procs =
84 {
85 ega_std_procs(svga16_get_params, svga16_put_params)
86 };
87
88 /* All the known instances */
89 /* EGA */
90 gx_device_ega far_data gs_ega_device =
91 ega_device("ega", ega_procs, 80, 350, 48.0 / 35.0, 0x10);
92
93 /* VGA */
94 gx_device_ega far_data gs_vga_device =
95 ega_device("vga", ega_procs, 80, 480, 1.0, 0x12);
96
97 /* Generic SuperVGA, 800x600, 16-color mode */
98 gx_device_ega far_data gs_svga16_device =
99 ega_device("svga16", svga16_procs, 100, 600, 1.0, 0x29 /*Tseng */ );
100
101 /* Save the BIOS state */
102 private pcfb_bios_state pcfb_save_state =
103 {-1};
104
105 /* Initialize the EGA for graphics mode */
106 int
ega_open(gx_device * dev)107 ega_open(gx_device * dev)
108 { /* Adjust the device resolution. */
109 /* This is a hack, pending refactoring of the put_params machinery. */
110 switch (fb_dev->video_mode) {
111 case 0x10: /* EGA */
112 gx_device_adjust_resolution(dev, 640, 350, 1);
113 break;
114 case 0x12: /* VGA */
115 gx_device_adjust_resolution(dev, 640, 480, 1);
116 break;
117 default: /* 800x600 SuperVGA */
118 gx_device_adjust_resolution(dev, 800, 600, 1);
119 break;
120 }
121 if (pcfb_save_state.display_mode < 0)
122 pcfb_get_state(&pcfb_save_state);
123 /* Do implementation-specific initialization */
124 pcfb_set_signals(dev);
125 pcfb_set_mode(fb_dev->video_mode);
126 set_s_map(-1); /* enable all maps */
127 return 0;
128 }
129
130 /* Reinitialize the EGA for text mode */
131 int
ega_close(gx_device * dev)132 ega_close(gx_device * dev)
133 {
134 if (pcfb_save_state.display_mode >= 0)
135 pcfb_set_state(&pcfb_save_state);
136 return 0;
137 }
138
139 /* Get/put the display mode parameter. */
140 private int
svga16_get_params(gx_device * dev,gs_param_list * plist)141 svga16_get_params(gx_device * dev, gs_param_list * plist)
142 {
143 int code = gx_default_get_params(dev, plist);
144
145 if (code < 0)
146 return code;
147 return param_write_int(plist, "DisplayMode", &fb_dev->video_mode);
148 }
149 private int
svga16_put_params(gx_device * dev,gs_param_list * plist)150 svga16_put_params(gx_device * dev, gs_param_list * plist)
151 {
152 int ecode = 0;
153 int code;
154 int imode = fb_dev->video_mode;
155 const char *param_name;
156
157 switch (code = param_read_int(plist, (param_name = "DisplayMode"), &imode)) {
158 default:
159 ecode = code;
160 param_signal_error(plist, param_name, ecode);
161 case 0:
162 case 1:
163 break;
164 }
165
166 if (ecode < 0)
167 return ecode;
168 code = gx_default_put_params(dev, plist);
169 if (code < 0)
170 return code;
171
172 if (imode != fb_dev->video_mode) {
173 if (dev->is_open)
174 gs_closedevice(dev);
175 fb_dev->video_mode = imode;
176 }
177 return 0;
178 }
179
180 /* Map a r-g-b color to an EGA color code. */
181 private gx_color_index
ega0_map_rgb_color(gx_device * dev,const gx_color_value cv[])182 ega0_map_rgb_color(gx_device * dev, const gx_color_value cv[])
183 {
184 return pc_4bit_map_rgb_color(dev, cv);
185 }
186 private gx_color_index
ega1_map_rgb_color(gx_device * dev,const gx_color_value cv[])187 ega1_map_rgb_color(gx_device * dev, const gx_color_value cv[])
188 {
189 const gx_color_value cvtop = (1 << (gx_color_value_bits - 1));
190 gx_color_value cvt[3];
191 cvt[0] = cv[0] & cvtop;
192 cvt[1] = cv[1] & cvtop;
193 cvt[2] = cv[2] & cvtop;
194 return pc_4bit_map_rgb_color(dev, cvt);
195 }
196
197 /* Map a color code to r-g-b. */
198 #define icolor (int)color
199 private int
ega01_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])200 ega01_map_color_rgb(gx_device * dev, gx_color_index color,
201 gx_color_value prgb[3])
202 {
203 #define one (gx_max_color_value / 2 + 1)
204 prgb[0] = (icolor & 4 ? one : 0);
205 prgb[1] = (icolor & 2 ? one : 0);
206 prgb[2] = (icolor & 1 ? one : 0);
207 return 0;
208 #undef one
209 }
210 #undef icolor
211
212 /* ------ Internal routines ------ */
213
214 /* Structure for operation parameters. */
215 /* Note that this structure is known to assembly code. */
216 /* Not all parameters are used for every operation. */
217 typedef struct rop_params_s {
218 fb_ptr dest; /* pointer to frame buffer */
219 int draster; /* raster of frame buffer */
220 const byte *src; /* pointer to source data */
221 int sraster; /* source raster */
222 int width; /* width in bytes */
223 int height; /* height in scan lines */
224 int shift; /* amount to right shift source */
225 int invert; /* 0 or -1 to invert source */
226 int data; /* data for fill */
227 } rop_params;
228 typedef rop_params _ss *rop_ptr;
229
230 /* Assembly language routines */
231
232 #if USE_ASM
233 void memsetcol(rop_ptr); /* dest, draster, height, data */
234 #else
235 #define memsetcol cmemsetcol
236 private void
cmemsetcol(rop_ptr rop)237 cmemsetcol(rop_ptr rop)
238 {
239 byte *addr = rop->dest;
240 int yc = rop->height;
241 byte data = rop->data;
242 int draster = rop->draster;
243
244 while (yc--) {
245 byte_discard(*addr);
246 *addr = data;
247 addr += draster;
248 }
249 }
250 #endif
251
252 #if USE_ASM
253 void memsetrect(rop_ptr); /* dest, draster, width, height, data */
254 #else
255 #define memsetrect cmemsetrect
256 private void
cmemsetrect(rop_ptr rop)257 cmemsetrect(rop_ptr rop)
258 {
259 int yc = rop->height;
260 int width = rop->width;
261
262 if (yc <= 0 || width <= 0)
263 return;
264 {
265 byte *addr = rop->dest;
266 byte data = rop->data;
267
268 if (width > 5) { /* use memset */
269 int skip = rop->draster;
270
271 do {
272 memset(addr, data, width);
273 addr += skip;
274 }
275 while (--yc);
276 } else { /* avoid the fixed overhead */
277 int skip = rop->draster - width;
278
279 do {
280 int cnt = width;
281
282 do {
283 *addr++ = data;
284 } while (--cnt);
285 addr += skip;
286 }
287 while (--yc);
288 }
289 }
290 }
291 #endif
292
293 #if USE_ASM
294 void memrwcol(rop_ptr); /* dest, draster, src, sraster, height, shift, invert */
295 # define memrwcol0(rop) memrwcol(rop) /* same except shift = 0 */
296 #else
297 # define memrwcol cmemrwcol
298 # define memrwcol0 cmemrwcol0
299 private void
cmemrwcol(rop_ptr rop)300 cmemrwcol(rop_ptr rop)
301 {
302 byte *dp = rop->dest;
303 const byte *sp = rop->src;
304 int yc = rop->height;
305 int shift = rop->shift;
306 byte invert = rop->invert;
307 int sraster = rop->sraster, draster = rop->draster;
308
309 while (yc--) {
310 byte_discard(*dp);
311 *dp = ((*sp >> shift) + (*sp << (8 - shift))) ^ invert;
312 dp += draster, sp += sraster;
313 }
314 }
315 private void
cmemrwcol0(rop_ptr rop)316 cmemrwcol0(rop_ptr rop)
317 {
318 byte *dp = rop->dest;
319 const byte *sp = rop->src;
320 int yc = rop->height;
321 byte invert = rop->invert;
322 int sraster = rop->sraster, draster = rop->draster;
323
324 if (yc > 0)
325 do {
326 byte_discard(*dp);
327 *dp = *sp ^ invert;
328 dp += draster, sp += sraster;
329 }
330 while (--yc);
331 }
332 #endif
333
334 #if USE_ASM
335 void memrwcol2(rop_ptr); /* dest, draster, src, sraster, height, shift, invert */
336 #else
337 #define memrwcol2 cmemrwcol2
338 private void
cmemrwcol2(rop_ptr rop)339 cmemrwcol2(rop_ptr rop)
340 {
341 byte *dp = rop->dest;
342 const byte *sp = rop->src;
343 int yc = rop->height;
344 int shift = rop->shift;
345 byte invert = rop->invert;
346 int sraster = rop->sraster, draster = rop->draster;
347
348 while (yc--) {
349 byte_discard(*dp);
350 *dp = ((sp[1] >> shift) + (*sp << (8 - shift))) ^ invert;
351 dp += draster, sp += sraster;
352 }
353 }
354 #endif
355
356 /* Forward definitions */
357 int ega_write_dot(gx_device *, int, int, gx_color_index);
358 private void fill_rectangle(rop_ptr, int, int, int);
359 private void fill_row_only(byte *, int, int, int);
360
361 /* Clean up after writing */
362 #define dot_end()\
363 set_g_mask(0xff) /* all bits on */
364
365 /* Write a dot using the EGA color codes. */
366 /* This doesn't have to be efficient. */
367 int
ega_write_dot(gx_device * dev,int x,int y,gx_color_index color)368 ega_write_dot(gx_device * dev, int x, int y, gx_color_index color)
369 {
370 byte data[4];
371
372 data[0] = (byte) color;
373 return ega_copy_color(dev, data, 1, 4, gx_no_bitmap_id, x, y, 1, 1);
374 }
375
376 /* Macro for testing bit-inclusion */
377 #define bit_included_in(x,y) !((x)&~(y))
378
379 /* Copy a monochrome bitmap. The colors are given explicitly. */
380 /* Color = gx_no_color_index means transparent (no effect on the image). */
381 int
ega_copy_mono(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 izero,gx_color_index ione)382 ega_copy_mono(gx_device * dev,
383 const byte * base, int sourcex, int raster, gx_bitmap_id id,
384 int x, int y, int w, int h, gx_color_index izero, gx_color_index ione)
385 {
386 rop_params params;
387
388 #define czero (int)izero
389 #define cone (int)ione
390 int dleft, count;
391 byte mask, rmask;
392 fb_ptr save_dest;
393 int other_color = -1;
394
395 fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
396 params.dest = mk_fb_ptr(x, y);
397 params.draster = fb_dev->raster;
398 params.src = base + (sourcex >> 3);
399 params.sraster = raster;
400 params.height = h;
401 params.shift = (x - sourcex) & 7;
402 /* Analyze the 16 possible cases: each of izero and ione may be */
403 /* 0, 0xf, transparent, or some other color. */
404 switch (czero) {
405 case no_color:
406 switch (cone) {
407 default: /* (T, other) */
408 /* Must do 2 passes */
409 other_color = cone;
410 save_dest = params.dest;
411 /* falls through */
412 case 0: /* (T, 0) */
413 set_g_function(gf_AND);
414 params.invert = -1;
415 break;
416 case 0xf: /* (T, 0xf) */
417 set_g_function(gf_OR);
418 params.invert = 0;
419 break;
420 case no_color: /* (T, T) */
421 return 0; /* nothing to do */
422 }
423 break;
424 case 0:
425 params.invert = 0;
426 switch (cone) {
427 default: /* (0, other) */
428 set_g_const(0);
429 set_g_const_map(cone ^ 0xf);
430 /* falls through */
431 case 0xf: /* (0, 0xf) */
432 break;
433 case no_color: /* (0, T) */
434 set_g_function(gf_AND);
435 break;
436 }
437 break;
438 case 0xf:
439 params.invert = -1;
440 switch (cone) {
441 case 0: /* (0xf, 0) */
442 break;
443 default: /* (0xf, other) */
444 set_g_const(0xf);
445 set_g_const_map(cone);
446 break;
447 case no_color: /* (0xf, T) */
448 set_g_function(gf_OR);
449 /* falls through */
450 }
451 break;
452 default:
453 switch (cone) {
454 default: /* (other, not T) */
455 if (bit_included_in(czero, cone)) {
456 set_g_const(czero);
457 set_g_const_map(czero ^ cone ^ 0xf);
458 params.invert = 0;
459 break;
460 } else if (bit_included_in(cone, czero)) {
461 set_g_const(cone);
462 set_g_const_map(cone ^ czero ^ 0xf);
463 params.invert = -1;
464 break;
465 }
466 /* No way around it, fill with one color first. */
467 save_dest = params.dest;
468 fill_rectangle((rop_ptr) & params, x & 7, w, cone);
469 params.dest = save_dest;
470 set_g_function(gf_XOR);
471 set_s_map(czero ^ cone);
472 other_color = -2; /* must reset s_map at end */
473 params.invert = -1;
474 break;
475 case no_color: /* (other, T) */
476 /* Must do 2 passes */
477 other_color = czero;
478 save_dest = params.dest;
479 set_g_function(gf_AND);
480 params.invert = 0;
481 break;
482 }
483 break;
484 }
485 /* Actually copy the bits. */
486 dleft = 8 - (x & 7);
487 mask = 0xff >> (8 - dleft);
488 count = w - dleft;
489 if (count < 0)
490 mask -= mask >> w,
491 rmask = 0;
492 else
493 rmask = 0xff00 >> (count & 7);
494 /* params: dest, src, sraster, height, shift, invert */
495 /* Smashes params.src, params.dest, count. */
496 copy:set_g_mask(mask);
497 if (params.shift == 0) { /* optimize the aligned case *//* Do left column */
498 memrwcol0((rop_ptr) & params);
499 /* Do center */
500 if ((count -= 8) >= 0) {
501 out_g_mask(0xff);
502 do {
503 params.src++, params.dest++;
504 memrwcol0((rop_ptr) & params);
505 }
506 while ((count -= 8) >= 0);
507 }
508 /* Do right column */
509 if (rmask) {
510 params.src++, params.dest++;
511 out_g_mask(rmask);
512 memrwcol0((rop_ptr) & params);
513 }
514 } else { /* Do left column */
515 int sleft = 8 - (sourcex & 7);
516
517 if (sleft >= dleft) { /* Source fits in one byte */
518 memrwcol((rop_ptr) & params);
519 } else if (w <= sleft) { /* Source fits in one byte, thin case */
520 memrwcol((rop_ptr) & params);
521 goto fin;
522 } else {
523 memrwcol2((rop_ptr) & params);
524 params.src++;
525 }
526 /* Do center */
527 if ((count -= 8) >= 0) {
528 out_g_mask(0xff);
529 do {
530 params.dest++;
531 memrwcol2((rop_ptr) & params);
532 params.src++;
533 }
534 while ((count -= 8) >= 0);
535 }
536 /* Do right column */
537 if (rmask) {
538 out_g_mask(rmask);
539 params.dest++;
540 if (count + 8 <= params.shift)
541 memrwcol((rop_ptr) & params);
542 else
543 memrwcol2((rop_ptr) & params);
544 }
545 }
546 fin:if (other_color != -1) {
547 if (other_color >= 0) { /* Do the second pass on (T, other) or (other, T). */
548 count = w - dleft;
549 params.src = base + (sourcex >> 3);
550 params.dest = save_dest;
551 params.invert ^= -1;
552 set_s_map(other_color);
553 set_g_function(gf_OR);
554 other_color = -2;
555 goto copy;
556 } else { /* Finished second pass, restore s_map */
557 set_s_map(-1);
558 }
559 }
560 set_g_function(gf_WRITE);
561 set_g_const_map(0);
562 dot_end();
563 return 0;
564 #undef czero
565 #undef cone
566 }
567
568 /* Copy a color pixelmap. This is just like a bitmap, */
569 /* except that each pixel takes 4 bits instead of 1. */
570 int
ega_copy_color(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)571 ega_copy_color(gx_device * dev,
572 const byte * base, int sourcex, int raster, gx_bitmap_id id,
573 int x, int y, int w, int h)
574 {
575 const byte *line = base + (sourcex >> 1);
576 unsigned mask = 0x80 >> (x & 7);
577 int px = sourcex & 1;
578 fb_ptr fb_line;
579 int fb_raster = fb_dev->raster;
580
581 fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
582 fb_line = mk_fb_ptr(x, y);
583 set_g_mode(gm_FILL);
584 select_g_mask();
585 for (;; px++) {
586 const byte *bptr = line;
587 fb_ptr fbptr = fb_line;
588 int py = h;
589
590 out_g_mask(mask);
591 if (px & 1) {
592 do {
593 byte_discard(*fbptr); /* latch frame buffer data */
594 *fbptr = *bptr;
595 bptr += raster;
596 fbptr += fb_raster;
597 }
598 while (--py);
599 line++;
600 } else {
601 do {
602 byte_discard(*fbptr); /* latch frame buffer data */
603 *fbptr = *bptr >> 4;
604 bptr += raster;
605 fbptr += fb_raster;
606 }
607 while (--py);
608 }
609 if (!--w)
610 break;
611 if ((mask >>= 1) == 0)
612 mask = 0x80, fb_line++;
613 }
614 set_g_mode(gm_DATA);
615 dot_end();
616 return 0;
617 }
618
619 /* Fill a rectangle. */
620 int
ega_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)621 ega_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
622 gx_color_index color)
623 {
624 rop_params params;
625
626 fit_fill(dev, x, y, w, h);
627 params.dest = mk_fb_ptr(x, y);
628 if (h == 1)
629 fill_row_only(params.dest, x & 7, w, (int)color);
630 else {
631 params.draster = fb_dev->raster;
632 params.height = h;
633 fill_rectangle((rop_ptr) & params, x & 7, w, (int)color);
634 dot_end();
635 }
636 return 0;
637 }
638
639 /* Tile a rectangle. Note that the two colors must both be supplied, */
640 /* i.e. neither one can be gx_no_color_index (transparent): */
641 /* a transparent color means that the tile is colored, not a mask. */
642 int
ega_tile_rectangle(gx_device * dev,const gx_tile_bitmap * tile,int x,int y,int w,int h,gx_color_index czero,gx_color_index cone,int px,int py)643 ega_tile_rectangle(gx_device * dev, const gx_tile_bitmap * tile,
644 int x, int y, int w, int h, gx_color_index czero, gx_color_index cone,
645 int px, int py)
646 #define zero (int)czero
647 #define one (int)cone
648 {
649 rop_params params;
650 int xmod, width_bytes;
651 int tile_height = tile->size.y;
652 int xbit;
653 int lcount;
654 int mask, rmask;
655 byte narrow;
656 byte again;
657 int const_bits, maps;
658 int ymod, yleft;
659
660 fit_fill(dev, x, y, w, h);
661 /* We only handle the easiest cases directly. */
662 if ((tile->size.x & 7) || one == -1 || zero == -1 || px || py)
663 return gx_default_tile_rectangle(dev, tile, x, y, w, h,
664 czero, cone, px, py);
665 /* Following is similar to aligned case of copy_mono */
666 params.dest = mk_fb_ptr(x, y);
667 params.draster = fb_dev->raster;
668 params.sraster = tile->raster;
669 params.shift = 0;
670 xbit = x & 7;
671 /* Set up the graphics registers */
672 const_bits = (zero ^ one) ^ 0xf;
673 if (const_bits) {
674 set_g_const(zero); /* either color will do */
675 set_g_const_map(const_bits);
676 }
677 if ((maps = zero & ~one) != 0) {
678 set_s_map(maps += const_bits);
679 params.invert = -1;
680 again = one & ~zero;
681 } else {
682 maps = one & ~zero;
683 set_s_map(maps += const_bits);
684 params.invert = 0;
685 again = 0;
686 }
687 xmod = (x % tile->size.x) >> 3;
688 width_bytes = tile->size.x >> 3;
689 mask = 0xff >> xbit;
690 if (w + xbit <= 8)
691 mask -= mask >> w,
692 rmask = 0,
693 narrow = 1;
694 else {
695 rmask = (0xff00 >> ((w + x) & 7)) & 0xff;
696 if (xbit)
697 w += xbit - 8;
698 else
699 mask = 0, --xmod, --params.dest;
700 narrow = 0;
701 }
702 ymod = y % tile_height;
703 tile:yleft = tile_height - ymod;
704 params.src = tile->data + ymod * params.sraster + xmod;
705 lcount = h;
706 if (narrow) { /* Optimize narrow case */
707 set_g_mask(mask);
708 if (lcount > yleft) {
709 params.height = yleft;
710 memrwcol0((rop_ptr) & params);
711 params.dest += yleft * params.draster;
712 params.src = tile->data + xmod;
713 params.height = tile_height;
714 lcount -= yleft;
715 while (lcount >= tile_height) {
716 memrwcol0((rop_ptr) & params);
717 params.dest += tile_height * params.draster;
718 lcount -= tile_height;
719 }
720 }
721 if (lcount) {
722 params.height = lcount;
723 memrwcol0((rop_ptr) & params);
724 }
725 } else {
726 fb_ptr line = params.dest;
727 int xpos = width_bytes - xmod;
728
729 while (1) {
730 int xleft = xpos;
731 int count = w;
732
733 params.height = (lcount > yleft ? yleft : lcount);
734 /* Do first byte, if not a full byte. */
735 if (mask) {
736 set_g_mask(mask);
737 memrwcol0((rop_ptr) & params);
738 }
739 /* Do full bytes */
740 if ((count -= 8) >= 0) {
741 set_g_mask(0xff);
742 do {
743 if (!--xleft)
744 xleft = width_bytes,
745 params.src -= width_bytes;
746 ++params.src, ++params.dest;
747 memrwcol0((rop_ptr) & params);
748 }
749 while ((count -= 8) >= 0);
750 }
751 /* Do last byte */
752 if (rmask) {
753 if (!--xleft)
754 xleft = width_bytes,
755 params.src -= width_bytes;
756 set_g_mask(rmask);
757 ++params.src, ++params.dest;
758 memrwcol0((rop_ptr) & params);
759 }
760 if ((lcount -= params.height) == 0)
761 break;
762 params.dest = line += params.height * params.draster;
763 params.src = tile->data + xmod;
764 yleft = tile_height;
765 }
766 }
767 /* Now do the second color if needed */
768 if (again) {
769 maps = again + const_bits;
770 set_s_map(maps);
771 again = 0;
772 params.dest = mk_fb_ptr(x, y);
773 if (mask == 0)
774 params.dest--;
775 params.invert = 0;
776 goto tile;
777 }
778 if (maps != 0xf)
779 set_s_map(-1);
780 if (const_bits)
781 set_g_const_map(0);
782 dot_end();
783 return 0;
784 }
785
786 /* Read scan lines back from the frame buffer. */
787 int
ega_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)788 ega_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
789 { /* The maximum width for an EGA/VGA device is 800 pixels.... */
790 int width_bytes = (dev->width + 7) >> 3;
791 int i;
792 bits32 *dest;
793 const byte *src;
794 const byte *end;
795 byte planes[100 * 4];
796
797 /* Plane 0 is the least significant plane. */
798 /* We know we're on a little-endian machine.... */
799 #define spread4(v)\
800 v+0x00000000, v+0x08000000, v+0x80000000, v+0x88000000,\
801 v+0x00080000, v+0x08080000, v+0x80080000, v+0x88080000,\
802 v+0x00800000, v+0x08800000, v+0x80800000, v+0x88800000,\
803 v+0x00880000, v+0x08880000, v+0x80880000, v+0x88880000
804 static const bits32 spread8[256] =
805 {spread4(0x0000), spread4(0x0800),
806 spread4(0x8000), spread4(0x8800),
807 spread4(0x0008), spread4(0x0808),
808 spread4(0x8008), spread4(0x8808),
809 spread4(0x0080), spread4(0x0880),
810 spread4(0x8080), spread4(0x8880),
811 spread4(0x0088), spread4(0x0888),
812 spread4(0x8088), spread4(0x8888)
813 };
814
815 if (y < 0 || y >= dev->height || dev->width > 800)
816 return_error(gs_error_rangecheck);
817 /* Read 4 planes into the holding buffer. */
818 for (i = 0; i < 4; ++i) {
819 set_g_read_plane(i);
820 memcpy(planes + 100 * i, mk_fb_ptr(0, y), width_bytes);
821 }
822 /* Now assemble the final data from the planes. */
823 for (dest = (bits32 *) data, src = planes, end = src + width_bytes;
824 src < end; ++dest, ++src
825 )
826 *dest = (((((spread8[src[0]] >> 1) | spread8[src[100]]) >> 1) |
827 spread8[src[200]]) >> 1) | spread8[src[300]];
828 if (actual_data != 0)
829 *actual_data = data;
830 return 0;
831 }
832
833 /* ------ Internal routines ------ */
834
835 /* Mask table for rectangle fill. */
836 static const byte rmask_tab[9] =
837 {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
838 };
839
840 /* Fill a rectangle specified by pointer into frame buffer, */
841 /* starting bit within byte, width, and height. */
842 /* Smashes rop->dest. */
843 private void
fill_rectangle(register rop_ptr rop,int bit,int w,int color)844 fill_rectangle(register rop_ptr rop, int bit, int w, int color)
845 /* rop: dest, draster, height */
846 {
847 set_g_const(color);
848 set_g_const_map(0xf);
849 select_g_mask();
850 if (bit + w <= 8) { /* Less than one byte */
851 out_g_mask(rmask_tab[w] >> bit);
852 memsetcol(rop);
853 } else {
854 byte right_mask;
855
856 if (bit) {
857 out_g_mask(0xff >> bit);
858 memsetcol(rop);
859 rop->dest++;
860 w += bit - 8;
861 }
862 if (w >= 8) {
863 out_g_mask(0xff); /* all bits */
864 rop->width = w >> 3;
865 memsetrect(rop);
866 rop->dest += rop->width;
867 w &= 7;
868 }
869 if ((right_mask = rmask_tab[w]) != 0) {
870 out_g_mask(right_mask);
871 memsetcol(rop);
872 }
873 }
874 set_g_const_map(0);
875 }
876
877 /* Fill a single row specified by pointer into frame buffer, */
878 /* starting bit within byte, and width; clean up afterwards. */
879 #define r_m_w(ptr) (*(ptr))++ /* read & write, data irrelevant */
880 private void
fill_row_only(byte * dest,int bit,int w,int color)881 fill_row_only(byte * dest, int bit, int w, int color)
882 /* rop: dest */
883 {
884 if (bit + w <= 8) { /* Less than one byte. */
885 /* Optimize filling with black or white. */
886 switch (color) {
887 case 0:
888 set_g_mask(rmask_tab[w] >> bit);
889 *dest &= color; /* read, then write 0s; */
890 /* some compilers optimize &= 0 to a store. */
891 out_g_mask(0xff); /* dot_end */
892 break;
893 case 0xf:
894 set_g_mask(rmask_tab[w] >> bit);
895 *dest |= 0xff; /* read, then write 1s; */
896 /* some compilers optimize &= 0 to a store. */
897 out_g_mask(0xff); /* dot_end */
898 break;
899 default:
900 set_g_const(color);
901 set_g_const_map(0xf);
902 set_g_mask(rmask_tab[w] >> bit);
903 r_m_w(dest);
904 out_g_mask(0xff); /* dot_end */
905 set_g_const_map(0);
906 }
907 } else {
908 byte right_mask;
909 int byte_count;
910
911 set_g_const(color);
912 set_g_const_map(0xf);
913 select_g_mask();
914 if (bit) {
915 out_g_mask(0xff >> bit);
916 r_m_w(dest);
917 dest++;
918 w += bit - 8;
919 }
920 byte_count = w >> 3;
921 if ((right_mask = rmask_tab[w & 7]) != 0) {
922 out_g_mask(right_mask);
923 r_m_w(dest + byte_count);
924 }
925 out_g_mask(0xff);
926 if (byte_count) {
927 memset(dest, 0, byte_count); /* data irrelevant */
928 }
929 set_g_const_map(0);
930 }
931 }
932