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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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