Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}