wdvi

network DVI viewer
Log | Files | Refs

dvi-draw.c (35817B)


      1 /*========================================================================*\
      2 
      3 Copyright (c) 1990-2013  Paul Vojta
      4 
      5 Permission is hereby granted, free of charge, to any person obtaining a copy
      6 of this software and associated documentation files (the "Software"), to
      7 deal in the Software without restriction, including without limitation the
      8 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      9 sell copies of the Software, and to permit persons to whom the Software is
     10 furnished to do so, subject to the following conditions:
     11 
     12 The above copyright notice and this permission notice shall be included in
     13 all copies or substantial portions of the Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     18 IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
     19 THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     22 IN THE SOFTWARE.
     23 
     24 NOTE:
     25 	xdvi is based on prior work, as noted in the modification history
     26 	in xdvi.c.
     27 
     28 \*========================================================================*/
     29 
     30 #include <err.h>
     31 #include <ctype.h>
     32 #include <stdarg.h>
     33 
     34 #include "dvi-draw.h"	/* drawing_mag */
     35 #include "dvi-init.h"	/* page_info */
     36 #include "events.h"	/* do_color_change(), ... */
     37 #include "font.h"	/* load_ft_font() XXX more */
     38 #include "special.h"	/* scan_special(), ... */
     39 #include "util.h"	/* xfopen(), snum() */
     40 #include "xdvi.h"
     41 #include "dvi.h"
     42 
     43 
     44 static	struct frame	frame0;		/* dummy head of list */
     45 
     46 #define	DVI_BUFFER_LEN	512
     47 static	unsigned char	dvi_buffer[DVI_BUFFER_LEN];
     48 static	struct frame	*current_frame;
     49 
     50 /* Points to drawinf record containing current dvi file location (for update by
     51    geom_scan).  */
     52 static	struct drawinf	*dvi_pointer_frame	= NULL;
     53 
     54 /*
     55  *	Explanation of the following constant:
     56  *	offset_[xy]   << 16:	margin (defaults to one inch)
     57  *	shrink_factor << 16:	one pixel page border
     58  *	shrink_factor << 15:	rounding for pixel_conv
     59  */
     60 #define OFFSET_X	(offset_x << 16) + (shrink_factor * 3 << 15)
     61 #define OFFSET_Y	(offset_y << 16) + (shrink_factor * 3 << 15)
     62 
     63 BMUNIT	bit_masks[33] = {
     64 	0x0,		0x1,		0x3,		0x7,
     65 	0xf,		0x1f,		0x3f,		0x7f,
     66 	0xff,		0x1ff,		0x3ff,		0x7ff,
     67 	0xfff,		0x1fff,		0x3fff,		0x7fff,
     68 	0xffff,		0x1ffff,	0x3ffff,	0x7ffff,
     69 	0xfffff,	0x1fffff,	0x3fffff,	0x7fffff,
     70 	0xffffff,	0x1ffffff,	0x3ffffff,	0x7ffffff,
     71 	0xfffffff,	0x1fffffff,	0x3fffffff,	0x7fffffff,
     72 	0xffffffff
     73 };
     74 
     75 static	void	draw_part(struct frame *, double);
     76 
     77 /*
     78  *	X routines.
     79  */
     80 
     81 /*
     82  *	Put a rectangle on the screen.
     83  */
     84 
     85 static	void
     86 put_rule(int x, int y, unsigned int w, unsigned int h)
     87 {
     88 	if (x >= max_x || x + (int) w < min_x ||
     89 	    y >= max_y || y + (int) h < min_y)
     90 		return;
     91 
     92 	if (fg_active != fg_current)
     93 		do_color_change();
     94 	XFillRectangle(DISP, currwin.win, ruleGC,
     95 	               x - currwin.base_x, y - currwin.base_y,
     96 	               w ? w : 1, h ? h : 1);
     97 }
     98 
     99 static	void
    100 put_bitmap(struct bitmap *bitmap, int x, int y)
    101 {
    102 	if (debug & DBG_BITMAP)
    103 		printf("X(%d,%d)\n", x - currwin.base_x, y - currwin.base_y);
    104 
    105 	if (x >= max_x || x + (int) bitmap->w < min_x ||
    106 	    y >= max_y || y + (int) bitmap->h < min_y)
    107 		return;
    108 
    109 	if (fg_active != fg_current)
    110 		do_color_change();
    111 
    112 	image->width = bitmap->w;
    113 	image->height = bitmap->h;
    114 	image->data = bitmap->bits;
    115 	image->bytes_per_line = bitmap->bytes_wide;
    116 	XPutImage(DISP, currwin.win, foreGC, image,
    117 	          0, 0,
    118 	          x - currwin.base_x, y - currwin.base_y,
    119 	          bitmap->w, bitmap->h);
    120 	if (foreGC2)
    121 		XPutImage(DISP, currwin.win, foreGC2, image,
    122 		          0, 0,
    123 		          x - currwin.base_x, y - currwin.base_y,
    124 		          bitmap->w, bitmap->h);
    125 }
    126 
    127 
    128 static	void	shrink_glyph_grey(struct glyph *);
    129 
    130 static	void
    131 put_image(struct glyph *g, int x, int y)
    132 {
    133 	XImage *img = g->image2;
    134 
    135 	if (x >= max_x || x + img->width < min_x ||
    136 	    y >= max_y || y + img->height < min_y)
    137 		return;
    138 
    139 	if (g->fg != fg_current)	/* if color change since last use */
    140 		shrink_glyph_grey(g);
    141 	else if (fg_active != fg_current)	/* if GCs need updating */
    142 		do_color_change();
    143 	XPutImage(DISP, currwin.win, foreGC, img,
    144 	          0, 0,
    145 	          x - currwin.base_x, y - currwin.base_y,
    146 	          (unsigned int) img->width, (unsigned int) img->height);
    147 	if (foreGC2 != NULL) {
    148 		img->data = g->pixmap2_t;
    149 		XPutImage(DISP, currwin.win, foreGC2, img,
    150 		          0, 0,
    151 		          x - currwin.base_x, y - currwin.base_y,
    152 		          (unsigned int) img->width, (unsigned int) img->height);
    153 		img->data = g->pixmap2;
    154 	}
    155 }
    156 
    157 /*
    158  *	Byte reading routines for dvi file.
    159  */
    160 
    161 static	unsigned char
    162 xxone()
    163 {
    164 	if (currinf.virtual) {
    165 	    ++currinf.pos;
    166 	    return EOP;
    167 	}
    168 	currinf.end = dvi_buffer +
    169 		fread((char *) (currinf.pos = dvi_buffer), 1, DVI_BUFFER_LEN,
    170 			dvi_file);
    171 	return currinf.end > dvi_buffer ? *(currinf.pos)++ : EOF;
    172 }
    173 
    174 #define	xone()  (currinf.pos < currinf.end ? *(currinf.pos)++ : xxone())
    175 
    176 static	unsigned long
    177 xnum(unsigned char size)
    178 {
    179 	long x = 0;
    180 
    181 	while (size--) x = (x << 8) | xone();
    182 	return x;
    183 }
    184 
    185 static	long
    186 xsnum(unsigned char size)
    187 {
    188 	long	x;
    189 
    190 	x = (signed char) xone();
    191 
    192 	while (--size)
    193 		x = (x << 8) | xone();
    194 	return x;
    195 }
    196 
    197 #define	xsfour()	xsnum(4)
    198 
    199 static	void
    200 xskip(long offset)
    201 {
    202 	currinf.pos += offset;
    203 	if (!currinf.virtual && currinf.pos > currinf.end)
    204 	    (void) fseek(dvi_file, (long) (currinf.pos - currinf.end), SEEK_CUR);
    205 }
    206 
    207 static void __attribute__((__noreturn__))
    208 tell_oops(const char *message, ...)
    209 {
    210 	va_list	args;
    211 
    212 	va_start(args, message);
    213 	vwarnx(message, args);
    214 	va_end(args);
    215 
    216 	if (currinf.virtual)
    217 	    warnx("in virtual font '%s'", currinf.virtual->fontname);
    218 	else
    219 #define	xtell(pos)	(ftell(dvi_file) - (currinf.end - (pos)))
    220 	    warnx("offset %ld", xtell(currinf.pos - 1));
    221 	exit(1);
    222 }
    223 
    224 
    225 /*
    226  *	Code for debugging options.
    227  */
    228 
    229 static	void
    230 print_bitmap(struct bitmap *bitmap)
    231 {
    232 	BMUNIT		*ptr	= (BMUNIT *) bitmap->bits;
    233 	int		x, y, i;
    234 
    235 	if (ptr == NULL)
    236 		errx(1, "print_bitmap called with null pointer.");
    237 	printf("w = %d, h = %d, bytes wide = %d\n",
    238 	    bitmap->w, bitmap->h, bitmap->bytes_wide);
    239 	for (y = 0; y < (int) bitmap->h; ++y) {
    240 	    for (x = bitmap->bytes_wide; x > 0; x -= BMBYTES) {
    241 #ifndef	WORDS_BIGENDIAN
    242 		for (i = 0; i < BMBITS; ++i)
    243 #else
    244 		for (i = BMBITS - 1; i >= 0; --i)
    245 #endif
    246 		    putchar((*ptr & (1 << i)) ? '@' : ' ');
    247 		++ptr;
    248 	    }
    249 	    putchar('\n');
    250 	}
    251 }
    252 
    253 static	void
    254 print_char(unsigned char ch, struct glyph *g)
    255 {
    256 	printf("char %d", ch);
    257 	if (isprint(ch))
    258 	    printf(" (%c)", ch);
    259 	putchar('\n');
    260 	printf("x = %d, y = %d, dvi = %ld\n", g->x, g->y, g->dvi_adv);
    261 	print_bitmap(&g->bitmap);
    262 }
    263 
    264 static	const	char	*dvi_table1[] = {
    265 	"SET1", NULL, NULL, NULL, "SETRULE", "PUT1", NULL, NULL,
    266 	NULL, "PUTRULE", "NOP", "BOP", "EOP", "PUSH", "POP", "RIGHT1",
    267 	"RIGHT2", "RIGHT3", "RIGHT4", "W0", "W1", "W2", "W3", "W4",
    268 	"X0", "X1", "X2", "X3", "X4", "DOWN1", "DOWN2", "DOWN3",
    269 	"DOWN4", "Y0", "Y1", "Y2", "Y3", "Y4", "Z0", "Z1",
    270 	"Z2", "Z3", "Z4"};
    271 
    272 static	const	char	*dvi_table2[] = {
    273 	"FNT1", "FNT2", "FNT3", "FNT4", "XXX1", "XXX2", "XXX3", "XXX4",
    274 	"FNTDEF1", "FNTDEF2", "FNTDEF3", "FNTDEF4", "PRE", "POST", "POSTPOST",
    275 	"SREFL", "EREFL", NULL, NULL, NULL, NULL};
    276 
    277 static	void
    278 print_dvi(unsigned char ch)
    279 {
    280 	const	char	*s;
    281 
    282 	printf("%4d %4d ", PXL_H, PXL_V);
    283 	if (ch <= (unsigned char) (SETCHAR0 + 127)) {
    284 		printf("SETCHAR%-3d", ch - SETCHAR0);
    285 		if (isprint(ch))
    286 			printf(" (%c)", ch);
    287 		putchar('\n');
    288 		return;
    289 	}
    290 	else if (ch < FNTNUM0)
    291 		s = dvi_table1[ch - 128];
    292 	else if (ch <= (unsigned char) (FNTNUM0 + 63)) {
    293 		printf("FNTNUM%d\n", ch - FNTNUM0);
    294 		return;
    295 	}
    296 	else
    297 		s = dvi_table2[ch - (FNTNUM0 + 64)];
    298 
    299 	if (s)
    300 		puts(s);
    301 	else
    302 		tell_oops("unknown op-code %d", ch);
    303 }
    304 
    305 
    306 /*
    307  *	Count the number of set bits in a given region of the bitmap
    308  */
    309 
    310 static	char	sample_count[]	= {0, 1, 1, 2, 1, 2, 2, 3,
    311 				   1, 2, 2, 3, 2, 3, 3, 4};
    312 
    313 static	int
    314 sample(BMUNIT *bits, int bytes_wide, int bit_skip, int w, int h)
    315 {
    316 	BMUNIT	*ptr, *endp;
    317 	BMUNIT	*cp;
    318 	int	bits_left;
    319 	int	n, bit_shift, wid;
    320 
    321 	ptr = bits + bit_skip / BMBITS;
    322 	endp = ADD(bits, h * bytes_wide);
    323 	bits_left = w;
    324 #ifndef	WORDS_BIGENDIAN
    325 	bit_shift = bit_skip % BMBITS;
    326 #else
    327 	bit_shift = BMBITS - bit_skip % BMBITS;
    328 #endif
    329 	n = 0;
    330 	while (bits_left) {
    331 #ifndef	WORDS_BIGENDIAN
    332 		wid = BMBITS - bit_shift;
    333 #else
    334 		wid = bit_shift;
    335 #endif
    336 		if (wid > bits_left)
    337 			wid = bits_left;
    338 		if (wid > 4)
    339 			wid = 4;
    340 #ifdef	WORDS_BIGENDIAN
    341 		bit_shift -= wid;
    342 #endif
    343 		for (cp = ptr; cp < endp; cp = ADD(cp, bytes_wide))
    344 			n += sample_count[(*cp >> bit_shift) & bit_masks[wid]];
    345 #ifndef	WORDS_BIGENDIAN
    346 		bit_shift += wid;
    347 		if (bit_shift == BMBITS) {
    348 			bit_shift = 0;
    349 			++ptr;
    350 	    	}
    351 #else
    352 		if (bit_shift == 0) {
    353 			bit_shift = BMBITS;
    354 			++ptr;
    355 		}
    356 #endif
    357 		bits_left -= wid;
    358 	}
    359 	return n;
    360 }
    361 
    362 
    363 static	void
    364 shrink_glyph_grey(struct glyph *g)
    365 {
    366 	int		rows_left, rows, init_cols;
    367 	int		cols_left;
    368 	int		cols;
    369 	int		x, y;
    370 	long		thesample;
    371 	BMUNIT		*old_ptr;
    372 	unsigned int	size;
    373 	int		rtmp;
    374 	unsigned int	depth;
    375 
    376 	if (fg_active != fg_current)
    377 		do_color_change();
    378 
    379 	/* These machinations ensure that the character is shrunk according to
    380 	   its hot point, rather than its upper left-hand corner. */
    381 	g->x2 = g->x / shrink_factor;
    382 	init_cols = g->x - g->x2 * shrink_factor;
    383 	if (init_cols <= 0)
    384 		init_cols += shrink_factor;
    385 	else
    386 		++g->x2;
    387 	g->bitmap2.w = g->x2 + ROUNDUP((int) g->bitmap.w - g->x, shrink_factor);
    388 	/* include row zero with the positively numbered rows */
    389 	rtmp = g->y + 1;
    390 	g->y2 = rtmp / shrink_factor;
    391 	rows = rtmp - g->y2 * shrink_factor;
    392 	if (rows <= 0) {
    393 		rows += shrink_factor;
    394 		--g->y2;
    395 	}
    396 	g->bitmap2.h = g->y2 + ROUNDUP((int) g->bitmap.h - rtmp, shrink_factor) + 1;
    397 
    398 	if (g->pixmap2 == NULL) {
    399 		depth = DefaultDepthOfScreen(SCRN);
    400 		g->image2 = XCreateImage(DISP, CopyFromParent, depth, ZPixmap, 0,
    401 		                         (char *) NULL, g->bitmap2.w, g->bitmap2.h,
    402 		                         BMBITS, 0);
    403 		size = g->image2->bytes_per_line * g->bitmap2.h;
    404 		g->pixmap2 = g->image2->data = xmalloc(size != 0 ? size : 1);
    405 	}
    406 	if (foreGC2 != NULL && g->pixmap2_t == NULL) {
    407 		size = g->image2->bytes_per_line * g->bitmap2.h;
    408 		g->pixmap2_t = xmalloc(size != 0 ? size : 1);
    409 	}
    410 
    411 	old_ptr = (BMUNIT *) g->bitmap.bits;
    412 	rows_left = g->bitmap.h;
    413 	y = 0;
    414 	while (rows_left) {
    415 		x = 0;
    416 		if (rows > rows_left) rows = rows_left;
    417 		cols_left = g->bitmap.w;
    418 		cols = init_cols;
    419 		while (cols_left) {
    420 			if (cols > cols_left) cols = cols_left;
    421 
    422 			thesample = sample(old_ptr, g->bitmap.bytes_wide,
    423 			                   (int) g->bitmap.w - cols_left, cols, rows);
    424 			XPutPixel(g->image2, x, y, pixeltbl[thesample]);
    425 			if (foreGC2 != NULL) {
    426 				g->image2->data = g->pixmap2_t;
    427 				XPutPixel(g->image2, x, y, pixeltbl_t[thesample]);
    428 				g->image2->data = g->pixmap2;
    429 			}
    430 
    431 			cols_left -= cols;
    432 			cols = shrink_factor;
    433 			x++;
    434 	    	}
    435 		*((char **) &old_ptr) += rows * g->bitmap.bytes_wide;
    436 		rows_left -= rows;
    437 		rows = shrink_factor;
    438 		y++;
    439 	}
    440 
    441 	while (y < (int) g->bitmap2.h) {
    442 		for (x = 0; x < (int) g->bitmap2.w; x++) {
    443 			XPutPixel(g->image2, x, y, *pixeltbl);
    444 			if (foreGC2 != NULL) {
    445 				g->image2->data = g->pixmap2_t;
    446 				XPutPixel(g->image2, x, y, *pixeltbl_t);
    447 				g->image2->data = g->pixmap2;
    448 			}
    449 		}
    450 	    	y++;
    451 	}
    452 
    453 	g->y2 = g->y / shrink_factor;
    454 	g->fg = fg_current;
    455 }
    456 
    457 /*
    458  *	Find font #n.
    459  */
    460 
    461 static	void
    462 change_font(unsigned long n)
    463 {
    464 	struct tn	*tnp;
    465 
    466 	if (n < currinf.tn_table_len)
    467 		currinf.fontp = currinf.tn_table[n];
    468 	else {
    469 		currinf.fontp = NULL;
    470 		for (tnp = currinf.tn_head; tnp != NULL; tnp = tnp->next)
    471 			if (tnp->TeXnumber == n) {
    472 				currinf.fontp = tnp->fontp;
    473 				break;
    474 			}
    475 	}
    476 	if (currinf.fontp == NULL)
    477 		tell_oops("non-existent font #%d", n);
    478 	maxchar = currinf.fontp->maxchar;
    479 	currinf.set_char_p = currinf.fontp->set_char_p;
    480 }
    481 
    482 
    483 /*
    484  *	Open a font file.
    485  */
    486 
    487 void
    488 open_font_file(struct font *fontp)
    489 {
    490 	if (fontp->file != NULL)
    491 		return;
    492 
    493 	fontp->file = xfopen(fontp->filename, "r");
    494 	if (fontp->file == NULL)
    495 		errx(1, "Font file disappeared: '%s'", fontp->filename);
    496 }
    497 
    498 /*
    499  *	Read special string.
    500  */
    501 
    502 static	char *
    503 read_special(long nbytes)
    504 {
    505 	static	char	*spcl	= NULL;
    506 	static	long	spcl_len = -1;
    507 	char	*p;
    508 
    509 	if (spcl_len < nbytes) {
    510 		if (spcl != NULL)
    511 			free(spcl);
    512 		spcl = xmalloc((unsigned) nbytes + 1);
    513 		spcl_len = nbytes;
    514 	}
    515 	p = spcl;
    516 	for (;;) {
    517 		int i = currinf.end - currinf.pos;
    518 
    519 		if (i > nbytes)
    520 			i = nbytes;
    521 		bcopy((char *) currinf.pos, p, i);
    522 		currinf.pos += i;
    523 		p += i;
    524 		nbytes -= i;
    525 		if (nbytes == 0)
    526 			break;
    527 		(void) xxone();
    528 		--currinf.pos;
    529 	}
    530 	*p = '\0';
    531 	return spcl;
    532 }
    533 
    534 
    535 /*
    536  *	Table used for scanning.  If >= 0, then skip that many bytes.
    537  *	M1 means end of page, M2 means special, M3 means FNTDEF,
    538  *	M4 means unrecognizable, and M5 means doesn't belong here.
    539  */
    540 
    541 #define	M1	255
    542 #define	M2	254
    543 #define	M3	253
    544 #define	M4	252
    545 #define	M5	251
    546 #define	MM	251
    547 
    548 static	unsigned char	scantable[256] = {
    549 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	/* chars 0 - 127 */
    550 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    551 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    552 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    553 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    554 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    555 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    556 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    557 	1,M4,			/* SET1,- (128,129) */
    558 			/* -,-,SETRULE,PUT1,-,-,-,PUTRULE,NOP,BOP (130-139) */
    559 	M4,M4,8,1,M4,M4,M4,8,0,44,
    560 	M1,0,0,1,2,3,4,0,1,2,	/* EOP,PUSH,POP,RIGHT1-4,W0M2 (140-149) */
    561 	3,4,0,1,2,3,4,1,2,3,	/* W3-4,X0-4,DOWN1-3 (150-159) */
    562 	4,0,1,2,3,4,0,1,2,3,	/* DOWN4,Y0-4,Z0-3 (160-169) */
    563 	4,			/* Z4 (170) */
    564 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	/* change font 171 - 234 */
    565 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    566 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    567 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    568 	1,2,3,4,M2,		/* FNT1-4,XXX1 (235-239) */
    569 			/* XXX2-4,FNTDEF1-4,PRE,POST,POSTPOST (240-249) */
    570 	M2,M2,M2,M3,M3,M3,M3,M5,M5,M5,
    571 	0,0,M4,M4,M4,M4};	/* SREFL,EREFL,-,-,-,- (250-255) */
    572 
    573 /*
    574  *	This is the generic scanning routine.  It assumes that currinf, etc.
    575  *	are ready to go at the start of the page to be scanned.
    576  */
    577 
    578 static	void
    579 spcl_scan(void (*spcl_proc)(char *))
    580 {
    581 	unsigned char	ch;
    582 	unsigned char	n;
    583 	long	a;
    584 
    585 	for (;;) {
    586 	    ch = xone();
    587 	    n = scantable[ch];
    588 	    if (n < MM)
    589 		while (n-- != 0)
    590 		    (void) xone();
    591 	    else if (n == M1) break;	/* end of page */
    592 	    else switch (n) {
    593 		case M2:	/* special */
    594 		    a = xnum(ch - XXX1 + 1);
    595 		    if (a > 0)
    596 			spcl_proc(read_special(a));
    597 		    break;
    598 		case M3:	/* FNTDEF */
    599 		    xskip((long) (12 + ch - FNTDEF1 + 1));
    600 		    ch = xone();
    601 		    xskip((long) ch + (long) xone());
    602 		    break;
    603 		case M4:	/* unrecognizable */
    604 		    tell_oops("unknown op-code %d", ch);
    605 		    break;
    606 		case M5:	/* doesn't belong */
    607 		    tell_oops("shouldn't happen: %s encountered",
    608 		      dvi_table2[ch - (FNTNUM0 + 64)]);
    609 		    break;
    610 	    }
    611 	}
    612 }
    613 
    614 
    615 /*
    616  *	Size of page interval for "Scanning pages xx-xx" message.
    617  */
    618 
    619 #ifndef	REPORT_INCR
    620 #define	REPORT_INCR	50
    621 #endif
    622 
    623 /*
    624  *	Prescanning routine for dvi file.  This looks for specials like
    625  *	`header=' and `!'.
    626  */
    627 
    628 void
    629 prescan(void)
    630 {
    631 	int	nextreportpage;
    632 
    633 	nextreportpage = scanned_page;
    634 	if (fseek(dvi_file, page_info[scanned_page + 1].offset, SEEK_SET) != 0)
    635 		err(1, "fseek");
    636 	currinf.pos = currinf.end = dvi_buffer;
    637 
    638 	for (;;) {
    639 	    page_info[scanned_page + 1].pw = page_info[scanned_page].pw;
    640 	    page_info[scanned_page + 1].ph = page_info[scanned_page].ph;
    641 	    page_info[scanned_page + 1].ww = page_info[scanned_page].ww;
    642 	    page_info[scanned_page + 1].wh = page_info[scanned_page].wh;
    643 
    644 	    if (debug & DBG_PS)
    645 		printf("Scanning page %d\n", scanned_page + 1);
    646 	    if (scanned_page >= nextreportpage) {
    647 		nextreportpage += REPORT_INCR;
    648 		if (nextreportpage > current_page)
    649 		    nextreportpage = current_page;
    650 	    }
    651 
    652 	    /* No calls to read_events() occur in this case.  */
    653 	    spcl_scan(scan_special);
    654 
    655 	    ++scanned_page;
    656 	    if (scanned_page_color < scanned_page) {
    657 		scan_color_eop();
    658 		scanned_page_color = scanned_page;
    659 	    }
    660 
    661 	    if (scanned_page >= current_page) break;
    662 	}
    663 }
    664 
    665 /*
    666  *	Routines to print characters.
    667  */
    668 
    669 long
    670 set_char(unsigned char ch)
    671 {
    672 	struct glyph	*g;
    673 
    674 	if (ch > maxchar) realloc_font(currinf.fontp, ch);
    675 	if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
    676 	    if (g->addr == 0) {
    677 		warnx("Character %d not defined in font '%s'", ch,
    678 			currinf.fontp->fontname);
    679 		g->addr = -1;
    680 		return 0L;
    681 	    }
    682 	    if (g->addr == -1)
    683 		return 0L;	/* previously flagged missing char */
    684 	    if (currinf.fontp->ft == NULL)	/* if not freetype font */
    685 	    {
    686 		open_font_file(currinf.fontp);
    687 		if (fseek(currinf.fontp->file, g->addr, SEEK_SET) != 0)
    688 			err(1, "fseek");
    689 	    }
    690 	    (*currinf.fontp->read_char)(currinf.fontp, ch);
    691 	    if (debug & DBG_BITMAP) print_char((unsigned char) ch, g);
    692 	    currinf.fontp->timestamp = ++current_timestamp;
    693 	}
    694 
    695 	    if (shrink_factor == 1)
    696 		put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
    697 	    else {
    698 		/*
    699 		 * use_grey
    700 		 */
    701 		if (g->pixmap2 == NULL) {
    702 			shrink_glyph_grey(g);
    703 		}
    704 		put_image(g, PXL_H - g->x2, PXL_V - g->y2);
    705 	    }
    706 	return g->dvi_adv;
    707 }
    708 
    709 
    710 static	long
    711 set_empty_char(unsigned char ch)
    712 {
    713 	return 0;
    714 }
    715 
    716 
    717 long
    718 load_n_set_char(unsigned char ch)
    719 {
    720 	if (!load_font(currinf.fontp)) {	/* if not found */
    721 	    warnx("Character(s) will be left blank.");
    722 	    currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
    723 	    return 0;
    724 	}
    725 	maxchar = currinf.fontp->maxchar;
    726 	currinf.set_char_p = currinf.fontp->set_char_p;
    727 	return (*currinf.set_char_p)(ch);
    728 }
    729 
    730 
    731 long
    732 set_vf_char(unsigned char ch)
    733 {
    734 	struct macro	*m;
    735 	struct drawinf	oldinfo;
    736 	unsigned char	oldmaxchar;
    737 	static	unsigned char	c;
    738 
    739 	if (ch > maxchar) realloc_virtual_font(currinf.fontp, ch);
    740 	if ((m = &currinf.fontp->macro[ch])->pos == NULL) {
    741 	    warnx("Character %d not defined in font '%s'", ch,
    742 		    currinf.fontp->fontname);
    743 	    m->pos = m->end = &c;
    744 	    return 0L;
    745 	}
    746 	    oldinfo = currinf;
    747 	    if (!currinf.virtual)
    748 		dvi_pointer_frame = &oldinfo;
    749 	    oldmaxchar = maxchar;
    750 	    WW = XX = YY = ZZ = 0;
    751 	    currinf.tn_table_len = VFTABLELEN;
    752 	    currinf.tn_table = currinf.fontp->vf_table;
    753 	    currinf.tn_head = currinf.fontp->vf_chain;
    754 	    currinf.pos = m->pos;
    755 	    currinf.end = m->end;
    756 	    currinf.virtual = currinf.fontp;
    757 	    draw_part(current_frame, currinf.fontp->dimconv);
    758 	    if (currinf.pos != currinf.end + 1)
    759 		tell_oops("virtual character macro does not end correctly");
    760 	    currinf = oldinfo;
    761 	    if (!currinf.virtual)
    762 		dvi_pointer_frame = &currinf;
    763 	    maxchar = oldmaxchar;
    764 	return m->dvi_adv;
    765 }
    766 
    767 
    768 
    769 /*
    770  *	set_ft_char() is used as a set_char routine to handle delayed loading
    771  *	of freetype fonts.  See more details in ft.c.
    772  */
    773 
    774 static void
    775 do_load_freetype_font(void)
    776 {
    777 	struct ftfont *ftp;
    778 
    779 	if (load_ft_font(currinf.fontp)) {
    780 		currinf.set_char_p = currinf.fontp->set_char_p = set_char;
    781 		return;
    782 	}
    783 
    784 	/* Revert to non-scalable font */
    785 	if (debug & DBG_OPEN)
    786 		printf(
    787 		  "Font %s is not loadable; reverting to non-scalable font\n",
    788 		  currinf.fontp->fontname);
    789 
    790 	ftp = currinf.fontp->ft;
    791 	ftp->t1->bad = True;
    792 	if (currinf.fontp == ftp->first_size) {
    793 		if (currinf.fontp->next_size == NULL) {
    794 			/* if this is the only size of this font face */
    795 			ftp->t1->ft = NULL;
    796 			free(ftp);
    797 		}
    798 		else {
    799 			struct font	*fontp2;
    800 
    801 			ftp->first_size = fontp2 = currinf.fontp->next_size;
    802 			/*
    803 			 * Opening the file might have succeeded at some other size,
    804 			 * so we need to transfer that information to the next
    805 			 * record in case it was put here.
    806 			 */
    807 			fontp2->file = currinf.fontp->file;
    808 			currinf.fontp->file = NULL;
    809 			fontp2->filename = currinf.fontp->filename;
    810 			currinf.fontp->filename = NULL;
    811 			fontp2->timestamp = currinf.fontp->timestamp;
    812 		}
    813 	}
    814 	else {
    815 		struct font *fontp2;
    816 
    817 		fontp2 = ftp->first_size;
    818 		while (fontp2->next_size != currinf.fontp)
    819 			fontp2 = fontp2->next_size;
    820 		fontp2->next_size = currinf.fontp->next_size;
    821 	}
    822 	currinf.fontp->ft = NULL;
    823 	/* The virtual font machinery will take it from here.  */
    824 	/* That will call load_font(), but it won't take us back to the */
    825 	/* freetype font, because that font will have been marked bad.  */
    826 	currinf.set_char_p = load_n_set_char;
    827 }
    828 
    829 long
    830 set_ft_char(unsigned char ch)
    831 {
    832 	do_load_freetype_font();
    833 
    834 	return (*currinf.set_char_p)(ch);
    835 }
    836 
    837 
    838 
    839 static	long
    840 set_no_char(unsigned char ch)
    841 {
    842 	if (currinf.virtual) {
    843 	    currinf.fontp = currinf.virtual->first_font;
    844 	    if (currinf.fontp != NULL) {
    845 		maxchar = currinf.fontp->maxchar;
    846 		currinf.set_char_p = currinf.fontp->set_char_p;
    847 		return (*currinf.set_char_p)(ch);
    848 	    }
    849 	}
    850 	tell_oops("attempt to set character of unknown font");
    851 }
    852 
    853 
    854 /*
    855  *	Set rule.  Arguments are coordinates of lower left corner.
    856  */
    857 
    858 static	void
    859 set_rule(int h, int w)
    860 {
    861 	put_rule(PXL_H, PXL_V - h + 1, (unsigned int) w, (unsigned int) h);
    862 }
    863 
    864 
    865 /*
    866  *	Interpret a sequence of dvi bytes (either the page from the dvi file,
    867  *	or a character from a virtual font).
    868  */
    869 
    870 #define	xspell_conv(n)	spell_conv0(n, current_dimconv)
    871 
    872 static	void
    873 draw_part(struct frame *minframe, double current_dimconv)
    874 {
    875 	unsigned char ch;
    876 
    877 	currinf.fontp = NULL;
    878 	currinf.set_char_p = set_no_char;
    879 	for (;;) {
    880 	    ch = xone();
    881 	    if (debug & DBG_DVI)
    882 		print_dvi(ch);
    883 	    if (ch <= (unsigned char) (SETCHAR0 + 127))
    884 		DVI_H += (*currinf.set_char_p)(ch);
    885 	    else if (FNTNUM0 <= ch && ch <= (unsigned char) (FNTNUM0 + 63))
    886 		change_font((unsigned long) (ch - FNTNUM0));
    887 	    else {
    888 		long a, b;
    889 
    890 		switch (ch) {
    891 		    case SET1:
    892 		    case PUT1:
    893 			a = (*currinf.set_char_p)(xone());
    894 			if (ch != PUT1) DVI_H += a;
    895 			break;
    896 
    897 		    case SETRULE:
    898 			/* Be careful, dvicopy outputs rules with
    899 			   height = 0x80000000.  We don't want any
    900 			   SIGFPE here. */
    901 			a = xsfour();
    902 			b = xspell_conv(xsfour());
    903 			if (a > 0 && b > 0)
    904 			    set_rule(pixel_round(xspell_conv(a)),
    905 				pixel_round(b));
    906 			DVI_H += 1 * b;
    907 			break;
    908 
    909 		    case PUTRULE:
    910 			a = xspell_conv(xsfour());
    911 			b = xspell_conv(xsfour());
    912 			if (a > 0 && b > 0)
    913 			    set_rule(pixel_round(a), pixel_round(b));
    914 			break;
    915 
    916 		    case NOP:
    917 			break;
    918 
    919 		    case BOP:
    920 			xskip((long) 11 * 4);
    921 			DVI_H = OFFSET_X;
    922 			DVI_V = OFFSET_Y;
    923 			PXL_V = pixel_conv(DVI_V);
    924 			WW = XX = YY = ZZ = 0;
    925 			break;
    926 
    927 		    case EOP:
    928 			if (current_frame != minframe)
    929 			    tell_oops("stack not empty at EOP");
    930 			return;
    931 
    932 		    case PUSH:
    933 			if (current_frame->next == NULL) {
    934 			    struct frame *newp = xmalloc(sizeof(struct frame));
    935 
    936 			    current_frame->next = newp;
    937 			    newp->prev = current_frame;
    938 			    newp->next = NULL;
    939 			}
    940 			current_frame = current_frame->next;
    941 			current_frame->data = currinf.data;
    942 			break;
    943 
    944 		    case POP:
    945 			if (current_frame == minframe)
    946 			    tell_oops("more POPs than PUSHes");
    947 			currinf.data = current_frame->data;
    948 			current_frame = current_frame->prev;
    949 			break;
    950 
    951 
    952 		    case RIGHT1:
    953 		    case RIGHT2:
    954 		    case RIGHT3:
    955 		    case RIGHT4:
    956 			DVI_H += 1 * xspell_conv(xsnum(ch - RIGHT1 + 1));
    957 			break;
    958 
    959 		    case W1:
    960 		    case W2:
    961 		    case W3:
    962 		    case W4:
    963 			WW = xspell_conv(xsnum(ch - W0));
    964 		    case W0:
    965 			DVI_H += 1 * WW;
    966 			break;
    967 
    968 		    case X1:
    969 		    case X2:
    970 		    case X3:
    971 		    case X4:
    972 			XX = xspell_conv(xsnum(ch - X0));
    973 		    case X0:
    974 			DVI_H += 1 * XX;
    975 			break;
    976 
    977 		    case DOWN1:
    978 		    case DOWN2:
    979 		    case DOWN3:
    980 		    case DOWN4:
    981 			DVI_V += xspell_conv(xsnum(ch - DOWN1 + 1));
    982 			PXL_V = pixel_conv(DVI_V);
    983 			break;
    984 
    985 		    case Y1:
    986 		    case Y2:
    987 		    case Y3:
    988 		    case Y4:
    989 			YY = xspell_conv(xsnum(ch - Y0));
    990 		    case Y0:
    991 			DVI_V += YY;
    992 			PXL_V = pixel_conv(DVI_V);
    993 			break;
    994 
    995 		    case Z1:
    996 		    case Z2:
    997 		    case Z3:
    998 		    case Z4:
    999 			ZZ = xspell_conv(xsnum(ch - Z0));
   1000 		    case Z0:
   1001 			DVI_V += ZZ;
   1002 			PXL_V = pixel_conv(DVI_V);
   1003 			break;
   1004 
   1005 		    case FNT1:
   1006 		    case FNT2:
   1007 		    case FNT3:
   1008 		    case FNT4:
   1009 			change_font(xnum(ch - FNT1 + 1));
   1010 			break;
   1011 
   1012 		    case XXX1:
   1013 		    case XXX2:
   1014 		    case XXX3:
   1015 		    case XXX4:
   1016 			a = xnum(ch - XXX1 + 1);
   1017 			if (a > 0)
   1018 			    applicationDoSpecial(read_special(a));
   1019 			break;
   1020 
   1021 		    case FNTDEF1:
   1022 		    case FNTDEF2:
   1023 		    case FNTDEF3:
   1024 		    case FNTDEF4:
   1025 			xskip((long) (12 + ch - FNTDEF1 + 1));
   1026 			a = (long) xone();
   1027 			xskip(a + (long) xone());
   1028 			break;
   1029 
   1030 		    case SREFL:
   1031 		    case EREFL:
   1032 		    case PRE:
   1033 		    case POST:
   1034 		    case POSTPOST:
   1035 			tell_oops("shouldn't happen: %s encountered",
   1036 				dvi_table2[ch - (FNTNUM0 + 64)]);
   1037 			break;
   1038 
   1039 		    default:
   1040 			tell_oops("unknown op-code %d", ch);
   1041 		} /* end switch*/
   1042 	    } /* end else (ch not a SETCHAR or FNTNUM) */
   1043 	} /* end for */
   1044 }
   1045 
   1046 #undef	xspell_conv
   1047 
   1048 void
   1049 draw_page(void)
   1050 {
   1051 	color_bottom = &fg_initial;
   1052 	color_bot_size = 1;
   1053 	if (page_colors != NULL && current_page > 0) {
   1054 	    color_bottom = page_colors[current_page - 1].colorstack;
   1055 	    color_bot_size = page_colors[current_page - 1].stacksize;
   1056 	}
   1057 	rcs_top = NULL;
   1058 	set_fg_color(&color_bottom[color_bot_size - 1]);
   1059 
   1060 	(void) fseek(dvi_file, page_info[current_page].offset, SEEK_SET);
   1061 
   1062 	bzero((char *) &currinf.data, sizeof currinf.data);
   1063 	currinf.tn_table_len = TNTABLELEN;
   1064 	currinf.tn_table = tn_table;
   1065 	currinf.tn_head = tn_head;
   1066 	currinf.pos = currinf.end = dvi_buffer;
   1067 	currinf.virtual = NULL;
   1068 	dvi_pointer_frame = &currinf;
   1069 	drawing_mag = (currwin.win == alt.win);
   1070 
   1071 	draw_part(current_frame = &frame0, dimconv);
   1072 
   1073 	drawing_mag = False;
   1074 	dvi_pointer_frame = NULL;
   1075 	currwin.win = (Window) 0;
   1076 }
   1077 
   1078 
   1079 /*
   1080  *	General dvi scanning routines.  These are used for:
   1081  *	    o	source special lookups and
   1082  *	    o	finding the dimensions of links (if compiling with support for
   1083  *		hypertext specials).
   1084  *	This routine can be a bit slower than draw_page()/draw_part(), since
   1085  *	it is not run that often; that is why it is a separate routine in
   1086  *	spite of much duplication.
   1087  *
   1088  *	Note that it does not use a separate copy of define_font().
   1089  */
   1090 
   1091 /*
   1092  *	All calculations are done with shrink factor = 1, so we re-do some
   1093  *	macros accordingly.  Many of these are also defined in special.c.
   1094  */
   1095 
   1096 #define	xspell_conv(n)	spell_conv0(n, current_dimconv)
   1097 #define	xpixel_conv(x)	((int) ((x) >> 16))
   1098 #define	xpixel_round(x)	((int) ROUNDUP(x, 1 << 16))
   1099 
   1100 #define	G_PXL_H		xpixel_conv(currinf.data.dvi_h)
   1101 #define	G_OFFSET_X	(offset_x << 16) + (3 << 15)
   1102 #define	G_OFFSET_Y	(offset_y << 16) + (3 << 15)
   1103 
   1104 # define mane_base_x	0
   1105 # define mane_base_y	0
   1106 
   1107 
   1108 /*
   1109  *	Used by the geometry-scanning routines.
   1110  *	It passes pointers to routines to be called at certain
   1111  *	points in the dvi file, and other information.
   1112  */
   1113 
   1114 struct geom_info {
   1115 	void	(*geom_box)	(struct geom_info *, char, long, long, long, long);
   1116 	void	(*geom_special)	(struct geom_info *, const char *);
   1117 	void	*geom_data;
   1118 };
   1119 
   1120 
   1121 /*
   1122  *	This set of routines can be called while draw_part() is active,
   1123  *	so the global variables must be separate.
   1124  */
   1125 
   1126 static	struct frame	*geom_current_frame;
   1127 
   1128 static	void		geom_scan_part(struct geom_info *,
   1129 			  struct frame *, double);
   1130 
   1131 /*
   1132  *	Handle a character in geometric scanning routine.
   1133  */
   1134 
   1135 static	long
   1136 geom_do_char(g_info, ch)
   1137 	struct geom_info	*g_info;
   1138 	unsigned char		ch;
   1139 {
   1140 	if (currinf.set_char_p == set_no_char) {
   1141 	    if (currinf.virtual == NULL
   1142 	      || (currinf.fontp = currinf.virtual->first_font) == NULL)
   1143 		return 0;	/* error; we'll catch it later */
   1144 	    maxchar = currinf.fontp->maxchar;
   1145 	    currinf.set_char_p = currinf.fontp->set_char_p;
   1146 	}
   1147 
   1148 	if (currinf.set_char_p == set_empty_char)
   1149 	    return 0;	/* error; we'll catch it later */
   1150 
   1151 	if (currinf.set_char_p == set_ft_char)
   1152 	    do_load_freetype_font();
   1153 
   1154 	if (currinf.set_char_p == load_n_set_char) {
   1155 	    if (ev_flags & EV_GE_NEWDOC)	/* if abort */
   1156 		return 0;
   1157 	    if (!load_font(currinf.fontp)) {	/* if not found */
   1158 		if (ev_flags & EV_GE_NEWDOC)	/* if abort */
   1159 		    return 0;
   1160 		warnx("Character(s) will be left blank.");
   1161 		currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
   1162 		return 0;
   1163 	    }
   1164 	    maxchar = currinf.fontp->maxchar;
   1165 	    currinf.set_char_p = currinf.fontp->set_char_p;
   1166 	}
   1167 
   1168 	if (currinf.set_char_p == set_char) {
   1169 	    struct glyph *g;
   1170 	    long x, y;
   1171 
   1172 	    if (ch > maxchar)
   1173 		return 0;	/* catch the error later */
   1174 	    if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
   1175 		if (g->addr == 0)
   1176 		    return 0;	/* catch the error later */
   1177 		if (g->addr == -1)
   1178 		    return 0;	/* previously flagged missing char */
   1179 		if (currinf.fontp->ft == NULL)
   1180 		{
   1181 		    open_font_file(currinf.fontp);
   1182 		    if (fseek(currinf.fontp->file, g->addr, SEEK_SET) != 0)
   1183 			err(1, "fseek");
   1184 		}
   1185 		(*currinf.fontp->read_char)(currinf.fontp, ch);
   1186 		if (debug & DBG_BITMAP) print_char((unsigned char) ch, g);
   1187 		currinf.fontp->timestamp = ++current_timestamp;
   1188 	    }
   1189 		x = G_PXL_H - g->x;
   1190 		y = PXL_V - g->y;
   1191 		g_info->geom_box(g_info, ch, x, y,
   1192 		  x + g->bitmap.w, y + g->bitmap.h);
   1193 
   1194 	    return 1 * g->dvi_adv;
   1195 	}
   1196 	else if (currinf.set_char_p == set_vf_char) {
   1197 	    struct macro	*m;
   1198 	    struct drawinf	oldinfo;
   1199 	    unsigned char	oldmaxchar;
   1200 
   1201 	    if (ch > maxchar)
   1202 		return 0;	/* catch the error later */
   1203 	    if ((m = &currinf.fontp->macro[ch])->pos == NULL) {
   1204 		return 0;	/* catch the error later */
   1205 	    }
   1206 
   1207 		oldinfo = currinf;
   1208 		oldmaxchar = maxchar;
   1209 		WW = XX = YY = ZZ = 0;
   1210 		currinf.tn_table_len = VFTABLELEN;
   1211 		currinf.tn_table = currinf.fontp->vf_table;
   1212 		currinf.tn_head = currinf.fontp->vf_chain;
   1213 		currinf.pos = m->pos;
   1214 		currinf.end = m->end;
   1215 		currinf.virtual = currinf.fontp;
   1216 		geom_scan_part(g_info, geom_current_frame,
   1217 		  currinf.fontp->dimconv);
   1218 		currinf = oldinfo;
   1219 		maxchar = oldmaxchar;
   1220 	    return 1 * m->dvi_adv;
   1221 	}
   1222 	else {
   1223 	    errx(1, "internal error -- currinf.set_char_p = %p",
   1224 		currinf.set_char_p);
   1225 	}
   1226 }
   1227 
   1228 /*
   1229  *	Do a rule in the geometry-scanning routine.
   1230  */
   1231 
   1232 static	void
   1233 geom_do_rule(g_info, h, w)
   1234 	struct geom_info	*g_info;
   1235 	long			h, w;
   1236 {
   1237 #if 0
   1238 	long			x, y;
   1239 
   1240 	x = G_PXL_H;
   1241 	y = PXL_V;
   1242 	g_info->geom_box(g_info, x, y - xpixel_round(h) + 1,
   1243 	  x + xpixel_round(w) - 1, y);
   1244 #endif
   1245 }
   1246 
   1247 
   1248 /*
   1249  *	Geometric dvi scanner work routine.  This does most of the work
   1250  *	(a) reading from a page, and (b) executing vf macros.
   1251  */
   1252 
   1253 static	void
   1254 geom_scan_part(g_info, minframe, current_dimconv)
   1255 	struct geom_info	*g_info;
   1256 	struct frame		*minframe;
   1257 	double			current_dimconv;
   1258 {
   1259 	unsigned char	ch;
   1260 
   1261 	currinf.fontp = NULL;
   1262 	currinf.set_char_p = set_no_char;
   1263 	for (;;) {
   1264 	    ch = xone();
   1265 	    if (ch <= (unsigned char) (SETCHAR0 + 127))
   1266 		DVI_H += geom_do_char(g_info, ch);
   1267 	    else if (FNTNUM0 <= ch && ch <= (unsigned char) (FNTNUM0 + 63))
   1268 		change_font((unsigned long) (ch - FNTNUM0));
   1269 	    else {
   1270 		long	a, b;
   1271 
   1272 		switch (ch) {
   1273 		    case SET1:
   1274 		    case PUT1:
   1275 			a = geom_do_char(g_info, xone());
   1276 			if (ch != PUT1) DVI_H += a;
   1277 			break;
   1278 
   1279 		    case SETRULE:
   1280 			/* Be careful, dvicopy outputs rules with
   1281 			   height = 0x80000000.  We don't want any
   1282 			   SIGFPE here. */
   1283 			a = xsfour();
   1284 			b = xspell_conv(xsfour());
   1285 			if (a >= 0 && b >= 0)
   1286 			    geom_do_rule(g_info, xspell_conv(a), b);
   1287 			DVI_H += 1 * b;
   1288 			break;
   1289 
   1290 		    case PUTRULE:
   1291 			a = xspell_conv(xsfour());
   1292 			b = xspell_conv(xsfour());
   1293 			if (a >= 0 && b >= 0)
   1294 			    geom_do_rule(g_info, a, b);
   1295 			break;
   1296 
   1297 		    case NOP:
   1298 			break;
   1299 
   1300 		    case BOP:
   1301 			xskip((long) 11 * 4);
   1302 			DVI_H = G_OFFSET_X;
   1303 			DVI_V = G_OFFSET_Y;
   1304 			PXL_V = xpixel_conv(DVI_V);
   1305 			WW = XX = YY = ZZ = 0;
   1306 			break;
   1307 
   1308 		    case PUSH:
   1309 			if (geom_current_frame->next == NULL) {
   1310 			    struct frame *newp = xmalloc(sizeof(struct frame));
   1311 
   1312 			    geom_current_frame->next = newp;
   1313 			    newp->prev = geom_current_frame;
   1314 			    newp->next = NULL;
   1315 			}
   1316 			geom_current_frame = geom_current_frame->next;
   1317 			geom_current_frame->data = currinf.data;
   1318 			break;
   1319 
   1320 		    case POP:
   1321 			if (geom_current_frame == minframe)
   1322 			    tell_oops("more POPs than PUSHes");
   1323 			currinf.data = geom_current_frame->data;
   1324 			geom_current_frame = geom_current_frame->prev;
   1325 			break;
   1326 
   1327 
   1328 		    case RIGHT1:
   1329 		    case RIGHT2:
   1330 		    case RIGHT3:
   1331 		    case RIGHT4:
   1332 			DVI_H += 1 * xspell_conv(xsnum(ch - RIGHT1 + 1));
   1333 			break;
   1334 
   1335 		    case W1:
   1336 		    case W2:
   1337 		    case W3:
   1338 		    case W4:
   1339 			WW = xspell_conv(xsnum(ch - W0));
   1340 		    case W0:
   1341 			DVI_H += 1 * WW;
   1342 			break;
   1343 
   1344 		    case X1:
   1345 		    case X2:
   1346 		    case X3:
   1347 		    case X4:
   1348 			XX = xspell_conv(xsnum(ch - X0));
   1349 		    case X0:
   1350 			DVI_H += 1 * XX;
   1351 			break;
   1352 
   1353 		    case DOWN1:
   1354 		    case DOWN2:
   1355 		    case DOWN3:
   1356 		    case DOWN4:
   1357 			DVI_V += xspell_conv(xsnum(ch - DOWN1 + 1));
   1358 			PXL_V = xpixel_conv(DVI_V);
   1359 			break;
   1360 
   1361 		    case Y1:
   1362 		    case Y2:
   1363 		    case Y3:
   1364 		    case Y4:
   1365 			YY = xspell_conv(xsnum(ch - Y0));
   1366 		    case Y0:
   1367 			DVI_V += YY;
   1368 			PXL_V = xpixel_conv(DVI_V);
   1369 			break;
   1370 
   1371 		    case Z1:
   1372 		    case Z2:
   1373 		    case Z3:
   1374 		    case Z4:
   1375 			ZZ = xspell_conv(xsnum(ch - Z0));
   1376 		    case Z0:
   1377 			DVI_V += ZZ;
   1378 			PXL_V = xpixel_conv(DVI_V);
   1379 			break;
   1380 
   1381 		    case FNT1:
   1382 		    case FNT2:
   1383 		    case FNT3:
   1384 		    case FNT4:
   1385 			change_font(xnum(ch - FNT1 + 1));
   1386 			break;
   1387 
   1388 		    case XXX1:
   1389 		    case XXX2:
   1390 		    case XXX3:
   1391 		    case XXX4:
   1392 			a = xnum(ch - XXX1 + 1);
   1393 			if (a > 0) {
   1394 			    char *str = read_special(a);
   1395 
   1396 			    /* process the specials we're looking for */
   1397 			    g_info->geom_special(g_info, str);
   1398 			}
   1399 			break;
   1400 
   1401 		    case FNTDEF1:
   1402 		    case FNTDEF2:
   1403 		    case FNTDEF3:
   1404 		    case FNTDEF4:
   1405 			xskip((long) (12 + ch - FNTDEF1 + 1));
   1406 			a = (long) xone();
   1407 			xskip(a + (long) xone());
   1408 			break;
   1409 
   1410 		    case SREFL:
   1411 		    case EREFL:
   1412 		    case PRE:
   1413 		    case POST:
   1414 		    case POSTPOST:
   1415 		    case EOP:
   1416 		    default:
   1417 			return;
   1418 
   1419 		} /* end switch*/
   1420 	    } /* end else (ch not a SETCHAR or FNTNUM) */
   1421 	} /* end for */
   1422 }
   1423 
   1424 /*
   1425  *	Main scanning routine.
   1426  */
   1427 
   1428 static struct frame geom_frame0;
   1429 
   1430 static	void
   1431 geom_scan(g_info)
   1432 	struct geom_info	*g_info;
   1433 {
   1434 	off_t		pos_save;
   1435 	struct drawinf	currinf_save;
   1436 	unsigned char	maxchar_save;
   1437 
   1438 	if (dvi_pointer_frame != NULL)
   1439 	    pos_save = ftell(dvi_file) -
   1440 		(dvi_pointer_frame->end - dvi_pointer_frame->pos);
   1441 	if (fseek(dvi_file, page_info[current_page].offset, SEEK_SET) != 0)
   1442 		err(1, "fseek");
   1443 
   1444 	currinf_save = currinf;
   1445 	maxchar_save = maxchar;
   1446 
   1447 	bzero((char *) &currinf.data, sizeof currinf.data);
   1448 	currinf.tn_table_len = TNTABLELEN;
   1449 	currinf.tn_table = tn_table;
   1450 	currinf.tn_head = tn_head;
   1451 	currinf.pos = currinf.end = dvi_buffer;
   1452 	currinf.virtual = NULL;
   1453 
   1454 	geom_scan_part(g_info, geom_current_frame = &geom_frame0, dimconv);
   1455 
   1456 	maxchar = maxchar_save;
   1457 	currinf = currinf_save;
   1458 
   1459 	if (dvi_pointer_frame != NULL) {
   1460 	    if (fseek(dvi_file, pos_save, SEEK_SET) != 0)
   1461 		err(1, "fseek");
   1462 	    dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
   1463 	}
   1464 }
   1465 
   1466 static void
   1467 hypertex_box(struct geom_info *g_info, char ch, long ulx, long uly, long lrx, long lry)
   1468 {
   1469 	struct htex_data *htex_data = g_info->geom_data;
   1470 	int		 index;
   1471 	long		 x, y;
   1472 
   1473 	if (htex_data->temp_incomplete == 0)
   1474 		return;
   1475 
   1476 	index = tolower(ch) - 'a';
   1477 	if (index < 0 || index > 26)
   1478 		return;
   1479 	if (htex_data->links[index] != NULL)
   1480 		/* This character is already taken, keep looking */
   1481 		return;
   1482 
   1483 	htex_data->links[index] = htex_data->temp_url;
   1484 	htex_data->temp_url = NULL;
   1485 	htex_data->temp_incomplete = 0;
   1486 
   1487 #define PAD 10
   1488 	x = (ulx - PAD) / mane.shrinkfactor;
   1489 	y = (uly - PAD) / mane.shrinkfactor;
   1490 	XFillRectangle(DISP, mane.win, linkGC, x, y,
   1491 	    (lrx + PAD) / mane.shrinkfactor - x, (lry + PAD) / mane.shrinkfactor - y);
   1492 }
   1493 
   1494 static void
   1495 hypertex_special(struct geom_info *g_info, const char *in)
   1496 {
   1497 	struct htex_data *htex_data = g_info->geom_data;
   1498 	char		*str;
   1499 
   1500 	if (strncasecmp(in, "html:<a href=\"", 14) != 0)
   1501 		return;
   1502 
   1503 	str = xstrdup(in + 14);
   1504 	if (strtok(str, "\"") == NULL)
   1505 		/* No closing " found. */
   1506 		return;
   1507 
   1508 	if (*str == '#')
   1509 		/* Anchor found */
   1510 		return;
   1511 
   1512 	htex_data->temp_incomplete = 1;
   1513 	htex_data->temp_url = str;
   1514 
   1515 	return;
   1516 }
   1517 
   1518 void
   1519 hypertex_search(struct htex_data *data)
   1520 {
   1521 	struct geom_info	g_info;
   1522 
   1523 	g_info.geom_box = hypertex_box;
   1524 	g_info.geom_special = hypertex_special;
   1525 	g_info.geom_data = data;
   1526 
   1527 	geom_scan(&g_info);
   1528 }