1 /* The rest of the code has the following copyright:
2 
3 Copyright (c) 1990-2013  Paul Vojta and others
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, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
19 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
22 
23 NOTE:
24 xdvi is based on prior work, as noted in the modification history
25 in xdvi.c.
26 
27 \*========================================================================*/
28 
29 #include "xdvi-config.h"
30 #include "xdvi.h"
31 
32 #include <stdarg.h>
33 
34 #include <stdlib.h>
35 #include <ctype.h>
36 
37 #include <setjmp.h>
38 
39 #define USE_HASH
40 
41 #include <ctype.h>
42 #include "kpathsea/c-fopen.h"
43 #include "kpathsea/c-stat.h"
44 #include "kpathsea/magstep.h"
45 #include "kpathsea/tex-file.h"
46 
47 #include <string.h>
48 
49 #include "dvi.h"
50 #include "string-utils.h"
51 #include "util.h"
52 #include "x_util.h"
53 #include "events.h"
54 #include "dvi-init.h"
55 #include "font-open.h"
56 #include "statusline.h"
57 #include "hypertex.h"
58 #include "special.h"
59 #ifdef PTEX
60 #include "ptexmap.h"
61 #endif
62 #include "my-snprintf.h"
63 #include "kpathsea/tex-file.h"
64 #include "mag.h"
65 #include "message-window.h"
66 
67 #include "dvi-draw.h"
68 #include "search-internal.h"
69 #include "encodings.h"
70 #include "pagesel.h"
71 #include "pagehist.h"
72 
73 #if FREETYPE
74 	/* other freetype includes are already done in dvi-init.h */
75 # include FT_TYPE1_TABLES_H
76 #endif
77 
78 #ifdef RGB_ANTI_ALIASING
79 #define TRACE_AA 0
80 #define TRACE_AA1 1
81 #define TRACE_AA3 0
82 #else
83 #define TRACE_AA 0
84 #define TRACE_AA1 0
85 #define TRACE_AA3 0
86 #endif
87 
88 #define MY_DEBUG 0
89 
90 #if MY_DEBUG
91 # define TRACE_FIND_VERBOSE(x) TRACE_FIND(x)
92 #else
93 # define TRACE_FIND_VERBOSE(x) /* as nothing */
94 #endif
95 
96 #if PS && PS_GS
97 #include "psgs.h"
98 #endif /* PS && PS_GS */
99 
100 #ifdef	DOPRNT	/* define this if vfprintf gives you trouble */
101 # define vfprintf(stream, message, args)	_doprnt(message, args, stream)
102 #endif
103 
104 #define BUF_SIZE 1024
105 
106 /*
107  *	All calculations are done with shrink factor = 1, so we re-do some
108  *	macros accordingly.  Many of these are also defined in special.c.
109  */
110 
111 #define	xpixel_conv(x)	((int) ((x) >> 16))
112 #define	xpixel_round(x)	((int) ROUNDUP(x, 1 << 16))
113 
114 #define	G_PXL_H		xpixel_conv(currinf.data.dvi_h)
115 #define	G_OFFSET_X	(resource.xoffset_int << 16) + (3 << 15)
116 #define	G_OFFSET_Y	(resource.yoffset_int << 16) + (3 << 15)
117 
118 #if PS
119 int scanned_page_ps;
120 int scanned_page_ps_bak;
121 #endif
122 
123 #if COLOR
124 int scanned_page_color;
125 #endif
126 
127 int scanned_page_reset, scanned_page;
128 
129 struct drawinf currinf;
130 Boolean htex_inside_href = False; /* whether we're inside a href */
131 
132 Boolean	drawing_mag = False;
133 
134 static struct frame frame0;	/* dummy head of list */
135 #ifdef	TEXXET
136 static struct frame *scan_frame;	/* head frame for scanning */
137 #endif
138 
139 static const char *const reverse_search_helptext =
140 "Forward/reverse search allows you to jump from a point "
141 "in the DVI file to the corresponding location in the .tex source file, and vice versa. "
142 "To make this possible, the .tex file needs to be compiled with source special support. "
143 "This can be done by using either a package like \"srcltx.sty\" or \"srctex.sty\", "
144 "or a command-line switch like \"-src\" for the TeX executable. "
145 "See the xdvi man page (section SOURCE SPECIALS) "
146 "for more information about this.";
147 
148 static ubyte dvi_buffer[DVI_BUFFER_LEN];
149 ubyte *G_dvi_buf_ptr = dvi_buffer;
150 static struct frame *current_frame;
151 
152 /* Points to drawinf record containing current dvi file location (for update by
153    geom_scan).  */
154 static	struct drawinf	*dvi_pointer_frame = NULL;
155 
156 #ifdef TEXXET
157 #define	DIR	currinf.dir
158 #else
159 #define	DIR	1
160 #endif
161 
162 /*
163  *	Explanation of the following constant:
164  *	offset_[xy]   << 16:	margin (defaults to one inch)
165  *	currwin.shrinkfactor << 16:	one pixel page border
166  *	currwin.shrinkfactor << 15:	rounding for pixel_conv
167  */
168 #define OFFSET_X	(resource.xoffset_int << 16) + (currwin.shrinkfactor * 3 << 15)
169 #define OFFSET_Y	(resource.yoffset_int << 16) + (currwin.shrinkfactor * 3 << 15)
170 
171 #if (BMBYTES == 1)
172 bmUnitT bit_masks[] = {
173     0x0, 0x1, 0x3, 0x7,
174     0xf, 0x1f, 0x3f, 0x7f,
175     0xff
176 };
177 #else
178 #if (BMBYTES == 2)
179 bmUnitT bit_masks[] = {
180     0x0, 0x1, 0x3, 0x7,
181     0xf, 0x1f, 0x3f, 0x7f,
182     0xff, 0x1ff, 0x3ff, 0x7ff,
183     0xfff, 0x1fff, 0x3fff, 0x7fff,
184     0xffff
185 };
186 #else /* BMBYTES == 4 */
187 bmUnitT bit_masks[] = {
188     0x0, 0x1, 0x3, 0x7,
189     0xf, 0x1f, 0x3f, 0x7f,
190     0xff, 0x1ff, 0x3ff, 0x7ff,
191     0xfff, 0x1fff, 0x3fff, 0x7fff,
192     0xffff, 0x1ffff, 0x3ffff, 0x7ffff,
193     0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
194     0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
195     0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
196     0xffffffff
197 };
198 #endif
199 #endif
200 
201 #ifdef	VMS
202 #define	off_t	int
203 #endif
204 extern off_t lseek();
205 
206 #ifndef	SEEK_SET	/* if <unistd.h> is not provided (or for <X11R5) */
207 #define	SEEK_SET	0
208 #define	SEEK_CUR	1
209 #define	SEEK_END	2
210 #endif
211 
212 static void draw_part(FILE *fp, struct frame *minframe, double current_dimconv);
213 
214 static void source_fwd_draw_box(void);
215 
216 
217 
218 /*
219  *	X routines.
220  */
221 
222 /*
223  *	Put a rectangle on the screen.
224  */
225 static void
put_rule(int x,int y,unsigned int w,unsigned int h)226 put_rule(int x, int y, unsigned int w, unsigned int h)
227 {
228     if (htex_inside_href)
229 	htex_record_position(x, y, w, h);
230     if (x < globals.win_expose.max_x && x + (int)w >= globals.win_expose.min_x && y < globals.win_expose.max_y && y + (int)h >= globals.win_expose.min_y) {
231 	if (--globals.ev.ctr == 0) {
232 	    if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
233 		/* 		fprintf(stderr, "longjmp1!\n"); */
234 		longjmp(globals.ev.canit, 1);
235 	    }
236 	}
237 #if COLOR
238 	if (fg_active != fg_current)
239 	    do_color_change();
240 #endif
241 	XFillRectangle(DISP, currwin.win,
242 		       globals.gc.rule,
243 		       x - currwin.base_x,
244 		       y - currwin.base_y,
245 		       w ? w : 1,
246 		       h ? h : 1);
247     }
248 }
249 
250 static void
put_bitmap(struct bitmap * bitmap,int x,int y)251 put_bitmap(struct bitmap *bitmap, int x, int y)
252 {
253     if (globals.debug & DBG_BITMAP)
254 	printf("X(%d,%d)\n", x - currwin.base_x, y - currwin.base_y);
255     if (htex_inside_href)
256 	htex_record_position(x, y, bitmap->w, bitmap->h);
257     if (x < globals.win_expose.max_x && x + (int)bitmap->w >= globals.win_expose.min_x &&
258 	y < globals.win_expose.max_y && y + (int)bitmap->h >= globals.win_expose.min_y) {
259 	if (--globals.ev.ctr == 0)
260 	    if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
261 		/* 		fprintf(stderr, "longjmp2!\n"); */
262 		longjmp(globals.ev.canit, 1);
263 	    }
264 #if COLOR
265 	if (fg_active != fg_current)
266 	    do_color_change();
267 #endif
268 	G_image->width = bitmap->w;
269 	G_image->height = bitmap->h;
270 	G_image->data = bitmap->bits;
271 	G_image->bytes_per_line = bitmap->bytes_wide;
272 	XPutImage(DISP, currwin.win, globals.gc.fore, G_image,
273 		  0, 0,
274 		  x - currwin.base_x, y - currwin.base_y, bitmap->w, bitmap->h);
275 	if (globals.gc.fore2) {
276 	    XPutImage(DISP, currwin.win, globals.gc.fore2, G_image,
277 		      0, 0,
278 		      x - currwin.base_x, y - currwin.base_y,
279 		      bitmap->w, bitmap->h);
280 	}
281     }
282 }
283 
284 #if GREY
285 
286 /* Anti-aliasing stuff.
287    The method used here is supersampling of the unshrunk glyph (this
288    also means that no anti-aliasing happens at shrink 1). A sample
289    of the number of bits that are `on' in the unsrunk glyph determines
290    the grey level of the shrunk image.
291 */
292 
293 /* Pixel lookup tables for anti-aliasing: These store all possible
294    supersampling values (i.e. number of bits set in the unshrunk
295    image) for the given shrink factor. E.g. at shrink level 2, the
296    size of the pixel table is 4; in other words, 1 pixel in the shrunk
297    image corresponds to 4 pixels in the unshrunk image. Thus, the possible
298    values for shrink level 2 are: black, 1/4 (0x404040), 1/2 (0x808080),
299    3/4 (0xc0c0c0) and white (0xffffff).
300 */
301 static Pixel *pixeltbl;
302 static Pixel *pixeltbl_gc2; /* drawing to globals.gc.fore2 (compare pixmap2_gc2) */
303 
304 static void shrink_glyph_grey(struct glyph *);
305 
306 static void
put_image(struct glyph * g,int x,int y)307 put_image(struct glyph *g, int x, int y)
308 {
309     XImage *img = g->image2;
310 
311     if (htex_inside_href)
312 	htex_record_position(x, y, img->width, img->height);
313     if (x < globals.win_expose.max_x && x + img->width >= globals.win_expose.min_x &&
314 	y < globals.win_expose.max_y && y + img->height >= globals.win_expose.min_y) {
315 	if (--globals.ev.ctr == 0)
316 	    if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
317 		/* 		fprintf(stderr, "longjmp3!\n"); */
318 		longjmp(globals.ev.canit, 1);
319 	    }
320 
321 #if COLOR
322 	if (g->fg != fg_current)	/* if color change since last use */
323 	    shrink_glyph_grey(g);
324 	else if (fg_active != fg_current)	/* if GCs need updating */
325 	    do_color_change();
326 #endif
327 	/* TODO: Can we increase gamma locally to make the inverted text more readable?
328 
329 	and to draw the background, so something like this:
330 	XFillRectangle(DISP, currwin.win, globals.gc.fore, x - currwin.base_x, y - currwin.base_y,
331 	(unsigned int)img->width * 2, (unsigned int)img->height * 2);
332 
333 	test this with color changes!!
334 	*/
335 	/*TEST_DELAY("check point 1 ...")*/
336 	XPutImage(DISP, currwin.win, globals.gc.fore, img,
337 		  0, 0,
338 		  x - currwin.base_x, y - currwin.base_y,
339 		  (unsigned int)img->width, (unsigned int)img->height);
340 	/*TEST_DELAY("check point 2 ...")*/
341 
342 	if (globals.gc.fore2 != NULL) {
343 	    img->data = g->pixmap2_gc2;
344 	    XPutImage(DISP, currwin.win, globals.gc.fore2, img,
345 		      0, 0,
346 		      x - currwin.base_x, y - currwin.base_y,
347 		      (unsigned int)img->width, (unsigned int)img->height);
348 	    img->data = g->pixmap2;
349 	}
350 	/*TEST_DELAY("check point 3 ...")*/
351     }
352 }
353 #endif /* GREY */
354 
355 /*
356  *	Draw the border of a rectangle on the screen.
357  *	This should be replaced by a grey background both in Xaw and Motif
358  *	as soon as #470325 is fixed (see also FIXED_FLUSHING_PAGING).
359  */
360 static void
draw_border(int x,int y,unsigned int width,unsigned int height,GC ourGC)361 draw_border(int x, int y, unsigned int width, unsigned int height, GC ourGC)
362 {
363     --width;
364     --height;
365     XDrawRectangle(DISP, currwin.win, ourGC, x, y, width, height);
366 }
367 
368 /* draw the grid */
369 static void
put_grid(int x,int y,unsigned int width,unsigned int height,unsigned int unit,GC gc)370 put_grid(int x, int y,
371 	 unsigned int width, unsigned int height, unsigned int unit,
372 	 GC gc)
373 {
374     int i;
375     float sep;
376     unsigned int tmp;
377 
378     --width;
379     --height;
380 
381 
382     /* draw vertial grid */
383 #define DRAWGRID_VER(gc) for (i = 1; \
384 			      (tmp = x + (int)(i * sep)) < x + width; \
385 			      i++) \
386 			  XFillRectangle(DISP, currwin.win, (gc), \
387 				   tmp, y, 1, height)
388     /* draw horizontal grid */
389 #define DRAWGRID_HOR(gc) for (i = 1; \
390 			      (tmp = y + (int)(i * sep)) < y + height; \
391 			      i++) \
392 		          XFillRectangle(DISP, currwin.win, (gc), \
393 				   x, tmp, width, 1)
394 
395     if (resource.grid_mode > 2) {	/* third level grid */
396 	sep = (float)unit / 4.0;
397 	DRAWGRID_VER(gc);
398 	DRAWGRID_HOR(gc);
399     }
400 
401     if (resource.grid_mode > 1) {	/* second level grid */
402 	sep = (float)unit / 2.0;
403 	DRAWGRID_VER(gc);
404 	DRAWGRID_HOR(gc);
405     }
406 
407     if (resource.grid_mode > 0) {	/* first level grid */
408 	sep = (float)unit;
409 	DRAWGRID_VER(gc);
410 	DRAWGRID_HOR(gc);
411     }
412 }
413 #undef DRAWGRID_VER
414 #undef DRAWGRID_HOR
415 
416 /*
417  *	Byte reading routines for dvi file.
418  */
419 
420 #define	xtell(fp, pos)	(lseek(fileno(fp), 0L, SEEK_CUR) - \
421 			    (currinf.end - (pos)))
422 
423 static ubyte
xxone(FILE * fp)424 xxone(FILE *fp)
425 {
426     if (currinf.virtual) {
427 	++currinf.pos;
428 	return EOP;
429     }
430 
431     currinf.end = G_dvi_buf_ptr
432 	+ read(fileno(fp), (char *)(currinf.pos = G_dvi_buf_ptr), DVI_BUFFER_LEN);
433     return currinf.end > G_dvi_buf_ptr ? *(currinf.pos)++ : EOF;
434 }
435 
436 #define	xone(fp)  (currinf.pos < currinf.end ? *(currinf.pos)++ : xxone(fp))
437 
438 static unsigned long
xnum(FILE * fp,ubyte size)439 xnum(FILE *fp, ubyte size)
440 {
441     long x = 0;
442 
443     while (size--)
444 	x = (x << 8) | xone(fp);
445     return x;
446 }
447 
448 static long
xsnum(FILE * fp,ubyte size)449 xsnum(FILE *fp, ubyte size)
450 {
451     long x;
452 
453 #if	__STDC__
454     x = (signed char)xone(fp);
455 #else
456     x = xone(fp);
457     if (x & 0x80)
458 	x -= 0x100;
459 #endif
460     while (--size)
461 	x = (x << 8) | xone(fp);
462     return x;
463 }
464 
465 #define	xsfour(fp)	xsnum(fp, 4)
466 
467 static void
xskip(FILE * fp,long offset)468 xskip(FILE *fp, long offset)
469 {
470     currinf.pos += offset;
471     if (!currinf.virtual && currinf.pos > currinf.end)
472 	(void)lseek(fileno(fp), (long)(currinf.pos - currinf.end), SEEK_CUR);
473 }
474 
475 void
dvi_fmt_error(const char * message,...)476 dvi_fmt_error(const char *message, ...)
477 {
478 
479     va_list args;
480     va_start(args, message);
481     fprintf(stderr, "%s: ", globals.program_name);
482     (void)vfprintf(stderr, message, args);
483     va_end(args);
484     if (currinf.virtual)
485 	fprintf(stderr, " in virtual font %s\n", currinf.virtual->fontname);
486     else
487 	fprintf(stderr, ", offset %ld\n", (long)xtell(globals.dvi_file.bak_fp, currinf.pos - 1));
488     /* #ifndef NDEBUG */
489     /*     xdvi_exit(EXIT_FAILURE); */
490     /* #else */
491     XDVI_ABORT((stderr, "I'll abort now, to help you debugging this."));
492     /* #endif */
493 }
494 
495 
496 /*
497  *	Code for debugging options.
498  */
499 
500 static void
print_bitmap(struct bitmap * bitmap)501 print_bitmap(struct bitmap *bitmap)
502 {
503     bmUnitT *ptr = (bmUnitT *)bitmap->bits;
504     int x, y, i;
505 
506     ASSERT(ptr != NULL, "Invalid bitmap bits");
507 
508     printf("w = %d, h = %d, bytes wide = %d\n",
509 	   bitmap->w, bitmap->h, bitmap->bytes_wide);
510     for (y = 0; y < (int)bitmap->h; ++y) {
511 	for (x = bitmap->bytes_wide; x > 0; x -= BMBYTES) {
512 #ifdef WORDS_BIGENDIAN
513 	    for (i = BMBITS - 1; i >= 0; --i)
514 		putchar((*ptr & (1 << i)) ? '@' : '.');
515 #else
516 	    for (i = 0; i < BMBITS; ++i)
517 		putchar((*ptr & (1 << i)) ? '@' : '.');
518 #endif
519 	    ++ptr;
520 	}
521 	putchar('\n');
522     }
523 }
524 
525 static void
print_char(ubyte ch,struct glyph * g)526 print_char(ubyte ch, struct glyph *g)
527 {
528     printf("char %d", ch);
529     if (isprint(ch))
530 	printf(" (%c)", ch);
531     putchar('\n');
532     printf("x = %d, y = %d, dvi = %ld\n", g->x, g->y, g->dvi_adv);
533     print_bitmap(&g->bitmap);
534 }
535 
536 static const char *dvi_table1[] = {
537     "SET1", "SET2", "SET3", "SET4", "SETRULE", "PUT1", "PUT2", "PUT3",
538     "PUT4", "PUTRULE", "NOP", "BOP", "EOP", "PUSH", "POP", "RIGHT1",
539     "RIGHT2", "RIGHT3", "RIGHT4", "W0", "W1", "W2", "W3", "W4",
540     "X0", "X1", "X2", "X3", "X4", "DOWN1", "DOWN2", "DOWN3",
541     "DOWN4", "Y0", "Y1", "Y2", "Y3", "Y4", "Z0", "Z1",
542     "Z2", "Z3", "Z4"
543 };
544 
545 static const char *dvi_table2[] = {
546     "FNT1", "FNT2", "FNT3", "FNT4", "XXX1", "XXX2", "XXX3", "XXX4",
547     "FNTDEF1", "FNTDEF2", "FNTDEF3", "FNTDEF4", "PRE", "POST", "POSTPOST",
548     "SREFL", "EREFL", NULL, NULL, NULL,
549 #ifdef PTEX
550     "DIRECTION"
551 #else /* !PTEX */
552     NULL
553 #endif /* !PTEX */
554 };
555 
556 static void
print_dvi(ubyte ch)557 print_dvi(ubyte ch)
558 {
559     const char *s;
560 
561     fprintf(stderr, "%4d %4d ", PXL_H, PXL_V);
562     if (ch <= (ubyte) (SETCHAR0 + 127)) {
563 	fprintf(stderr, "SETCHAR%-3d", ch - SETCHAR0);
564 	if (isprint(ch))
565 	    fprintf(stderr, " (%c)", ch);
566 	fputc('\n', stderr);
567 	return;
568     }
569     else if (ch < FNTNUM0)
570 	s = dvi_table1[ch - 128];
571     else if (ch <= (ubyte) (FNTNUM0 + 63)) {
572 	fprintf(stderr, "FNTNUM%d\n", ch - FNTNUM0);
573 	return;
574     }
575     else
576 	s = dvi_table2[ch - (FNTNUM0 + 64)];
577     if (s) {
578 	fputs(s, stderr);
579 	fputc('\n', stderr);
580     }
581     else
582 	XDVI_FATAL((stderr, "print_dvi: unknown op-code %d", ch));
583 }
584 
585 
586 /*
587  *	Count the number of set bits in a 4x4-region of the bitmap
588  */
589 
590 static char sample_count[] = {
591     0, 1, 1, 2,
592     1, 2, 2, 3,
593     1, 2, 2, 3,
594     2, 3, 3, 4
595 };
596 
597 /*
598  * For greyscaling, return the number of bits that are set in a given region
599  * of width w and height h of the bitmap `bits', starting horizontally after
600  * `bit_skip' bits, where `bytes_wide' is the same as the `bytes_wide' field
601  * in the bitmap struct (scan line width in bytes).
602  * Note that `bits' is really a one-dimensional array, i.e. all the rows
603  * are put in sequence into one single row.
604  */
605 static int
sample(bmUnitT * bits,int bytes_wide,int bit_skip,int w,int h)606 sample(bmUnitT *bits, int bytes_wide, int bit_skip, int w, int h)
607 {
608     bmUnitT *beg_ptr, *end_ptr, *curr_ptr;
609     int bits_left;
610     int n, bit_shift, wid;
611 
612 #if TRACE_AA
613     fprintf(stderr, "sample: %d bytes wide, %d skip, %d w, %d h\n", bytes_wide, bit_skip, w, h);
614 #endif
615 
616     beg_ptr = bits + bit_skip / BMBITS;
617     end_ptr = ADD(bits, h * bytes_wide);
618 
619 #if TRACE_AA
620     fprintf(stderr, "beg_ptr: %p, end: %p\n", (void *)beg_ptr, (void *)end_ptr);
621 #endif
622 
623     bits_left = w;
624 #ifdef	WORDS_BIGENDIAN
625     bit_shift = BMBITS - bit_skip % BMBITS;
626 #else
627     bit_shift = bit_skip % BMBITS;
628 #endif
629 #if TRACE_AA
630     fprintf(stderr, "shift: %d\n", bit_shift);
631 #endif
632     n = 0;
633 
634     while (bits_left) {
635 #ifdef	WORDS_BIGENDIAN
636 	wid = bit_shift;
637 #else
638 	wid = BMBITS - bit_shift;
639 #endif
640 	if (wid > bits_left)
641 	    wid = bits_left;
642 	if (wid > 4) /* why? */
643 	    wid = 4;
644 #ifdef	WORDS_BIGENDIAN
645 	bit_shift -= wid;
646 #endif
647 	for (curr_ptr = beg_ptr;
648 	     curr_ptr < end_ptr;
649 	     curr_ptr = ADD(curr_ptr, bytes_wide)) {
650 #if TRACE_AA
651 	    int i;
652 	    for (i = 0; i < bytes_wide; i++) {
653 		fprintf(stderr, "%d ", *(curr_ptr + i));
654 	    }
655 	    fprintf(stderr, "\nMask: %d; count: %d\n", wid,
656 		    sample_count[ (*curr_ptr >> bit_shift) & bit_masks[wid] ]);
657 #endif
658 	    n += sample_count[ (*curr_ptr >> bit_shift) & bit_masks[wid] ];
659 	}
660 #ifdef	WORDS_BIGENDIAN
661 	if (bit_shift == 0) {
662 	    bit_shift = BMBITS;
663 	    ++beg_ptr;
664 	}
665 #else
666 	bit_shift += wid;
667 	if (bit_shift == BMBITS) {
668 	    bit_shift = 0;
669 	    ++beg_ptr;
670 	}
671 #endif
672 	bits_left -= wid;
673 	/*  	    fprintf(stderr, "bits_left: %d\n", bits_left); */
674     }
675     return n;
676 }
677 
678 extern	double	bbox_matrix[2][2];
679 extern	Boolean	bbox_scaled, bbox_rotated;
680 
moveH(int dir,long dx)681 static void moveH(int dir, long dx)
682 {
683   int pint=TATE;
684   if (pint&2) { pint&=1; dx=-dx;}
685   if (pint) {
686     DVI_H -= dx * bbox_matrix[1][0];
687     DVI_V += dx * bbox_matrix[0][0];
688   } else {
689     DVI_H += dir * dx * bbox_matrix[0][0];
690     DVI_V += dir * dx * bbox_matrix[1][0];
691   }
692   PXL_V = pixel_conv(DVI_V);
693 }
694 
moveV(int dir,long dy)695 static void moveV(int dir, long dy)
696 {
697   int pint=TATE;
698   if (pint&2) { pint&=1; dy=-dy;}
699   if (pint) {
700     DVI_H -= dy * bbox_matrix[1][1];
701     DVI_V += dy * bbox_matrix[0][1];
702   } else {
703     DVI_H += dir * dy * bbox_matrix[0][1];
704     DVI_V += dir * dy * bbox_matrix[1][1];
705   }
706   PXL_V = pixel_conv(DVI_V);
707 }
708 
709 #define PUSH_POSITION do { \
710 	dvi_h_sav = DVI_H; \
711 	dvi_v_sav = DVI_V; \
712 	pxl_v_sav = PXL_V; } while (0)
713 #define POP_POSITION do { \
714 	DVI_H = dvi_h_sav; \
715 	DVI_V = dvi_v_sav; \
716 	PXL_V = pxl_v_sav; } while (0)
717 #define DEFINE_POSITION_VAL \
718 	long dvi_h_sav, dvi_v_sav, pxl_v_sav
719 
720 #ifndef   WORDS_BIGENDIAN
721 #define EXTREME_LEFT_BIT   (1 << 0)
722 #define EXTREME_RIGHT_BIT  ((bmUnitT)(1 << (BMBITS-1)))
723 #define SHIFT_RIGHT(a)     ((a) <<= 1)
724 #else  /* WORDS_BIGENDIAN */
725 #define EXTREME_LEFT_BIT   ((bmUnitT)(1 << (BMBITS-1)))
726 #define EXTREME_RIGHT_BIT  (1 << 0)
727 #define SHIFT_RIGHT(a)     ((a) >>= 1)
728 #endif /* WORDS_BIGENDIAN */
729 
730 static	void
bbox_scale_bitmap(struct glyph * g)731 bbox_scale_bitmap(struct glyph *g)
732 {
733     bmUnitT *new_ptr;
734     int xmax, ymax, xmin, ymin, x, y;
735     double d;
736 
737     if (g->bitmap3.bits) {
738 	if (g->matrix[0][0] == (float) bbox_matrix[0][0]
739 	    && g->matrix[0][1] == (float) bbox_matrix[0][1]
740 	    && g->matrix[1][0] == (float) bbox_matrix[1][0]
741 	    && g->matrix[1][1] == (float) bbox_matrix[1][1])
742 	    return;
743 	else
744 	    free(g->bitmap.bits);
745     } else {
746 	g->bitmap3 = g->bitmap;
747 	g->x3 = g->x;
748 	g->y3 = g->y;
749     }
750 
751     xmax = ymax = xmin = ymin = 0;
752     x = g->bitmap3.w * bbox_matrix[0][0];
753     y = g->bitmap3.w * bbox_matrix[1][0];
754     if (xmax < x) xmax = x;
755     else if (xmin > x) xmin = x;
756     if (ymax < y) ymax = y;
757     else if (ymin > y) ymin = y;
758     x = g->bitmap3.w * bbox_matrix[0][0] + g->bitmap3.h * bbox_matrix[0][1];
759     y = g->bitmap3.w * bbox_matrix[1][0] + g->bitmap3.h * bbox_matrix[1][1];
760     if (xmax < x) xmax = x;
761     else if (xmin > x) xmin = x;
762     if (ymax < y) ymax = y;
763     else if (ymin > y) ymin = y;
764     x = g->bitmap3.h * bbox_matrix[0][1];
765     y = g->bitmap3.h * bbox_matrix[1][1];
766     if (xmax < x) xmax = x;
767     else if (xmin > x) xmin = x;
768     if (ymax < y) ymax = y;
769     else if (ymin > y) ymin = y;
770     xmin--; ymin--; xmax++; ymax++;
771 
772     d = bbox_matrix[0][0] * bbox_matrix[1][1]
773 	- bbox_matrix[0][1] * bbox_matrix[1][0];
774 
775     g->x = g->x3 * bbox_matrix[0][0] + g->y3 * bbox_matrix[0][1] - xmin;
776     g->y = g->x3 * bbox_matrix[1][0] + g->y3 * bbox_matrix[1][1] - ymin;
777     g->matrix[0][0] = (float) bbox_matrix[0][0];
778     g->matrix[0][1] = (float) bbox_matrix[0][1];
779     g->matrix[1][0] = (float) bbox_matrix[1][0];
780     g->matrix[1][1] = (float) bbox_matrix[1][1];
781 
782     free_bitmap2(g);
783     g->bitmap.w = xmax - xmin + 1;
784     g->bitmap.h = ymax - ymin + 1;
785     alloc_bitmap(&g->bitmap);
786     clear_bitmap(&g->bitmap);
787 
788     new_ptr = (bmUnitT *) g->bitmap.bits;
789     for (y = ymin; y <= ymax; y++) {
790 	register bmUnitT m, *cp;
791 
792 	cp = new_ptr;
793 	m = EXTREME_LEFT_BIT;
794 	for (x = xmin; x <= xmax; x++) {
795 	    int bx, by;
796 	    bx = (x * bbox_matrix[1][1] - y * bbox_matrix[0][1]) / d;
797 	    by = (y * bbox_matrix[0][0] - x * bbox_matrix[1][0]) / d;
798 	    if (bx >= 0 && bx < g->bitmap3.w
799 		&& by >= 0 && by < g->bitmap3.h
800 		&& *((bmUnitT *)g->bitmap3.bits
801 		     + by * (g->bitmap3.bytes_wide / BMBYTES) + bx / BMBITS)
802 #ifndef	WORDS_BIGENDIAN
803 		& (1 << (bx % BMBITS)))
804 #else
805 		& (1 << (BMBITS - 1 - bx % BMBITS)))
806 #endif
807 		    *cp |= m;
808 	    if (m == EXTREME_RIGHT_BIT) {
809 		m = EXTREME_LEFT_BIT;
810 		++cp;
811 	    }
812 	    else SHIFT_RIGHT(m);
813 	}
814 	new_ptr = ADD(new_ptr, g->bitmap.bytes_wide);
815     }
816 }
817 
818 static void
shrink_glyph(struct glyph * g)819 shrink_glyph(struct glyph *g)
820 {
821     int shrunk_bytes_wide, shrunk_height;
822     int rows_left, rows, init_cols;
823     int cols_left;
824     int cols;
825     bmUnitT *unshrunk_ptr, *shrunk_ptr;
826     bmUnitT m, *cp;
827     /* threshold for which a bit will be set to `on' in the shrunken bitmap */
828     int min_sample = currwin.shrinkfactor * currwin.shrinkfactor * resource.density / 100;
829     int row_num;
830 
831     /* These machinations ensure that the character is shrunk according to
832        its hot point, rather than its upper left-hand corner. */
833     g->x2 = g->x / currwin.shrinkfactor;
834     init_cols = g->x - g->x2 * currwin.shrinkfactor;
835     if (init_cols <= 0)
836 	init_cols += currwin.shrinkfactor;
837     else
838 	++g->x2;
839     g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
840     /* include row zero with the positively numbered rows */
841     row_num = g->y + 1;
842     g->y2 = row_num / currwin.shrinkfactor;
843     rows = row_num - g->y2 * currwin.shrinkfactor;
844     if (rows <= 0) {
845 	rows += currwin.shrinkfactor;
846 	--g->y2;
847     }
848     g->bitmap2.h = shrunk_height
849 	= g->y2 + ROUNDUP((int)g->bitmap.h - row_num, currwin.shrinkfactor) + 1;
850     alloc_bitmap(&g->bitmap2);
851 
852     unshrunk_ptr = (bmUnitT *) g->bitmap.bits;
853     shrunk_ptr = (bmUnitT *) g->bitmap2.bits;
854     shrunk_bytes_wide = g->bitmap2.bytes_wide;
855     rows_left = g->bitmap.h;
856     memset((char *)shrunk_ptr, '\0', shrunk_bytes_wide * shrunk_height);
857 
858     while (rows_left) {
859 	if (rows > rows_left)
860 	    rows = rows_left;
861 	cols_left = g->bitmap.w;
862 #ifndef	WORDS_BIGENDIAN
863 	m = 1; /* XXX was (1 << 0) */
864 #else
865 	m = ((bmUnitT)1 << (BMBITS - 1));
866 #endif
867 	cp = shrunk_ptr;
868 	cols = init_cols;
869 	while (cols_left) {
870 	    /* ??? */
871 	    if (cols > cols_left)
872 		cols = cols_left;
873 	    /* set a bit to `on' if it's over the threshold */
874 	    if (sample(unshrunk_ptr, g->bitmap.bytes_wide,
875 		       (int)g->bitmap.w - cols_left, cols, rows)
876 		>= min_sample)
877 		*cp |= m;
878 #ifndef	WORDS_BIGENDIAN
879 	    if (m == ((bmUnitT)1 << (BMBITS - 1))) {
880 		m = 1; /* XXX was (1 << 0) */
881 		++cp;
882 	    }
883 	    else
884 		m <<= 1;
885 #else
886 	    if (m == 1) { /* XXX was (1 << 0) */
887 		m = ((bmUnitT)1 << (BMBITS - 1));
888 		++cp;
889 	    }
890 	    else
891 		m >>= 1;
892 #endif
893 	    cols_left -= cols;
894 	    cols = currwin.shrinkfactor;
895 	}
896 	shrunk_ptr += shrunk_bytes_wide / sizeof(bmUnitT);
897 	unshrunk_ptr += rows * g->bitmap.bytes_wide / sizeof(bmUnitT);
898 	/* 	*((char **)&shrunk_ptr) += shrunk_bytes_wide; */
899 	/* 	*((char **)&unshrunk_ptr) += rows * g->bitmap.bytes_wide; */
900 	rows_left -= rows;
901 	rows = currwin.shrinkfactor;
902     }
903     g->y2 = g->y / currwin.shrinkfactor;
904     if (globals.debug & DBG_BITMAP)
905 	print_bitmap(&g->bitmap2);
906 }
907 
908 #ifdef PTEX
909 void
rotate_bitmap(struct bitmap * bm)910 rotate_bitmap(struct bitmap *bm)
911 {
912       struct bitmap new_bm;
913       bmUnitT *old_ptr, *new_ptr, *cp;
914       int    x, y;
915       bmUnitT m1, m2;
916 
917       new_bm.h = bm->w;
918       new_bm.w = bm->h;
919       alloc_bitmap(&new_bm);
920       clear_bitmap(&new_bm);
921       old_ptr = ADD(bm->bits, bm->bytes_wide * bm->h);
922       new_ptr = (bmUnitT *)new_bm.bits;
923 
924       m1 = EXTREME_LEFT_BIT;
925       for (y = 0; y < bm->h; y++) {
926 	old_ptr = SUB(old_ptr, bm->bytes_wide);
927 	cp = old_ptr;
928 	m2 = EXTREME_LEFT_BIT;
929 	for (x = 0; x < bm->w; x++) {
930 	  if (*cp & m2)
931 	    *ADD(new_ptr, x*new_bm.bytes_wide) |= m1;
932 	  if (m2 == EXTREME_RIGHT_BIT) {
933 	    m2 = EXTREME_LEFT_BIT;
934 	    ++cp;
935 	  }
936 	  else SHIFT_RIGHT(m2);
937 	}
938 	if (m1 == EXTREME_RIGHT_BIT) {
939 	  m1 = EXTREME_LEFT_BIT;
940 	  ++new_ptr;
941 	}
942 	else SHIFT_RIGHT(m1);
943       }
944 
945       free(bm->bits);
946       *bm = new_bm;
947 }
948 
949 
950 void
reverse_rotate_bitmap(struct bitmap * bm)951 reverse_rotate_bitmap(struct bitmap *bm)
952 {
953       struct bitmap new_bm;
954       bmUnitT *old_ptr, *new_ptr, *cp;
955       int    x, y;
956       bmUnitT m1, m2;
957 
958       new_bm.h = bm->w;
959       new_bm.w = bm->h;
960       alloc_bitmap(&new_bm);
961       clear_bitmap(&new_bm);
962       old_ptr = (bmUnitT *)bm->bits;
963       new_ptr = (bmUnitT *)new_bm.bits;
964 
965       m1 = EXTREME_LEFT_BIT;
966       for (y = 0; y < bm->h; y++) {
967 	cp = old_ptr;
968 	old_ptr = ADD(old_ptr, bm->bytes_wide);
969 	m2 = EXTREME_LEFT_BIT;
970 	for (x = bm->w; x--;) {
971 	  if (*cp & m2)
972 	    *ADD(new_ptr, x * new_bm.bytes_wide) |= m1;
973 	  if (m2 == EXTREME_RIGHT_BIT) {
974 	    m2 = EXTREME_LEFT_BIT;
975 	    ++cp;
976 	  }
977 	  else SHIFT_RIGHT(m2);
978 	}
979 	if (m1 == EXTREME_RIGHT_BIT) {
980 	  m1 = EXTREME_LEFT_BIT;
981 	  ++new_ptr;
982 	}
983 	else SHIFT_RIGHT(m1);
984       }
985 
986       free(bm->bits);
987       *bm = new_bm;
988 }
989 #endif /* PTEX */
990 
991 #ifdef	GREY
992 
993 #ifdef RGB_ANTI_ALIASING
994 /* void */
995 /* filter_colors(Pixel *p1, Pixel *p2) */
996 /* { */
997 /*     Pixel res1, res2; */
998 
999 /*     int res1_r = *p1 & G_visual->red_mask; */
1000 /*     int res1_g = *p1 & G_visual->green_mask; */
1001 /*     int res1_b = *p1 & G_visual->blue_mask; */
1002 
1003 /*     int res2_r = *p2 & G_visual->red_mask; */
1004 /*     int res2_g = *p2 & G_visual->green_mask; */
1005 /*     int res2_b = *p2 & G_visual->blue_mask; */
1006 /* } */
1007 
1008 static void
color_filter_image(struct glyph * g)1009 color_filter_image(struct glyph *g)
1010 {
1011     int rows = g->bitmap2.h;
1012     int cols = g->bitmap2.w;
1013     int i, j, k;
1014     int arr_size = rows * cols * 3;
1015     unsigned char *arr = xmalloc(arr_size * sizeof *arr);
1016     unsigned char *arr2 = xmalloc(arr_size * sizeof *arr2);
1017 
1018     fprintf(stderr, "total: %d\n", arr_size);
1019 
1020     for (i = 0, j = 0; j < rows; j++) {
1021 	for (k = 0; k < cols; k++) {
1022 	    Pixel p = XGetPixel(g->image2, k, j);
1023 #if TRACE_AA3
1024 	    fprintf(stderr, "k: %d, j: %d, idx: %d\n", k, j, i);
1025 #endif
1026 	    arr[i] = (p & G_visual->red_mask) >> 16;
1027 	    arr[i + 1] = (p & G_visual->green_mask) >> 8;
1028 	    arr[i + 2] = (p & G_visual->blue_mask);
1029 #if TRACE_AA3
1030 	    fprintf(stderr, "0x%.6lX -> %d, %d, %d\n", p, arr[i], arr[i + 1], arr[i + 2]);
1031 #endif
1032 	    i += 3;
1033 	}
1034     }
1035 
1036     for (i = 0; i < arr_size; i++) {
1037 	if (i == 0) { /* merge two elems */
1038 	    if (i == arr_size - 1) /* only one elem, do nothing */
1039 		break;
1040 	    arr2[i] = (int)(resource.subpixel_energy[0] * arr[i] +
1041 			    resource.subpixel_energy[1] * arr[i + 1] + 0.5);
1042 	}
1043 	else if (i == arr_size - 1) { /* merge two elems */
1044 	    if (i == 0) /* only one elem, do nothing */
1045 		break;
1046 	    arr2[i] = (int)(resource.subpixel_energy[1] * arr[i - 1] +
1047 			    resource.subpixel_energy[0] * arr[i] + 0.5);
1048 	}
1049 	else { /* merge three elems */
1050 	    arr2[i] = (int)(resource.subpixel_energy[1] * arr[i - 1] +
1051 			    resource.subpixel_energy[0] * arr[i] +
1052 			    resource.subpixel_energy[1] * arr[i + 1] + 0.5);
1053 #if TRACE_AA3
1054 	    fprintf(stderr, "%d, %d, %d -> %d\n", arr[i - 1], arr[i], arr[i + 1], arr2[i]);
1055 #endif
1056 	}
1057     }
1058 
1059     for (i = 0, j = 0; j < rows; j++) {
1060 	for (k = 0; k < cols; k++) {
1061 	    Pixel p = arr2[i] << 16 | (arr2[i + 1] << 8) | arr2[i + 2];
1062 #if TRACE_AA3
1063 	    fprintf(stderr, "%d, %d, %d -> 0x%.6lX\n", arr2[i], arr2[i + 1], arr2[i + 2], p);
1064 #endif
1065 	    XPutPixel(g->image2, k, j, p);
1066 	    i += 3;
1067 	}
1068     }
1069 
1070     free(arr);
1071     free(arr2);
1072 }
1073 
1074 #endif
1075 
1076 static void
shrink_glyph_grey(struct glyph * g)1077 shrink_glyph_grey(struct glyph *g)
1078 {
1079     int rows_left, rows, init_cols;
1080     int cols_left;
1081     int cols;
1082     int x, y;
1083     long thesample;
1084     /*     int min_sample = currwin.shrinkfactor * currwin.shrinkfactor * resource.density / 100; */
1085     Pixel onoff, onoff2;
1086     bmUnitT *unshrunk_ptr;
1087     unsigned int size;
1088     int row_num;
1089     int actual_w;
1090 
1091 #if COLOR
1092     if (fg_active != fg_current) {
1093 	do_color_change();
1094     }
1095 #endif
1096     if (pixeltbl == NULL) { /* fix #1611508 (segfault when starting with -nogrey) */
1097 	do_color_change();
1098     }
1099 
1100     /* TODO: rounding errors causing color fringing (see HACK comment below):
1101 
1102     \documentclass{article}
1103     \pagestyle{empty}
1104 
1105     \begin{document}
1106     l
1107     \end{document}
1108 
1109     With ./xdvi-xaw.bin -name xdvi -subpixel rgb -s 4 ./test.dvi:
1110 
1111     subpixel order: rgb = 1
1112     g->x2: 0, init_cols: -2
1113     AFTER: g->x2: 0, init_cols: 2
1114 
1115     but with ./xdvi-xaw.bin -name xdvi -s 4 ./test.dvi:
1116 
1117     g->x2: 0, init_cols: -3
1118     AFTER: g->x2: 0, init_cols: 1
1119     */
1120 
1121     /* These machinations ensure that the character is shrunk according to
1122        its hot point, rather than its upper left-hand corner. */
1123 #ifdef RGB_ANTI_ALIASING
1124     if (resource.subpixel_order == SUBPIXEL_NONE)
1125 	g->x2 = g->x / currwin.shrinkfactor;
1126     else {
1127 	if (g->x < 0)
1128 	    g->x2 = (int)(g->x / 3.0 - 0.5) / currwin.shrinkfactor;
1129 	else
1130 	    g->x2 = (int)(g->x / 3.0 + 0.5) / currwin.shrinkfactor;
1131     }
1132 
1133     if (resource.subpixel_order == SUBPIXEL_NONE)
1134 	init_cols = g->x - g->x2 * currwin.shrinkfactor;
1135     else {
1136 	if (g->x < 0)
1137 	    init_cols = (int)(g->x / 3.0 - 0.5) - g->x2 * currwin.shrinkfactor;
1138 	else
1139 	    init_cols = (int)(g->x / 3.0 + 0.5) - g->x2 * currwin.shrinkfactor;
1140 	fprintf(stderr, "g->x: %d, g->x2: %d, init_cols: %d\n", g->x, g->x2, init_cols);
1141     }
1142 #else
1143     g->x2 = g->x / currwin.shrinkfactor;
1144     init_cols = g->x - g->x2 * currwin.shrinkfactor;
1145 #endif
1146 
1147     if (init_cols <= 0)
1148 	init_cols += currwin.shrinkfactor;
1149     else
1150 	++(g->x2);
1151 
1152 #ifdef RGB_ANTI_ALIASING
1153 
1154     if (resource.subpixel_order == SUBPIXEL_NONE)
1155 	g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
1156     else {
1157 	fprintf(stderr, "AFTER: g->x2: %d, init_cols: %d\n", g->x2, init_cols);
1158 	/* 	fprintf(stderr, "g->bitmap.w / 3.0 + 0.5: %d; g->x / 3.0: %d; all: %d, %d\n", */
1159 	/* 		(int)(g->bitmap.w / 3.0 + 0.5), */
1160 	/* 		(int)(g->x / 3.0), */
1161 	/* 		(int)((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0), */
1162 	/* 		g->x2 + (int)((((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0) + currwin.shrinkfactor - 1) / currwin.shrinkfactor)); */
1163 	g->bitmap2.w = g->x2 + ROUNDUP((int)((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0), currwin.shrinkfactor);
1164 	/* 	fprintf(stderr, "g->bitmap.w: %d\n", g->bitmap2.w); */
1165     }
1166 #else
1167     g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
1168 #endif
1169 
1170     /* include row zero with the positively numbered rows */
1171     row_num = g->y + 1;
1172 #ifdef DBG_AA
1173     fprintf(stderr, "row_num: %d\n", row_num);
1174 #endif /* DBG_AA */
1175     /* g->y2 is the new height of the image: */
1176     g->y2 = row_num / currwin.shrinkfactor;
1177 #ifdef DBG_AA
1178     fprintf(stderr, "g->y2: %d\n", g->y2);
1179 #endif /* DBG_AA */
1180     /* in C89 and before, result of division can `truncate towards negative infinity'
1181        (i.e., round to the larger digit) for negative quotients, hence we need
1182        to test for rows < 0. OTOH, if rows = 0, use currwin.shrinkfactor instead
1183        (why?)
1184     */
1185     if ((rows = row_num - g->y2 * currwin.shrinkfactor) <= 0) {
1186 	rows += currwin.shrinkfactor;
1187 	--(g->y2);
1188     }
1189     g->bitmap2.h = g->y2 + ROUNDUP((int)g->bitmap.h - row_num, currwin.shrinkfactor) + 1;
1190 
1191 #if TRACE_AA1
1192     if (resource.subpixel_order != SUBPIXEL_NONE) {
1193 	fprintf(stderr, "\nbitmap.h: %d, bitmap.w: %d\n", g->bitmap2.h, g->bitmap2.w);
1194     }
1195 #endif /* DBG_AA */
1196 
1197     /* allocate pixmap for antialiasing ... */
1198     if (g->pixmap2 == NULL) {
1199 	g->image2 = XCreateImage(DISP, G_visual, G_depth, ZPixmap,
1200 				 0, (char *)NULL, g->bitmap2.w, g->bitmap2.h,
1201 				 BMBITS, 0);
1202 	size = g->image2->bytes_per_line * g->bitmap2.h;
1203 	g->pixmap2 = g->image2->data = xmalloc(size != 0 ? size : 1);
1204 	ASSERT(g->pixmap2_gc2 == NULL, "pixmap2_gc2 is not NULL.");
1205     }
1206     /* ... and the pixmap used for globals.gc.fore2: */
1207     if (globals.gc.fore2 != NULL && g->pixmap2_gc2 == NULL) {
1208 	size = g->image2->bytes_per_line * g->bitmap2.h;
1209 	g->pixmap2_gc2 = xmalloc(size != 0 ? size : 1);
1210     }
1211 
1212 #if 0
1213     if (resource.subpixel_order != SUBPIXEL_NONE) {
1214 	fprintf(stderr, "\n============= BITMAP ==============\n");
1215 	print_bitmap(&g->bitmap);
1216     }
1217 #endif
1218 
1219     unshrunk_ptr = (bmUnitT *)g->bitmap.bits;
1220     actual_w = g->bitmap.w;
1221     rows_left = g->bitmap.h;
1222     y = 0;
1223     /* the basic algorithm is the same as in the nogrey code, with the main
1224        exception that the return value of sample() is used. */
1225     while (rows_left) {
1226 #ifdef RGB_ANTI_ALIASING
1227 	Pixel pixel = 0;
1228 	Pixel pixel2 = 0;
1229 #endif
1230 	x = 0;
1231 	if (rows > rows_left) /* why - extra safety? */
1232 	    rows = rows_left;
1233 	cols_left = g->bitmap.w;
1234 	/*  	fprintf(stderr, "init_cols: %d\n", init_cols); */
1235 	cols = init_cols;
1236 	while (cols_left) {
1237 	    if (cols > cols_left) /* why - extra safety? */
1238 		cols = cols_left;
1239 
1240 	    thesample = sample(unshrunk_ptr, g->bitmap.bytes_wide,
1241 			       (int)g->bitmap.w - cols_left, cols, rows);
1242 
1243 	    /* 	    if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[2] != 0) */
1244 	    /* 		onoff = thesample >= min_sample ? 0xffffff : 0; */
1245 	    /* 	    else */
1246 	    onoff = pixeltbl[thesample];
1247 
1248 #ifdef XSERVER_INFO
1249 	    if (globals.debug & DBG_PK) {
1250 		int c;
1251 		/* 		fprintf(stderr, "onoff: %d\n", onoff); */
1252 		if (onoff > 65536)
1253 		    c = onoff / 65536;
1254 		else if (onoff > 256)
1255 		    c = onoff / 256;
1256 		else
1257 		    c = onoff;
1258 		if (c == 0)
1259 		    fprintf(stdout, ",..");
1260 		else
1261 		    fprintf(stdout, ",%.2x", c);
1262 	    }
1263 #endif
1264 
1265 #ifdef RGB_ANTI_ALIASING
1266 	    if (resource.subpixel_order != SUBPIXEL_NONE) {
1267 		int div = x / 3;
1268 		int rest = x % 3;
1269 
1270 		if (resource.subpixel_order == SUBPIXEL_RGB) {
1271 		    if (rest == 0)
1272 			pixel = onoff & G_visual->red_mask;
1273 		    else if (rest == 1)
1274 			pixel |= onoff & G_visual->green_mask;
1275 		    else
1276 			pixel |= onoff & G_visual->blue_mask;
1277 		}
1278 		else { /* SUBPIXEL_BGR */
1279 		    if (rest == 0)
1280 			pixel = onoff & G_visual->blue_mask;
1281 		    else if (rest == 1)
1282 			pixel |= onoff & G_visual->green_mask;
1283 		    else
1284 			pixel |= onoff & G_visual->red_mask;
1285 		}
1286 
1287 #if 0 && TRACE_AA1
1288 		fprintf(stderr, "sample: %ld; row %d, col %d, left %d: 0x%.6lx; pixel: 0x%.6lx at pos %d,%d (x:%d)\n",
1289 			thesample, rows, cols, cols_left, onoff, pixel, div, y, x);
1290 #endif /* TRACE_AA */
1291 		fprintf(stderr, "pixel at %d\n", div);
1292 		XPutPixel(g->image2, div, y, pixel);
1293 
1294 		/* HACK to fix color fringing problem */
1295 		if (div + 1 < g->bitmap2.w) {
1296 		    fprintf(stderr, "rest pixel at %d\n", div);
1297 		    XPutPixel(g->image2, div + 1, y, 0);
1298 		}
1299 	    }
1300 	    else {
1301 #if 0 && TRACE_AA1
1302 		fprintf(stderr, "sample: %ld; row %d, col %d, left %d: 0x%.6lx at pos %d, %d\n",
1303 			thesample, rows, cols, cols_left, onoff, x, y);
1304 #endif /* TRACE_AA */
1305 		XPutPixel(g->image2, x, y, onoff);
1306 	    }
1307 #else
1308 	    XPutPixel(g->image2, x, y, onoff);
1309 #endif /* RGB_ANTI_ALIASING */
1310 	    if (globals.gc.fore2 != NULL) {
1311 		onoff2 = pixeltbl_gc2[thesample];
1312 #ifdef RGB_ANTI_ALIASING
1313 		if (resource.subpixel_order != SUBPIXEL_NONE) {
1314 		    int div = x / 3;
1315 		    int rest = x % 3;
1316 
1317 		    if (resource.subpixel_order == SUBPIXEL_RGB) {
1318 			if (rest == 0)
1319 			    pixel2 = onoff2 & G_visual->red_mask;
1320 			else if (rest == 1)
1321 			    pixel2 |= onoff2 & G_visual->green_mask;
1322 			else
1323 			    pixel2 |= onoff2 & G_visual->blue_mask;
1324 		    }
1325 		    else { /* SUBPIXEL_BGR */
1326 			if (rest == 0)
1327 			    pixel2 = onoff2 & G_visual->blue_mask;
1328 			else if (rest == 1)
1329 			    pixel2 |= onoff2 & G_visual->green_mask;
1330 			else
1331 			    pixel2 |= onoff2 & G_visual->red_mask;
1332 		    }
1333 
1334 		    g->image2->data = g->pixmap2_gc2;
1335 #if TRACE_AA1
1336 		    fprintf(stderr, "fore2 at %d, %d\n", div, y);
1337 #endif
1338 		    XPutPixel(g->image2, div, y, pixel2);
1339 		    g->image2->data = g->pixmap2;
1340 		}
1341 		else {
1342 #else /* RGB_ANTI_ALIASING */
1343 		    g->image2->data = g->pixmap2_gc2;
1344 		    XPutPixel(g->image2, x, y, onoff2);
1345 		    g->image2->data = g->pixmap2;
1346 #endif
1347 #ifdef RGB_ANTI_ALIASING
1348 		}
1349 #endif
1350 	    }
1351 
1352 #if 0 && TRACE_AA1
1353 	    fprintf(stderr, "subtracting %d from %d: %d\n", cols, cols_left, cols_left - cols);
1354 #endif
1355 	    cols_left -= cols;
1356 	    cols = currwin.shrinkfactor;
1357 	    x++;
1358 	}
1359 	/* advance pointer by the number of rows covered */
1360 	/* 	fprintf(stderr, "++: %d; %d, %d\n", rows * g->bitmap.bytes_wide, g->bitmap.bytes_wide, sizeof(bmUnitT)); */
1361 	unshrunk_ptr += rows * g->bitmap.bytes_wide / sizeof(bmUnitT);
1362 	/* 	*((char **)&unshrunk_ptr) += rows * g->bitmap.bytes_wide; */
1363 	rows_left -= rows;
1364 	rows = currwin.shrinkfactor;
1365 	y++;
1366 #ifdef XSERVER_INFO
1367 	if (globals.debug & DBG_PK)
1368 	    fprintf(stdout, "\n");
1369 #endif
1370     }
1371 #ifdef XSERVER_INFO
1372     if (globals.debug & DBG_PK)
1373 	fprintf(stdout, "\n");
1374 #endif
1375 
1376 #if 0
1377     fprintf(stderr, "y: %d, bitmap.h: %d\n", y, (int)g->bitmap2.h);
1378 #endif /* DBG_AA */
1379 
1380     /* fill remaining rows not covered before (how?) */
1381     while (y < (int)g->bitmap2.h) {
1382 	for (x = 0; x < (int)g->bitmap2.w; x++) {
1383 	    /*  	    int c = *pixeltbl; */
1384 #if TRACE_AA1
1385 	    fprintf(stderr, "Remaining at %d, %d: 0x%.6lx\n", x, y, *pixeltbl);
1386 #endif
1387 	    XPutPixel(g->image2, x, y, *pixeltbl);
1388 	    /*  	    if (c == 0) */
1389 	    /*  		fprintf(stdout, ",.."); */
1390 	    /*  	    else */
1391 	    /*  		fprintf(stdout, ",%.2x", c); */
1392 	    if (globals.gc.fore2 != NULL) {
1393 		g->image2->data = g->pixmap2_gc2;
1394 #if TRACE_AA1
1395 		fprintf(stderr, "image2 at %d, %d: 0x%.6lx\n", x, y, *pixeltbl_gc2);
1396 #endif
1397 		XPutPixel(g->image2, x, y, *pixeltbl_gc2);
1398 		g->image2->data = g->pixmap2;
1399 	    }
1400 	}
1401 	y++;
1402     }
1403 
1404 #ifdef RGB_ANTI_ALIASING
1405     if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[1] != 0)
1406 	color_filter_image(g);
1407     if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[2] != 0)
1408 	color_filter_image(g);
1409 #endif
1410 
1411     g->y2 = g->y / currwin.shrinkfactor;
1412 #if COLOR
1413     g->fg = fg_current;
1414 #endif
1415 }
1416 #endif /* GREY */
1417 
1418 /*
1419  *	Find font #n.
1420  */
1421 
1422 static void
change_font(unsigned long n)1423 change_font(unsigned long n)
1424 {
1425     struct tn *tnp;
1426 
1427     if (n < currinf.tn_table_len)
1428 	currinf.fontp = currinf.tn_table[n];
1429     else {
1430 	currinf.fontp = NULL;
1431 	for (tnp = currinf.tn_head; tnp != NULL; tnp = tnp->next)
1432 	    if (tnp->TeXnumber == n) {
1433 		currinf.fontp = tnp->fontp;
1434 		break;
1435 	    }
1436     }
1437     if (currinf.fontp == NULL)
1438 	XDVI_FATAL((stderr, "Non-existent font number %ld", n));
1439     if (currinf.fontp->set_char_p == NULL)
1440 	XDVI_FATAL((stderr, "No procedure to set font %ld, %s", n, currinf.fontp->fontname));
1441     maxchar = currinf.fontp->maxchar;
1442     currinf.set_char_p = currinf.fontp->set_char_p;
1443 }
1444 
1445 
1446 /*
1447  *	Open a font file.
1448  */
1449 
1450 void
open_font_file(struct font * fontp)1451 open_font_file(struct font *fontp)
1452 {
1453     if (fontp->file == NULL) {
1454 	fontp->file = XFOPEN(fontp->filename, OPEN_MODE);
1455 	if (fontp->file == NULL)
1456 	    XDVI_FATAL((stderr, "Couldn't re-locate font file `%s'", fontp->filename));
1457     }
1458 }
1459 
1460 /*
1461  * Read and return a 0-terminated special string allocated in static memory
1462  * (i.e. contents will be overwritten by next call of this function).
1463  */
1464 
1465 static char *
read_special(FILE * fp,long nbytes)1466 read_special(FILE *fp, long nbytes)
1467 {
1468     static char *spcl = NULL;
1469     static long spcl_len = -1;
1470     char *p;
1471 
1472     if (nbytes > spcl_len) {
1473 	spcl = xrealloc(spcl, (unsigned)nbytes + 1);
1474 	spcl_len = nbytes;
1475     }
1476     p = spcl;
1477     for (;;) {
1478 	int i = currinf.end - currinf.pos;
1479 
1480 	if (i > nbytes)
1481 	    i = nbytes;
1482 	memcpy(p, (char *)currinf.pos, i);
1483 	currinf.pos += i;
1484 	p += i;
1485 	nbytes -= i;
1486 	if (nbytes == 0)
1487 	    break;
1488 	(void)xxone(fp);
1489 	--currinf.pos;
1490     }
1491     *p = '\0';
1492     return spcl;
1493 }
1494 
1495 /*
1496  *	Table used for scanning.  If >= 0, then skip that many bytes.
1497  *	M1 means end of page, M2 means special, M3 means FNTDEF,
1498  *	M4 means unrecognizable, and M5 means doesn't belong here.
1499  */
1500 
1501 #define	M1	255
1502 #define	M2	254
1503 #define	M3	253
1504 #define	M4	252
1505 #define	M5	251
1506 #define	MM	251
1507 
1508 static ubyte scantable[256] = {
1509     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* chars 0 - 127 */
1510     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1511     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1512     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1513     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1514     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1515     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1516     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1517     1, 2,	/* SET1,SET2 (128,129) */
1518 #ifdef PTEX
1519     /* SET3,SET4,SETRULE,PUT1,PUT2,PUT3,PUT4,PUTRULE,NOP,BOP (130-139) */
1520     3, 4, 8, 1, 2, 3, 4, 8, 0, 44,
1521 #else
1522     /* -,-,SETRULE,PUT1,PUT2,-,-,PUTRULE,NOP,BOP (132-139) */
1523     M4, M4, 8, 1, 2, M4, M4, 8, 0, 44,
1524 #endif
1525     M1, 0, 0, 1, 2, 3, 4, 0, 1, 2,	/* EOP,PUSH,POP,RIGHT1-4,W0M2 (140-149) */
1526     3, 4, 0, 1, 2, 3, 4, 1, 2, 3,	/* W3-4,X0-4,DOWN1-3 (150-159) */
1527     4, 0, 1, 2, 3, 4, 0, 1, 2, 3,	/* DOWN4,Y0-4,Z0-3 (160-169) */
1528     4,	/* Z4 (170) */
1529     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* change font 171 - 234 */
1530     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1531     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1532     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1533     1, 2, 3, 4, M2,	/* FNT1-4,XXX1 (235-239) */
1534     /* XXX2-4,FNTDEF1-4,PRE,POST,POSTPOST (240-249) */
1535     M2, M2, M2, M3, M3, M3, M3, M5, M5, M5,
1536     0, 0, M4, M4, M4, M4
1537 };	/* SREFL,EREFL,-,-,-,- (250-255) */
1538 
1539 /*
1540  *	This is the generic scanning routine.  It assumes that currinf, etc.
1541  *	are ready to go at the start of the page to be scanned.
1542  */
1543 
1544 
1545 
1546 Boolean
spcl_scan(Boolean (* spcl_proc)(char * str,int str_len,void * data),void * data,Boolean return_if_found,FILE * fp)1547 spcl_scan(Boolean (*spcl_proc)(char *str, int str_len, void *data), void *data, Boolean return_if_found, FILE *fp)
1548 {
1549     ubyte ch;
1550     ubyte n;
1551     long a;
1552 
1553     for (;;) {
1554 	ch = xone(fp);
1555 	/*  	print_dvi(ch); */
1556 	n = scantable[ch];
1557 	if (n < MM)
1558 	    while (n-- != 0)
1559 		(void)xone(fp);
1560 	else if (n == M1)
1561 	    break;	/* end of page */
1562 	else
1563 	    switch (n) {
1564 	    case M2:	/* special */
1565 		a = xnum(fp, ch - XXX1 + 1);
1566 		if (a > 0) {
1567 		    if (spcl_proc(read_special(fp, a), a, data) && return_if_found) {
1568 			return True;
1569 		    }
1570 		}
1571 		break;
1572 	    case M3:	/* FNTDEF */
1573 		xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
1574 		ch = xone(fp);
1575 		xskip(fp, (long)ch + (long)xone(fp));
1576 		break;
1577 #ifndef PTEX
1578 	    case M4:	/* unrecognizable */
1579 		XDVI_FATAL((stderr, "unknown op-code %d", ch));
1580 		break;
1581 #endif /* !PTEX */
1582 	    case M5:	/* doesn't belong */
1583 		dvi_fmt_error("spcl_scan: shouldn't happen: %s encountered",
1584 			      dvi_table2[ch - (FNTNUM0 + 64)]);
1585 		break;
1586 	    }
1587     }
1588     return False;
1589 }
1590 
1591 #define	xspell_conv(n)	spell_conv0(n, current_dimconv)
1592 
1593 /*
1594  *	Prescanning routine for dvi file.  This looks for specials like
1595  *	`header=' and `!'.
1596  */
1597 
1598 void
prescan(FILE * fp)1599 prescan(FILE *fp)
1600 {
1601     if (fp == NULL) {
1602 	return;
1603     }
1604 
1605     TRACE_FILES((stderr, "prescan on %p", (void *)fp));
1606 
1607     (void)lseek(fileno(fp), pageinfo_get_offset(scanned_page + 1), SEEK_SET);
1608     G_dvi_buf_ptr = dvi_buffer;
1609     currinf.pos = currinf.end = G_dvi_buf_ptr;
1610     for (;;) {
1611 	if (scanned_page == -1) { /* on first page */
1612 	    TRACE_FILES((stderr, "prescan on page 1"));
1613 	    pageinfo_set_page_width(scanned_page + 1, pageinfo_get_page_width(total_pages));
1614 	    pageinfo_set_page_height(scanned_page + 1, pageinfo_get_page_height(total_pages));
1615 	    pageinfo_set_window_width(scanned_page + 1, pageinfo_get_window_width(total_pages));
1616 	    pageinfo_set_window_height(scanned_page + 1, pageinfo_get_window_height(total_pages));
1617 	}
1618 	else {
1619 	    TRACE_FILES((stderr, "prescan on page %d", scanned_page));
1620 	    pageinfo_set_page_width(scanned_page + 1, pageinfo_get_page_width(scanned_page));
1621 	    pageinfo_set_page_height(scanned_page + 1, pageinfo_get_page_height(scanned_page));
1622 	    pageinfo_set_window_width(scanned_page + 1, pageinfo_get_window_width(scanned_page));
1623 	    pageinfo_set_window_height(scanned_page + 1, pageinfo_get_window_height(scanned_page));
1624 	}
1625 	if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE) {
1626 	    break;
1627 	}
1628 	/* NOTE:  longjmp(globals.ev.canit) should not be done within
1629 	   read_events(). */
1630 	htex_prescan_save();
1631 	htex_prescan_initpage();
1632 
1633 	if (!setjmp(globals.ev.canit)) {
1634 	    struct htex_prescan_data data;
1635 	    int pre_depth, depth;
1636 	    data.pageno = scanned_page + 1;
1637 	    data.scan_type = HTEX_ANCHOR_NUM; /* just for the anchor numbers */
1638 	    pre_depth = htex_prescan_get_depth();
1639 	    (void)spcl_scan(scan_special, &data, False, fp);
1640 
1641 	    depth = htex_prescan_get_depth();
1642 
1643 	    if (depth > pre_depth) {
1644 		/* we have a mismatched anchor. We currently don't deal with
1645 		   _nested_ mismatched anchors (ugh), so there's only one
1646 		   anchor string that can be used as info on the next page. */
1647 		int anchor_num = htex_prescan_get_mismatched_anchor_num(depth);
1648 		/* scan again to find the anchor string at anchor number `anchor_num' */
1649 		(void)lseek(fileno(fp), pageinfo_get_offset(scanned_page + 1), SEEK_SET);
1650 		currinf.pos = currinf.end = G_dvi_buf_ptr;
1651 		data.anchor_num = anchor_num;
1652 		data.scan_type = HTEX_ANCHOR_STRING;
1653 		htex_prescan_reset_firstpass();
1654 		(void)spcl_scan(scan_special, &data, False, fp);
1655 		depth = htex_prescan_get_depth();
1656 	    }
1657 	    else if (depth > 0 && scanned_page >= 0) { /* mismatch was on a previous page */
1658 		htex_prescan_carry_over(scanned_page, scanned_page + 1);
1659 	    }
1660 	}
1661 	else { /* if interrupted */
1662 	    htex_prescan_restore(scanned_page + 1);
1663 #if PS
1664 	    psp.interrupt();
1665 #endif
1666 	    break;
1667 	}
1668 	if (globals.ev.flags & EV_GE_NEWPAGE)
1669 	    break;
1670 	++scanned_page;
1671 #if COLOR
1672 	if (scanned_page_color < scanned_page) {
1673 	    scan_color_eop();
1674 	    scanned_page_color = scanned_page;
1675 	}
1676 #endif
1677 #if PS
1678 	if (scanned_page_ps < scanned_page)
1679 	    scanned_page_ps = scanned_page;
1680 #endif
1681 	if (scanned_page >= current_page)
1682 	    break;
1683     }
1684 
1685 #if PS
1686     if (!(globals.ev.flags & EV_GE_NEWPAGE))
1687 	psp.endheader();
1688 #endif
1689 }
1690 
1691 /*
1692  *	Routines to print characters.
1693  */
1694 
1695 #ifdef PTEX
1696 static void
set_char_rotate_glyph(struct glyph * g)1697 set_char_rotate_glyph(struct glyph *g)
1698 {
1699   int tmp, rot = TATE - g->tdir;
1700   if (rot<0) rot+=4;
1701   switch(rot) {
1702   case 2:
1703     rotate_bitmap(&g->bitmap);
1704     tmp = g->x;
1705     g->x = g->bitmap.w - g->y;
1706     g->y = tmp;
1707     g->tdir = TATE;
1708     free_bitmap2(g);
1709   case 1:
1710     rotate_bitmap(&g->bitmap);
1711     tmp = g->x;
1712     g->x = g->bitmap.w - g->y;
1713     g->y = tmp;
1714     g->tdir = TATE;
1715     free_bitmap2(g);
1716     break;
1717   case 3:
1718     reverse_rotate_bitmap(&g->bitmap);
1719     tmp = g->x;
1720     g->x = g->y;
1721     g->y = g->bitmap.h - tmp;
1722     g->tdir = TATE;
1723     free_bitmap2(g);
1724   }
1725 }
1726 #endif /* PTEX */
1727 
1728 static setcharRetvalT
1729 common_set_char(
1730 #ifdef TEXXET
1731 		wide_ubyte,
1732 #endif
1733 		struct glyph *);
1734 
1735 setcharRetvalT
set_char(wide_ubyte cmd,wide_ubyte ch)1736 set_char(
1737 #ifdef TEXXET
1738 	 wide_ubyte cmd,
1739 #endif
1740 	 wide_ubyte ch)
1741 {
1742     struct glyph *g;
1743 
1744     if (ch > maxchar)
1745 	realloc_font(currinf.fontp, (wide_ubyte)ch);
1746     if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
1747 	if (g->addr == 0) {
1748 	    if (!resource.hush_chars)
1749 		XDVI_WARNING((stderr, "Character %d not defined in font %s", ch, currinf.fontp->fontname));
1750 	    g->addr = -1;
1751 #ifdef TEXXET
1752 	    return;
1753 #else
1754 	    return 0L;
1755 #endif
1756 	}
1757 	if (g->addr == -1) {
1758 #ifdef TEXXET
1759 	    return;
1760 #else
1761 	    return 0L; /* previously flagged missing char */
1762 #endif
1763 	}
1764 #if FREETYPE
1765 	if (currinf.fontp->ft == NULL)	/* if not freetype font */
1766 #endif
1767 	{
1768 	    open_font_file(currinf.fontp);
1769 	    fseek(currinf.fontp->file, g->addr, SEEK_SET);
1770 	}
1771 	(*currinf.fontp->read_char) (currinf.fontp, ch);
1772 	if (globals.debug & DBG_BITMAP)
1773 	    print_char((ubyte) ch, g);
1774 	currinf.fontp->timestamp = ++current_timestamp;
1775     }
1776 #ifdef PTEX
1777     set_char_rotate_glyph(g);
1778 #endif /* PTEX */
1779 #ifdef TEXXET
1780     common_set_char(cmd, g);
1781 #else
1782     return common_set_char(g);
1783 #endif
1784 }
1785 
1786 static setcharRetvalT
common_set_char(wide_ubyte cmd,struct glyph * g)1787 common_set_char(
1788 #ifdef TEXXET
1789 		wide_ubyte cmd,
1790 #endif
1791 		struct glyph *g)
1792 {
1793 #ifdef	TEXXET
1794     DEFINE_POSITION_VAL;
1795     PUSH_POSITION;
1796     if (! TATE && currinf.dir < 0)
1797 	moveH(1, -g->dvi_adv);
1798 
1799     if (scan_frame == NULL) {
1800 #endif
1801 	if (bbox_scaled)
1802 	    bbox_scale_bitmap(g);
1803 	else if (g->bitmap3.bits) {
1804 	    free(g->bitmap.bits);
1805 	    g->bitmap = g->bitmap3;
1806 	    g->bitmap3.bits = NULL;
1807 	    g->x = g->x3;
1808 	    g->y = g->y3;
1809 	    free_bitmap2(g);
1810 	}
1811 
1812 #ifdef RGB_ANTI_ALIASING
1813 	if (currwin.shrinkfactor == -1) {
1814 	    put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
1815 	}
1816 #ifdef __GNUC__
1817 #warning TODO: implement horizontal AA at shrink 1
1818 #endif
1819 #else
1820 	if (currwin.shrinkfactor == 1) {
1821 	    put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
1822 	}
1823 #endif
1824 	else {
1825 #ifdef	GREY
1826 	    if (resource.use_grey) {
1827 		if (g->pixmap2 == NULL) {
1828 #ifdef DBG_AA
1829 		    fprintf(stderr, "shrinking the bitmap!\n");
1830 #endif /* DBG_AA */
1831 		    /*  		    print_bitmap(&g->bitmap); */
1832 		    shrink_glyph_grey(g);
1833 		}
1834 		put_image(g, PXL_H - g->x2, PXL_V - g->y2);
1835 	    }
1836 	    else {
1837 		if (g->bitmap2.bits == NULL) {
1838 		    shrink_glyph(g);
1839 		}
1840 		put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
1841 	    }
1842 #else
1843 	    if (g->bitmap2.bits == NULL) {
1844 		shrink_glyph(g);
1845 	    }
1846 	    put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
1847 #endif
1848 	}
1849 #ifdef TEXXET
1850     }
1851     if (cmd == PUT1 || (resource.omega && cmd == PUT2))
1852 	POP_POSITION;
1853     else if (TATE || currinf.dir > 0)
1854 	moveH(1, g->dvi_adv);
1855     return;
1856 #else
1857     return g->dvi_adv;
1858 #endif
1859 }
1860 
1861 /*
1862  *	Routines to print characters.
1863  */
1864 
1865 static void
warn_setting_empty_char(void)1866 warn_setting_empty_char(void)
1867 {
1868 	/* this is probably serious enough for a GUI warning */
1869 	popup_message(globals.widgets.top_level,
1870 		MSG_ERR,
1871 		/* helptext */
1872 		"Xdvi tries all of the following possibilities in turn, and "
1873 		  "all of them have failed:\n\n"
1874 		"  (1) If the resource type1 is set, try a PostScript Type 1 "
1875 		  "version of a font.\n\n"
1876 		"  (2) Otherwise, or if the Type 1 version hasn't been found, "
1877 		  "try to "
1878 		"locate, or generate via mktexpk, a TeX Pixel (PK) version of "
1879 		  "the font.\n\n"
1880 		"  (3) Use the fallback font defined via the \"altfont\" "
1881 		  "resource (cmr10 by default), "
1882 		"both as Type 1 and as PK version, at various resolutions.\n\n"
1883 		"It seems that your font setup is defective.\n",
1884 		/* errmsg */
1885 		"Error loading font %s: Neither a Type 1 version nor "
1886 		"a pixel version could be found. The character(s) "
1887 		"will be left blank.",
1888 		currinf.fontp->fontname);
1889 }
1890 
1891 static setcharRetvalT
set_empty_char(wide_ubyte cmd,wide_ubyte ch)1892 set_empty_char(
1893 #ifdef TEXXET
1894 	       wide_ubyte cmd,
1895 #endif
1896 	       wide_ubyte ch)
1897 {
1898 #ifdef TEXXET
1899     UNUSED(cmd);
1900 #endif
1901     UNUSED(ch);
1902 #ifdef TEXXET
1903     return;
1904 #else
1905     return 0L;
1906 #endif
1907 }
1908 
1909 #ifdef PTEX
1910 setcharRetvalT
set_char2(wide_ubyte cmd,wide_ubyte ch)1911 set_char2(
1912 #ifdef TEXXET
1913 	 wide_ubyte cmd,
1914 #endif
1915 	 wide_ubyte ch)
1916 {
1917     struct glyph *g;
1918 
1919     if (ch > currinf.fontp->maxchar ||
1920 	(g = currinf.fontp->kglyph[ch]) == NULL || g->bitmap.bits == NULL) {
1921 	(*currinf.fontp->read_char)(currinf.fontp, ch);
1922 	g = currinf.fontp->kglyph[ch];
1923 	free_bitmap2(g);
1924 	g->tdir = currinf.fontp->dir;
1925 	if (globals.debug & DBG_BITMAP) print_char((ubyte) ch, g);
1926     }
1927     set_char_rotate_glyph(g);
1928 #ifdef TEXXET
1929     common_set_char(cmd, g);
1930 #else
1931     return common_set_char(g);
1932 #endif
1933 }
1934 #endif /* PTEX */
1935 
1936 setcharRetvalT
load_n_set_char(wide_ubyte cmd,wide_ubyte ch)1937 load_n_set_char(
1938 #ifdef TEXXET
1939 		wide_ubyte cmd,
1940 #endif
1941 		wide_ubyte ch)
1942 {
1943     if (!load_font(currinf.fontp
1944 #if DELAYED_MKTEXPK
1945 		   , True
1946 #endif
1947 		   )) {	/* if not found */
1948 	if (globals.ev.flags & EV_GE_NEWDOC) {	/* if abort */
1949 	    longjmp(globals.ev.canit, 1);
1950 	}
1951 
1952 	currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
1953 	warn_setting_empty_char();
1954 
1955 #ifdef TEXXET
1956 	return;
1957 #else
1958 	return 0L;
1959 #endif
1960     }
1961     maxchar = currinf.fontp->maxchar;
1962     currinf.set_char_p = currinf.fontp->set_char_p;
1963 #ifdef TEXXET
1964     (*currinf.set_char_p) (cmd, ch);
1965     return;
1966 #else
1967     return (*currinf.set_char_p) (ch);
1968 #endif
1969 }
1970 
1971 setcharRetvalT
set_vf_char(wide_ubyte cmd,wide_ubyte ch)1972 set_vf_char(
1973 #ifdef TEXXET
1974 	    wide_ubyte cmd,
1975 #endif
1976 	    wide_ubyte ch)
1977 {
1978     struct macro *m;
1979     struct drawinf oldinfo;
1980     wide_ubyte oldmaxchar;
1981     static ubyte c;
1982 #ifdef TEXXET
1983     DEFINE_POSITION_VAL;
1984 #endif
1985 
1986     if (ch > maxchar)
1987 	realloc_virtual_font(currinf.fontp, ch);
1988     if ((m = &currinf.fontp->macro[ch])->pos == NULL) {
1989 	if (!resource.hush_chars)
1990 	    XDVI_WARNING((stderr, "Character %d not defined in font %s", ch, currinf.fontp->fontname));
1991 	m->pos = m->end = &c;
1992 #ifdef TEXXET
1993 	return;
1994 #else
1995 	return 0L;
1996 #endif
1997     }
1998 #ifdef TEXXET
1999     PUSH_POSITION;
2000     if (! TATE && currinf.dir < 0)
2001 	moveH(1, -m->dvi_adv);
2002     if (scan_frame == NULL) {
2003 #endif
2004 	oldinfo = currinf;
2005 	if (!currinf.virtual)
2006 	    dvi_pointer_frame = &oldinfo;
2007 	oldmaxchar = maxchar;
2008 	WW = XX = YY = ZZ = 0;
2009 	currinf.tn_table_len = VFTABLELEN;
2010 	currinf.tn_table = currinf.fontp->vf_table;
2011 	currinf.tn_head = currinf.fontp->vf_chain;
2012 	currinf.pos = m->pos;
2013 	currinf.end = m->end;
2014 	currinf.virtual = currinf.fontp;
2015 
2016 	draw_part(globals.dvi_file.bak_fp, current_frame, currinf.fontp->dimconv);
2017 	if (currinf.pos != currinf.end + 1)
2018 	    dvi_fmt_error("virtual character macro does not end correctly");
2019 	currinf = oldinfo;
2020 	if (!currinf.virtual)
2021 	    dvi_pointer_frame = &currinf;
2022 	maxchar = oldmaxchar;
2023 #ifdef TEXXET
2024     }
2025     if (cmd == PUT1 || (resource.omega && cmd == PUT2))
2026 	POP_POSITION;
2027     else if (TATE || currinf.dir > 0)
2028 	moveH(1, m->dvi_adv);
2029     return;
2030 #else
2031     return m->dvi_adv;
2032 #endif
2033 }
2034 
2035 
2036 #if FREETYPE
2037 
2038 /*
2039  *	set_ft_char() is used as a set_char routine to handle delayed loading
2040  *	of freetype fonts.  See more details in ft.c.
2041  */
2042 
2043 static void
do_load_freetype_font(void)2044 do_load_freetype_font(void)
2045 {
2046 	if (!load_ft_font(currinf.fontp)) {
2047 	    /* Revert to non-scalable font */
2048 	    struct ftfont *ftp;
2049 
2050 	    TRACE_FT((stderr,
2051 	      "Font %s is not loadable; reverting to non-scalable font",
2052 	      currinf.fontp->fontname));
2053 
2054 	    ftp = currinf.fontp->ft;
2055 	    ftp->t1->bad = True;
2056 	    if (currinf.fontp == ftp->first_size) {
2057 		if (currinf.fontp->next_size == NULL) {
2058 		    /* if this is the only size of this font face */
2059 		    ftp->t1->ft = NULL;
2060 		    free(ftp);
2061 		}
2062 		else {
2063 		    struct font	*fontp2;
2064 
2065 		    ftp->first_size = fontp2 = currinf.fontp->next_size;
2066 		    /*
2067 		     * Opening the file might have succeeded at some other size,
2068 		     * so we need to transfer that information to the next
2069 		     * record in case it was put here.
2070 		     */
2071 		    fontp2->file = currinf.fontp->file;
2072 		    currinf.fontp->file = NULL;
2073 		    fontp2->filename = currinf.fontp->filename;
2074 		    currinf.fontp->filename = NULL;
2075 		    fontp2->timestamp = currinf.fontp->timestamp;
2076 		}
2077 	    }
2078 	    else {
2079 		struct font *fontp2;
2080 
2081 		fontp2 = ftp->first_size;
2082 		while (fontp2->next_size != currinf.fontp)
2083 		    fontp2 = fontp2->next_size;
2084 		fontp2->next_size = currinf.fontp->next_size;
2085 	    }
2086 	    currinf.fontp->ft = NULL;
2087 	    /* The virtual font machinery will take it from here.  */
2088 	    /* That will call load_font(), but it won't take us back to the */
2089 	    /* freetype font, because that font will have been marked bad.  */
2090 	    currinf.set_char_p = load_n_set_char;
2091 	}
2092 	else
2093 	    currinf.set_char_p = currinf.fontp->set_char_p = set_char;
2094 }
2095 
2096 setcharRetvalT
set_ft_char(wide_ubyte cmd,wide_ubyte ch)2097 set_ft_char(
2098 # if TEXXET
2099 	    wide_ubyte cmd,
2100 # endif
2101 	    wide_ubyte ch)
2102 {
2103 	do_load_freetype_font();
2104 
2105 # if !TEXXET
2106 	return (*currinf.set_char_p)(ch);
2107 # else
2108 	(*currinf.set_char_p)(cmd, ch);
2109 	return;
2110 # endif
2111 }
2112 
2113 #endif /* FREETYPE */
2114 
2115 
2116 static setcharRetvalT
set_no_char(wide_ubyte cmd,wide_ubyte ch)2117 set_no_char(
2118 #ifdef TEXXET
2119 	    wide_ubyte cmd,
2120 #endif
2121 	    wide_ubyte ch)
2122 {
2123     if (currinf.virtual) {
2124 	currinf.fontp = currinf.virtual->first_font;
2125 	if (currinf.fontp != NULL) {
2126 	    maxchar = currinf.fontp->maxchar;
2127 	    currinf.set_char_p = currinf.fontp->set_char_p;
2128 #ifdef TEXXET
2129 	    (*currinf.set_char_p) (cmd, ch);
2130 	    return;
2131 #else
2132 	    return (*currinf.set_char_p) (ch);
2133 #endif
2134 	}
2135     }
2136     dvi_fmt_error("set_no_char: attempt to set character of unknown font");
2137     exit(0);
2138     /* NOTREACHED */
2139 }
2140 
2141 
2142 /*
2143  *	Set rule.  Arguments are coordinates of lower left corner.
2144  */
2145 
2146 static	void
set_rotated_rule(long h,long w)2147 set_rotated_rule(long h, long w)
2148 {
2149     XPoint points[4];
2150     int pint = TATE;
2151     if (pint&2) { pint&=1;
2152       w=-w; h=-h;
2153     }
2154     points[0].x = PXL_H - currwin.base_x;
2155     points[0].y = PXL_V - currwin.base_y;
2156 #ifdef PTEX
2157     if (pint) {
2158 	points[1].x = -w * bbox_matrix[1][0];
2159 	points[1].y = w * bbox_matrix[0][0];
2160 	points[2].x = h * bbox_matrix[1][1];
2161 	points[2].y = -h * bbox_matrix[0][1];
2162     } else
2163 #endif /* PTEX */
2164     {
2165 	points[1].x = DIR * w * bbox_matrix[0][0];
2166 	points[1].y = DIR * w * bbox_matrix[1][0];
2167 	points[2].x = -h * bbox_matrix[0][1];
2168 	points[2].y = -h * bbox_matrix[1][1];
2169     }
2170     points[3].x = -points[1].x;
2171     points[3].y = -points[1].y;
2172 
2173     if (--globals.ev.ctr == 0) {
2174 	if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
2175 	    /* fprintf(stderr, "longjmp1!\n"); */
2176 	    longjmp(globals.ev.canit, 1);
2177 	}
2178     }
2179 #if COLOR
2180     if (fg_active != fg_current)
2181 	do_color_change();
2182 #endif
2183     XFillPolygon(DISP, currwin.win,
2184 		 htex_inside_href ? globals.gc.high: globals.gc.rule,
2185 		 points, 4, Convex, CoordModePrevious);
2186 }
2187 
2188 static void
set_rule(int h,int w)2189 set_rule(int h, int w)
2190 {
2191     if (bbox_rotated) {
2192 	set_rotated_rule(h, w);
2193 	return;
2194     }
2195     h = h * bbox_matrix[1][1];
2196     w = w * bbox_matrix[0][0];
2197 #ifdef PTEX
2198     if (TATE==1)
2199 	put_rule(PXL_H, PXL_V, (unsigned int)h, (unsigned int)w);
2200     else if (TATE==3) /* dtou */
2201 	put_rule(PXL_H - h + 1, PXL_V - w + 1, (unsigned int)h, (unsigned int)w);
2202     else
2203 #endif /* PTEX */
2204 #ifdef TEXXET
2205     put_rule(PXL_H - (currinf.dir < 0 ? w - 1 : 0), PXL_V - h + 1,
2206 	     (unsigned int)w, (unsigned int)h);
2207 #else
2208     put_rule(PXL_H, PXL_V - h + 1, (unsigned int)w, (unsigned int)h);
2209 #endif
2210 }
2211 
2212 
2213 /*
2214  *	Interpret a sequence of dvi bytes (either the page from the dvi file,
2215  *	or a character from a virtual font).
2216  */
2217 
2218 static void
draw_part(FILE * fp,struct frame * minframe,double current_dimconv)2219 draw_part(FILE *fp, struct frame *minframe, double current_dimconv)
2220 {
2221     ubyte ch = 0;
2222 #ifdef TEXXET
2223     struct drawinf oldinfo;
2224     wide_ubyte oldmaxchar = 0;
2225     off_t file_pos = 0;
2226     int refl_count = 0;
2227 #endif
2228     int pause_cnt = 0;
2229 
2230     globals.pausing.flag = False;
2231 
2232     currinf.fontp = NULL;
2233     currinf.set_char_p = set_no_char;
2234 #ifdef TEXXET
2235     currinf.dir = 1;
2236     scan_frame = NULL;	/* indicates we're not scanning */
2237 #endif
2238 
2239     for (;;) {
2240 	ch = xone(fp);
2241 	if (globals.debug & DBG_DVI) {
2242 	    print_dvi(ch);
2243 	}
2244 	if (ch <= (ubyte)(SETCHAR0 + 127)) {
2245 #ifdef TEXXET
2246 	    (*currinf.set_char_p) (ch, ch);
2247 #else
2248 	    moveH(1, (*currinf.set_char_p) (ch));
2249 #endif
2250 	}
2251 	else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63)) {
2252 	    change_font((unsigned long)(ch - FNTNUM0));
2253 	}
2254 	else {
2255 	    long a, b;
2256 
2257 	    switch (ch) {
2258 	    case SET1:
2259 	    case PUT1:
2260 #ifdef TEXXET
2261 		(*currinf.set_char_p) (ch, xone(fp));
2262 #else
2263 		a = (*currinf.set_char_p) (xone(fp));
2264 		if (ch != PUT1)
2265 		    moveH(1, a);
2266 #endif
2267 		break;
2268 
2269 	    case SET2:
2270 	    case PUT2:
2271 		if (!resource.omega)
2272 		    dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
2273 				  __FILE__, __LINE__, ch);
2274 		else {
2275 #ifdef TEXXET
2276 		    (*currinf.set_char_p) (ch, xnum(fp, 2));
2277 #else
2278 		    a = (*currinf.set_char_p) (xnum(fp, 2));
2279 		    if (ch != PUT2)
2280 			moveH(1, a);
2281 #endif
2282 		}
2283 		break;
2284 
2285 	    case SET3:
2286 	    case PUT3:
2287 		if (!resource.omega)
2288 		    dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
2289 				  __FILE__, __LINE__, ch);
2290 		else {
2291 #ifdef TEXXET
2292 		    (*currinf.set_char_p) (ch, xnum(fp, 3));
2293 #else
2294 		    a = (*currinf.set_char_p) (xnum(fp, 3));
2295 		    if (ch != PUT3)
2296 			moveH(1, a);
2297 #endif
2298 		}
2299 		break;
2300 
2301 	    case SET4:
2302 	    case PUT4:
2303 		if (!resource.omega)
2304 		    dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
2305 				  __FILE__, __LINE__, ch);
2306 		else {
2307 #ifdef TEXXET
2308 		    (*currinf.set_char_p) (ch, xnum(fp, 4));
2309 #else
2310 		    a = (*currinf.set_char_p) (xnum(fp, 4));
2311 		    if (ch != PUT4)
2312 			moveH(1, a);
2313 #endif
2314 		}
2315 		break;
2316 
2317 	    case SETRULE:
2318 		/* Be careful, dvicopy outputs rules with
2319 		   height = 0x80000000.  We don't want any
2320 		   SIGFPE here. */
2321 		a = xsfour(fp);
2322 		b = xspell_conv(xsfour(fp));
2323 		if (a > 0 && b > 0
2324 #ifdef TEXXET
2325 		    && scan_frame == NULL
2326 #endif
2327 		    ) {
2328 		    set_rule(pixel_round(xspell_conv(a)), pixel_round(b));
2329 		}
2330 		moveH(DIR, b);
2331 		break;
2332 
2333 	    case PUTRULE:
2334 		a = xspell_conv(xsfour(fp));
2335 		b = xspell_conv(xsfour(fp));
2336 		if (a > 0 && b > 0
2337 #ifdef TEXXET
2338 		    && scan_frame == NULL
2339 #endif
2340 		    ) {
2341 		    set_rule(pixel_round(a), pixel_round(b));
2342 		}
2343 		break;
2344 
2345 	    case NOP:
2346 		break;
2347 
2348 	    case BOP:
2349 		xskip(fp, (long)11 * 4);
2350 		DVI_H = OFFSET_X;
2351 		DVI_V = OFFSET_Y;
2352 		PXL_V = pixel_conv(DVI_V);
2353 		WW = XX = YY = ZZ = 0;
2354 		bbox_matrix[0][0] = bbox_matrix[1][1] = 1.0;
2355 		bbox_matrix[0][1] = bbox_matrix[1][0] = 0.0;
2356 		bbox_scaled = bbox_rotated = False;
2357 		break;
2358 
2359 	    case EOP:
2360 		if (current_frame != minframe)
2361 		    dvi_fmt_error("%s:%d: draw_part: stack not empty at EOP", __FILE__, __LINE__);
2362 		return;
2363 
2364 	    case PUSH:
2365 		if (current_frame->next == NULL) {
2366 		    struct frame *newp = xmalloc(sizeof *newp);
2367 
2368 		    current_frame->next = newp;
2369 		    newp->prev = current_frame;
2370 		    newp->next = NULL;
2371 		}
2372 		current_frame = current_frame->next;
2373 		current_frame->data = currinf.data;
2374 		break;
2375 
2376 	    case POP:
2377 		if (current_frame == minframe)
2378 		    dvi_fmt_error("%s:%d: draw_part: more POPs than PUSHes", __FILE__, __LINE__);
2379 		currinf.data = current_frame->data;
2380 		current_frame = current_frame->prev;
2381 		break;
2382 
2383 #ifdef TEXXET
2384 	    case SREFL:
2385 		if (scan_frame == NULL) {
2386 		    /* we're not scanning:  save some info. */
2387 		    oldinfo = currinf;
2388 		    oldmaxchar = maxchar;
2389 		    if (!currinf.virtual)
2390 			file_pos = xtell(fp, currinf.pos);
2391 		    scan_frame = current_frame;	/* now we're scanning */
2392 		    refl_count = 0;
2393 		    break;
2394 		}
2395 		/* we are scanning */
2396 		if (current_frame == scan_frame)
2397 		    ++refl_count;
2398 		break;
2399 
2400 	    case EREFL:
2401 		if (scan_frame != NULL) {	/* if we're scanning */
2402 		    if (current_frame == scan_frame && --refl_count < 0) {
2403 			/* we've hit the end of our scan */
2404 			scan_frame = NULL;
2405 			/* first:  push */
2406 			if (current_frame->next == NULL) {
2407 			    struct frame *newp = xmalloc(sizeof *newp);
2408 
2409 			    current_frame->next = newp;
2410 			    newp->prev = current_frame;
2411 			    newp->next = NULL;
2412 			}
2413 			current_frame = current_frame->next;
2414 			current_frame->data = currinf.data;
2415 			/* next:  restore old file position, XX, etc. */
2416 			if (!currinf.virtual) {
2417 			    off_t bgn_pos = xtell(fp, G_dvi_buf_ptr);
2418 
2419 			    if (file_pos >= bgn_pos) {
2420 				oldinfo.pos = dvi_buffer + (file_pos - bgn_pos);
2421 				oldinfo.end = currinf.end;
2422 			    }
2423 			    else {
2424 				(void)lseek(fileno(fp), file_pos, SEEK_SET);
2425 				oldinfo.pos = oldinfo.end;
2426 			    }
2427 			}
2428 			currinf = oldinfo;
2429 			maxchar = oldmaxchar;
2430 			/* and then:  recover position info. */
2431 			DVI_H = current_frame->data.dvi_h;
2432 			DVI_V = current_frame->data.dvi_v;
2433 			PXL_V = current_frame->data.pxl_v;
2434 			/* and finally, reverse direction */
2435 			currinf.dir = -currinf.dir;
2436 		    }
2437 		    break;
2438 		}
2439 		/* we're not scanning, */
2440 		/* so just reverse direction and then pop */
2441 		currinf.dir = -currinf.dir;
2442 		currinf.data = current_frame->data;
2443 		current_frame = current_frame->prev;
2444 		break;
2445 #endif /* TEXXET */
2446 
2447 	    case RIGHT1:
2448 	    case RIGHT2:
2449 	    case RIGHT3:
2450 	    case RIGHT4:
2451 		moveH(DIR, xspell_conv(xsnum(fp, ch - RIGHT1 + 1)));
2452 		break;
2453 
2454 	    case W1:
2455 	    case W2:
2456 	    case W3:
2457 	    case W4:
2458 		WW = xspell_conv(xsnum(fp, ch - W0));
2459 	    case W0:
2460 		moveH(DIR, WW);
2461 		break;
2462 
2463 	    case X1:
2464 	    case X2:
2465 	    case X3:
2466 	    case X4:
2467 		XX = xspell_conv(xsnum(fp, ch - X0));
2468 	    case X0:
2469 		moveH(DIR, XX);
2470 		break;
2471 
2472 	    case DOWN1:
2473 	    case DOWN2:
2474 	    case DOWN3:
2475 	    case DOWN4:
2476 		moveV(1, xspell_conv(xsnum(fp, ch - DOWN1 + 1)));
2477 		break;
2478 
2479 	    case Y1:
2480 	    case Y2:
2481 	    case Y3:
2482 	    case Y4:
2483 		YY = xspell_conv(xsnum(fp, ch - Y0));
2484 	    case Y0:
2485 		moveV(1, YY);
2486 		break;
2487 
2488 	    case Z1:
2489 	    case Z2:
2490 	    case Z3:
2491 	    case Z4:
2492 		ZZ = xspell_conv(xsnum(fp, ch - Z0));
2493 	    case Z0:
2494 		moveV(1, ZZ);
2495 		break;
2496 
2497 	    case FNT1:
2498 	    case FNT2:
2499 	    case FNT3:
2500 	    case FNT4:
2501 		change_font(xnum(fp, ch - FNT1 + 1));
2502 		break;
2503 
2504 	    case XXX1:
2505 	    case XXX2:
2506 	    case XXX3:
2507 	    case XXX4:
2508 		a = xnum(fp, ch - XXX1 + 1);
2509 		if (a > 0) {
2510 		    char *p = read_special(fp, a);
2511 		    if (resource.pause && strcmp(p, resource.pause_special) == 0) {
2512 			if (++pause_cnt > globals.pausing.num) {
2513 			    globals.pausing.flag = True;
2514 			    /* can't use longjmp(globals.ev.canit, 1); */
2515 			    return;
2516 			}
2517 		    }
2518 		    applicationDoSpecial(p, a);
2519 		}
2520 		break;
2521 
2522 	    case FNTDEF1:
2523 	    case FNTDEF2:
2524 	    case FNTDEF3:
2525 	    case FNTDEF4:
2526 		xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
2527 		a = (long)xone(fp);
2528 		xskip(fp, a + (long)xone(fp));
2529 		break;
2530 
2531 #ifndef TEXXET
2532 	    case SREFL:
2533 	    case EREFL:
2534 #endif
2535 	    case PRE:
2536 	    case POST:
2537 	    case POSTPOST:
2538 		dvi_fmt_error("%s:%d: draw_part: shouldn't happen: %s encountered",
2539 			      __FILE__, __LINE__, dvi_table2[ch - (FNTNUM0 + 64)]);
2540 		break;
2541 #ifdef PTEX
2542 	    case TDIR:
2543 		TATE = xone(fp);
2544 		break;
2545 #endif /* PTEX */
2546 
2547 	    default:
2548 		dvi_fmt_error("%s:%d: draw_part: unknown op-code %d", __FILE__, __LINE__, ch);
2549 	    }	/* end switch */
2550 	}	/* end else (ch not a SETCHAR or FNTNUM) */
2551     }	/* end for */
2552 }
2553 
2554 extern int waiting_for_anchor;
2555 
2556 static void
warn_raw_postscript(void)2557 warn_raw_postscript(void)
2558 {
2559     static int *pagelist = NULL;
2560     static int pagelist_size = 0;
2561 #ifdef PS
2562     if (!resource.hush_stdout) {
2563 	if (total_pages >= pagelist_size) {
2564 	    pagelist_size = total_pages + 1;
2565 	    pagelist = xrealloc(pagelist, pagelist_size * sizeof *pagelist);
2566 	    memset(pagelist, 0, pagelist_size * sizeof *pagelist);
2567 	}
2568 
2569 	ASSERT(pagelist_size > current_page, "pagelist_size too small");
2570 	if (pagelist[current_page] == 0) {
2571 	    XDVI_WARNING((stderr, "Raw Postscript commands on page %d may be rendered incorrectly.",
2572 			  current_page + 1));
2573 	    pagelist[current_page] = 1;
2574 	}
2575 
2576 	/* too likely to overdraw important information */
2577 	/* 	statusline_info(STATUS_MEDIUM, */
2578 	/* 			 "Warning: Postscript commands on this page may not display correctly."); */
2579     }
2580 #endif /* PS */
2581 }
2582 
2583 void
draw_page(void)2584 draw_page(void)
2585 {
2586 #if 0
2587     volatile double save_gamma = 0.0;
2588 #endif /* 0 */
2589     /* Check for changes in dvi file. */
2590     if (dvi_file_changed()) {
2591 	return;
2592     }
2593 
2594     if (globals.dvi_file.bak_fp == NULL) {
2595 	return;
2596     }
2597 
2598 #ifdef PS
2599     have_raw_postscript = False;
2600 #endif
2601 
2602 #if COLOR
2603     color_bottom = &fg_initial;
2604     color_bot_size = 1;
2605 
2606     if (page_colors.stack != NULL && current_page > 0) {
2607 	color_bottom = page_colors.stack[current_page - 1].colorstack;
2608 	color_bot_size = page_colors.stack[current_page - 1].stacksize;
2609     }
2610     rcs_top = NULL;
2611     ASSERT(color_bot_size > 0, "color_bot_size mustn't become negative!");
2612     ASSERT(color_bottom != NULL, "color_bottom mustn't become negative!");
2613     set_fg_color(&color_bottom[color_bot_size - 1]);
2614 #endif /* COLOR */
2615 
2616 #if !FIXED_FLUSHING_PAGING
2617     draw_border(-currwin.base_x, -currwin.base_y,
2618 		ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2,
2619 		ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2, globals.gc.high);
2620 #endif /* MOTIF */
2621 
2622     if (resource.grid_mode > 0)	{ /* grid is wanted */
2623 	put_grid(-currwin.base_x, -currwin.base_y,
2624 		 /* 		 ROUNDUP(globals.page.unshrunk_w, currwin.shrinkfactor) + 2, */
2625 		 /* 		 ROUNDUP(globals.page.unshrunk_h, currwin.shrinkfactor) + 2, */
2626 		 ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2,
2627 		 ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2,
2628 		 ROUNDUP(globals.grid_paper_unit, currwin.shrinkfactor),
2629 		 globals.gc.high);
2630     }
2631 
2632     (void) lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(current_page), SEEK_SET);
2633 
2634     memset((char *)&currinf.data, '\0', sizeof currinf.data);
2635     currinf.tn_table_len = TNTABLELEN;
2636     currinf.tn_table = tn_table;
2637     currinf.tn_head = tn_head;
2638     currinf.pos = currinf.end = dvi_buffer;
2639     currinf.virtual = NULL;
2640     dvi_pointer_frame = &currinf;
2641     drawing_mag = (currwin.win == magnifier.win);
2642     psfig_begun = False;
2643 
2644     htex_initpage(False, False, current_page);
2645 
2646     if (currwin.win == mane.win) {
2647 	XRectangle rect;
2648 	rect.x = globals.win_expose.min_x;
2649 	rect.y = globals.win_expose.min_y;
2650 	rect.width = globals.win_expose.max_x - globals.win_expose.min_x;
2651 	rect.height = globals.win_expose.max_y - globals.win_expose.min_y;
2652 	/*  	fprintf(stderr, "clip: %d, %d, %d, %d\n", */
2653 	/* 		globals.win_expose.min_x, */
2654 	/* 		globals.win_expose.min_y, */
2655 	/* 		globals.win_expose.max_x - globals.win_expose.min_x, */
2656 	/* 		globals.win_expose.max_y - globals.win_expose.min_y); */
2657 #define SET_CLIP(gc)	if (gc != NULL) XSetClipRectangles(DISP, gc, 0, 0, &rect, 1, Unsorted)
2658 #define CLEAR_CLIP(gc)  if (gc != NULL) XSetClipMask(DISP, gc, None)
2659 	/* Set clip masks for all GC's */
2660 	SET_CLIP(globals.gc.fore);
2661 	SET_CLIP(globals.gc.fore2);
2662 	SET_CLIP(globals.gc.fore2_bak);
2663 	SET_CLIP(globals.gc.fore2_bak1);
2664 	SET_CLIP(globals.gc.rule);
2665 	SET_CLIP(globals.gc.high);
2666 	SET_CLIP(globals.gc.linkcolor);
2667 	SET_CLIP(globals.gc.copy);
2668     }
2669 
2670     if (!setjmp(globals.ev.canit)) {
2671 	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2672 
2673 	ALL GLYPH DRAWING/RULE SETTING COMMANDS THAT MIGHT INVOKE
2674 	longjmp(globals.ev.canit)
2675 	MUST GO INSIDE THIS IF CASE, AND MUST NOT BE INVOKED FROM
2676 	SOMEWHERE ELSE!
2677 
2678 	Failure to check whether a command could (indirectly) invoke
2679 	such a drawing routine (like e.g. put_rule()) will result
2680 	in *really* strange bugs (see e.g. #616920, and probably also #471021).
2681 
2682 	!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2683 	*/
2684 	/* generate an expose event */
2685 	if (search_have_match(current_page)) {
2686 	    search_erase_highlighting(False);
2687 	}
2688 	if (globals.curr_mode == TEXT_MODE_ACTIVE) {
2689 	    text_change_region(TEXT_SEL_ERASE, NULL);
2690 	}
2691 	draw_part(globals.dvi_file.bak_fp, current_frame = &frame0, dimconv);
2692 
2693 	if (have_raw_postscript) {
2694 	    warn_raw_postscript();
2695 	}
2696     }
2697     else {
2698 	/* If we were interrupted, put the expose event back, so that the
2699 	 * region gets redrawn.  The if statement is necessary because the
2700 	 * magnifier may have been destroyed as part of the interrupt.  */
2701 	if (currwin.win == mane.win || currwin.win == magnifier.win) {
2702 	    expose(currwin.win == mane.win ? &mane : &magnifier,
2703 		   globals.win_expose.min_x - currwin.base_x, globals.win_expose.min_y - currwin.base_y,
2704 		   globals.win_expose.max_x - globals.win_expose.min_x, globals.win_expose.max_y - globals.win_expose.min_y);
2705 	}
2706 
2707 #ifdef PS
2708 	psp.interrupt();
2709 	/* reset this flag too, just to make sure ... */
2710 # if defined(PS_GS) && GS_PIXMAP_CLEARING_HACK
2711 	had_ps_specials = False;
2712 # endif
2713 #endif
2714 	globals.ev.flags &= ~EV_MAG_GONE;
2715 #if 0
2716 	if (search_have_match() && save_gamma != 0.0) {
2717 	    resource.gamma = save_gamma;
2718 	    do_color_change();
2719 	    reset_fonts();
2720 	}
2721 #endif /* 0 */
2722     }
2723 
2724     drawing_mag = False;
2725     dvi_pointer_frame = NULL;
2726     if (currwin.win == mane.win) {
2727 	if (globals.src.fwd_box_page >= 0) {
2728 	    source_fwd_draw_box(); /* draw box showing found source line */
2729 	}
2730 	htex_draw_anchormarkers();
2731     }
2732 #ifdef PS
2733     psp.endpage();
2734 #endif
2735     if (currwin.win == mane.win && resource.postscript != 1) {
2736        display_bboxes();
2737     }
2738     if (search_have_match(current_page)) {
2739 	/* highlight search match */
2740 	search_draw_inverted_regions();
2741     }
2742     if (currwin.win == mane.win && (globals.curr_mode == TEXT_MODE_ACTIVE)) {
2743 	/* highlight selection */
2744 	text_change_region(TEXT_SEL_REDRAW, NULL);
2745     }
2746     if (globals.curr_mode == RULER_MODE_ACTIVE) {
2747 	redraw_ruler();
2748     }
2749 
2750     clear_bboxes();
2751 
2752     if (currwin.win == mane.win) {
2753 	CLEAR_CLIP(globals.gc.fore);
2754 	CLEAR_CLIP(globals.gc.fore2);
2755 	CLEAR_CLIP(globals.gc.fore2_bak);
2756 	CLEAR_CLIP(globals.gc.fore2_bak1);
2757 	CLEAR_CLIP(globals.gc.rule);
2758 	CLEAR_CLIP(globals.gc.high);
2759 	CLEAR_CLIP(globals.gc.linkcolor);
2760 	CLEAR_CLIP(globals.gc.copy);
2761     }
2762 #undef SET_CLIP
2763 #undef CLEAR_CLIP
2764 
2765     currwin.win = (Window) 0;
2766 }
2767 
2768 /* this sets the file-scope htex_anchor_type to the type of the anchor just scanned,
2769    which is used by the drawing routines to determine whether current position is inside
2770    an anchor. Called from special.c.
2771 */
2772 void
htex_do_special(const char * str,size_t len)2773 htex_do_special(const char *str, size_t len)
2774 {
2775     if (INSIDE_MANE_WIN) {
2776 	htex_inside_href = htex_scan_anchor(str, len);
2777     }
2778 }
2779 
2780 /*
2781  *	General dvi scanning routines.  These are used for:
2782  *	    o	source special lookups and
2783  *	    o	finding the dimensions of links (if compiling with support for
2784  *		hypertext specials).
2785  *	This routine can be a bit slower than draw_page()/draw_part(), since
2786  *	it is not run that often; that is why it is a separate routine in
2787  *	spite of much duplication.
2788  *
2789  *	Note that it does not use a separate copy of define_font().
2790  */
2791 
2792 /*
2793  *	This set of routines can be called while draw_part() is active,
2794  *	so the global variables must be separate.
2795  */
2796 
2797 static struct frame geom_frame0;	/* dummy head of list */
2798 
2799 #ifdef TEXXET
2800 static struct frame *geom_scan_frame;	/* head frame for scanning */
2801 #endif
2802 
2803 static struct frame *geom_current_frame;
2804 
2805 static uint32_t
get_unicode_char(wide_ubyte ch,struct drawinf currinf,char * retbuf)2806 get_unicode_char(wide_ubyte ch, struct drawinf currinf, char *retbuf)
2807 {
2808 #if FREETYPE
2809     /* attempt 1: if it's a Type1 font, get the Adobe character name
2810        from FreeType's FT_Get_Glyph_Name */
2811     if (currinf.fontp->ft != NULL) {
2812 	FT_Face face = currinf.fontp->ft->face;
2813 
2814 	ASSERT(face != NULL, "Font must have been loaded at this point!");
2815 	if (FT_Has_PS_Glyph_Names(face)) {
2816 	    char buffer[32];	/* holds longest name in adobe2unicode_table */
2817 	    int index = currinf.fontp->glyph[ch].addr;
2818 
2819 	    if (index == 0
2820 	      || FT_Get_Glyph_Name(face, index, buffer, sizeof buffer) != 0)
2821 		TRACE_FIND_VERBOSE((stderr, "T1 char: %d has no name", ch));
2822 	    else {
2823 		TRACE_FIND_VERBOSE((stderr,
2824 			    "T1 char: %d = `%s' (font: %s; enc: %s)",
2825 			    ch, char_name,
2826 			    currinf.fontp->fontname,
2827 			    currinf.fontp->ft->t1->encname));
2828 		return adobe2unicode_name(buffer);
2829 	    }
2830 	}
2831     }
2832 #endif /* FREETYPE */
2833     /* attempt 2: try to derive the encoding from the font name,
2834        by looking it up in a list of known font names.
2835     */
2836     return guess_encoding(ch, currinf.fontp->fontname, retbuf);
2837 }
2838 
2839 #define MAX_CHARS 16 /* maximum number of unicode characters that one do_char can produce (rounded up ...) */
2840 static const size_t ALLOC_STEP = 1024;
2841 
2842 /* create a page break at BOP, unless we're at the start of the file */
2843 static void
do_newpage(struct scan_info * info)2844 do_newpage(struct scan_info *info)
2845 {
2846     struct word_info *w_info = (struct word_info *)info->data;
2847     if (w_info->curr_buf_idx > 0) { /* not at start of file */
2848 	/* resize buffer if needed */
2849 	while (w_info->curr_buf_idx + MAX_CHARS >= w_info->txt_buf_size) {
2850 	    w_info->txt_buf_size += ALLOC_STEP;
2851 	    w_info->txt_buf = xrealloc(w_info->txt_buf, w_info->txt_buf_size);
2852 	}
2853 	w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
2854     }
2855 }
2856 
2857 static void
reset_bboxes(struct word_info * info)2858 reset_bboxes(struct word_info *info)
2859 {
2860     size_t i;
2861     for (i = 0; i < info->bboxes_size; i++) {
2862 	info->bboxes[i].ulx = INT_MAX;
2863 	info->bboxes[i].uly = INT_MAX;
2864 	info->bboxes[i].lrx = 0;
2865 	info->bboxes[i].lry = 0;
2866     }
2867 }
2868 
2869 static void
delete_last_bbox(struct word_info * info)2870 delete_last_bbox(struct word_info *info)
2871 {
2872     info->bboxes[info->bboxes_idx].ulx = INT_MAX;
2873     info->bboxes[info->bboxes_idx].uly = INT_MAX;
2874     info->bboxes[info->bboxes_idx].lrx = 0;
2875     info->bboxes[info->bboxes_idx].lry = 0;
2876 }
2877 
2878 static void
finish_bbox(struct word_info * info)2879 finish_bbox(struct word_info *info)
2880 {
2881     /*     if (info->bboxes_idx == 0) /\* nothing to do *\/ */
2882     /* 	return; */
2883 
2884     info->bboxes_idx++;
2885     while (info->bboxes_idx + 1 > info->bboxes_size) {
2886 	/* re-allocate info */
2887 	info->bboxes_size += 32;
2888 	info->bboxes = xrealloc(info->bboxes, info->bboxes_size * sizeof *(info->bboxes));
2889     }
2890     info->bboxes[info->bboxes_idx].ulx = INT_MAX;
2891     info->bboxes[info->bboxes_idx].uly = INT_MAX;
2892     info->bboxes[info->bboxes_idx].lrx = 0;
2893     info->bboxes[info->bboxes_idx].lry = 0;
2894 
2895 #if 0
2896     fprintf(stderr, "========= finish_bbox: index=%d, boxes:\n", info->bboxes_idx);
2897     {
2898 	int i;
2899 	for (i = 0; i < info->bboxes_idx; i++) {
2900 	    fprintf(stderr, "%d: x %d, y %d, w %d, h %d\n",
2901 		    i, info->bboxes[i].ulx, info->bboxes[i].uly, info->bboxes[i].lrx, info->bboxes[i].lry);
2902 	}
2903     }
2904 #endif /* 0 */
2905 }
2906 
2907 static void
create_bbox(struct word_info * info,int x,int y,int w,int h)2908 create_bbox(struct word_info *info, int x, int y, int w, int h)
2909 {
2910 #if 0
2911     fprintf(stderr, "++++++++++++++ inside match: %d,%d,%d,%d!\n", x,y,w,h);
2912     XDrawRectangle(DISP, mane.win, globals.gc.high,
2913 		   x / (double)currwin.shrinkfactor + 0.5,
2914 		   y / (double)currwin.shrinkfactor + 0.5,
2915 		   w / (double)currwin.shrinkfactor + 0.5,
2916 		   h / (double)currwin.shrinkfactor + 0.5);
2917 #endif
2918     while (info->bboxes_idx + 1 > info->bboxes_size) {
2919 	/* re-allocate info */
2920 	size_t old_size = info->bboxes_size;
2921 	size_t i;
2922 	info->bboxes_size += 32;
2923 	info->bboxes = xrealloc(info->bboxes, info->bboxes_size * sizeof *(info->bboxes));
2924 	for (i = old_size; i < info->bboxes_size; i++) {
2925 	    info->bboxes[i].ulx = INT_MAX;
2926 	    info->bboxes[i].uly = INT_MAX;
2927 	    info->bboxes[i].lrx = 0;
2928 	    info->bboxes[i].lry = 0;
2929 	}
2930 
2931     }
2932     /* adjust size of box */
2933     if (x < info->bboxes[info->bboxes_idx].ulx)
2934 	info->bboxes[info->bboxes_idx].ulx = x;
2935     if (y < info->bboxes[info->bboxes_idx].uly)
2936 	info->bboxes[info->bboxes_idx].uly = y;
2937     if (x + w > info->bboxes[info->bboxes_idx].lrx)
2938 	info->bboxes[info->bboxes_idx].lrx = x + w;
2939     if (y + h > info->bboxes[info->bboxes_idx].lry)
2940 	info->bboxes[info->bboxes_idx].lry = y + h;
2941 #if 0
2942     fprintf(stderr, "dimens: %d, %d, %d, %d\n",
2943 	    info->bboxes[info->bboxes_idx].ulx,
2944 	    info->bboxes[info->bboxes_idx].uly,
2945 	    info->bboxes[info->bboxes_idx].lrx,
2946 	    info->bboxes[info->bboxes_idx].lry);
2947     fprintf(stderr, "============ create_bbox: index=%d, boxes:\n", info->bboxes_idx);
2948     {
2949 	int i;
2950 	for (i = 0; i <= info->bboxes_idx; i++) {
2951 	    fprintf(stderr, "%d: x %d, y %d, w %d, h %d\n",
2952 		    i, info->bboxes[i].ulx, info->bboxes[i].uly, info->bboxes[i].lrx, info->bboxes[i].lry);
2953 	}
2954     }
2955 #endif /* 0 */
2956 }
2957 
2958 static void
map_index_positions(const struct search_info * searchinfo,const struct page_mapping * page_mapping,int * from,int * to)2959 map_index_positions(const struct search_info *searchinfo,
2960 		    const struct page_mapping *page_mapping,
2961 		    int *from, int *to)
2962 {
2963     *from = searchinfo->from_pos;
2964     *to = searchinfo->to_pos;
2965 
2966     if (*from >= page_mapping[0].offset) { /* on second page of scan */
2967 #if 0
2968 	fprintf(stderr, "current_page: %d, from: %d, to: %d; subtracting %d for pageinfo at index 0\n",
2969 		current_page, *from, *to, page_mapping[0].offset);
2970 #endif /* 0 */
2971 	if (page_mapping[0].offset != -1) {
2972 	    ASSERT(page_mapping[0].offset != -1, "page_mapping not properly initialized?");
2973 	    (*from) -= page_mapping[0].offset;
2974 	    (*to) -= page_mapping[0].offset;
2975 	}
2976 	ASSERT(*from >= 0, "index must be > 0");
2977 	ASSERT(*to >= 0, "index must be > 0");
2978 
2979     }
2980 }
2981 
2982 /* decrement curr_buf_idx so that the previous character in info
2983  * (which might be a multi-byte character) is erased.
2984  */
2985 static void
erase_prev_char(struct word_info * info)2986 erase_prev_char(struct word_info *info)
2987 {
2988     /* erase the hyphen, which might be a multibyte character */
2989     if ((unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) < 0x80) { /* single-byte */
2990 	TRACE_FIND_VERBOSE((stderr, "1 XXX: %d",
2991 			    (unsigned char)(info->txt_buf[info->curr_buf_idx - 1])));
2992 	info->txt_buf[--(info->curr_buf_idx)] = '\0';
2993     }
2994     else { /* skip back over multi-byte sequence */
2995 	while ((unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) >= 0x80
2996 	       && (unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) < 0xC0) { /* 10xxxxxx bytes */
2997 	    TRACE_FIND_VERBOSE((stderr, "2 XXX: %d",
2998 				(unsigned char)(info->txt_buf[info->curr_buf_idx - 1])));
2999 	    info->txt_buf[--(info->curr_buf_idx)] = '\0';
3000 	}
3001 	/* first byte (TODO: sanity check?) */
3002 	info->txt_buf[--(info->curr_buf_idx)] = '\0';
3003     }
3004 }
3005 
3006 
3007 static Boolean
inside_text_match(int curr_pos,int from,int to)3008 inside_text_match(int curr_pos, int from, int to)
3009 {
3010     return from < curr_pos && curr_pos <= to;
3011 }
3012 
3013 static Boolean reinit_scan = False;
3014 
3015 void
reinit_text_scan(void)3016 reinit_text_scan(void) {
3017     reinit_scan = True;
3018 }
3019 
3020 static Boolean
inside_bbox(int x,int y,int w,int h,struct bbox * bboxes)3021 inside_bbox(int x, int y, int w, int h,
3022 	    struct bbox *bboxes)
3023 {
3024     int mid_x, mid_y;
3025 #if 0
3026     XDrawRectangle(DISP, mane.win, globals.gc.high,
3027 		   x / (double)currwin.shrinkfactor + 0.5,
3028 		   y / (double)currwin.shrinkfactor + 0.5,
3029 		   w / (double)currwin.shrinkfactor + 0.5,
3030 		   h / (double)currwin.shrinkfactor + 0.5);
3031 #endif
3032     /* already treat it as inside if there's an overlap of more than 50% */
3033     mid_x = x + w / 2.0;
3034     mid_y = y + h / 2.0;
3035 #if 0
3036     fprintf(stderr, "------- check:\n%d, %d\n%d, %d, %d, %d\n",
3037 	    mid_x, mid_y, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
3038 #endif
3039     if (bboxes->ulx <= mid_x &&
3040 	bboxes->uly <= mid_y &&
3041 	bboxes->lrx >= mid_x &&
3042 	bboxes->lry >= mid_y) {
3043 #if 0
3044 	fprintf(stderr, "====== MATCH:\n%d, %d\n%d, %d, %d, %d\n",
3045 		mid_x, mid_y, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
3046 #endif
3047 	return True;
3048     }
3049     return False;
3050 }
3051 
3052 static Boolean
inside_bbox_line(int y,int h,struct bbox * bboxes)3053 inside_bbox_line(int y, int h,
3054 		 struct bbox *bboxes)
3055 {
3056     int mid_y = y + h / 2.0;
3057     if (bboxes->uly <= mid_y &&
3058 	bboxes->lry >= mid_y) {
3059 #if 0
3060 	fprintf(stderr, "MATCH:\n%d, %d, %d, %d\n%d, %d, %d, %d\n",
3061 		x, y, w, h, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
3062 #endif
3063 	return True;
3064     }
3065     return False;
3066 }
3067 
3068 static void
do_char(wide_ubyte ch,struct drawinf currinf,struct scan_info * info,long pxl_v1,long pxl_v2,long x1,long x2,struct glyph * g)3069 do_char(wide_ubyte ch,
3070 	struct drawinf currinf,
3071 	struct scan_info *info,
3072 	long pxl_v1, long pxl_v2,
3073 	long x1, long x2,
3074 	struct glyph *g)
3075 {
3076     struct word_info *w_info = (struct word_info *)info->data;
3077     struct search_settings *settings = NULL;
3078     const struct page_mapping *page_mapping = NULL;
3079     uint32_t u_glyph = 0, new_glyph = 0;
3080     Boolean convert_to_lowercase = False;
3081     /* if set to true, ignore whitespace before/after character (for CJK characters) */
3082     Boolean ignore_whitespace = False;
3083 
3084     /* default min space between words, in DVI units */
3085     /* TODO: for T1 fonts, should we look at fontdimen2 / fontdimen4?
3086        (e.g. tfminfo[fontmaps[currinf.fontp->t1id].tfmidx].fontdimen2)
3087     */
3088     long min_delta = (int)(1.5 * currinf.fontp->pixsize + 0.5) << 16;
3089 
3090     size_t buf_offset = w_info->buffer_offset;
3091 
3092     size_t i;
3093     /* for delayed insertion of newlines in text selection mode */
3094     static Boolean had_newline = False;
3095     /* for whitespace insertion in text selection mode */
3096     static Boolean had_chars_in_line = False;
3097     static long last_dvi_h1 = 0, last_pxl_v = 0;
3098     static long last_dvi_h2 = 0;
3099     static long last_x = 0;
3100     static uint32_t last_u_glyph = 0;
3101     static int last_page = -1;
3102     static int page_bak = -1;
3103     const char *expanded_lig = NULL;
3104     const uint32_t UNKNOWN_GLYPH_CODE = 0x003F; /* question mark */
3105     char retbuf[MAX_CHARS];
3106     retbuf[0] = '\0';
3107 
3108     if (w_info != NULL && w_info->settings != NULL) {
3109 	settings = w_info->settings;
3110 	if (!settings->case_sensitive)
3111 	    convert_to_lowercase = True;
3112     }
3113 
3114     if (w_info->bbox_pass) {
3115 	ASSERT(w_info != NULL, "");
3116 	ASSERT(w_info->page_mapping != NULL, "");
3117 	page_mapping = w_info->page_mapping;
3118     }
3119 
3120     if (reinit_scan || last_page != current_page) { /* reinit */
3121 	last_dvi_h1 = last_pxl_v = last_dvi_h2 = last_x = 0;
3122 	last_page = current_page;
3123 	last_u_glyph = 0;
3124 	w_info->bboxes_idx = 0;
3125 	reset_bboxes(w_info);
3126 	/* 	w_info->curr_buf_idx  = 0; */
3127 	reinit_scan = False;
3128 	had_newline = False;
3129 	had_chars_in_line = False;
3130     }
3131 
3132     /*      TRACE_FIND((stderr, "\n--------- POSITIONS: %ld, %ld, %ld, %ld", x1, pxl_v2, x2, y2)); */
3133 
3134     if ((u_glyph = get_unicode_char(ch, currinf, retbuf)) == 0) {
3135 	if (retbuf[0] == '\0') {
3136 	    TRACE_FIND((stderr, "unknown glyph `%lu'\n", (unsigned long)ch));
3137 	    u_glyph = UNKNOWN_GLYPH_CODE;
3138 	}
3139 	else /* several characters in retbuf, will be evaluated later */
3140 	    u_glyph = 0;
3141     }
3142 
3143     TRACE_FIND_VERBOSE((stderr, "UNICODE: 0x%.4X; idx: %ld",
3144 			(unsigned int)u_glyph,
3145 			(unsigned long)w_info->curr_buf_idx));
3146 
3147     /* resize buffer if needed */
3148     while (w_info->curr_buf_idx + MAX_CHARS >= w_info->txt_buf_size) {
3149 	w_info->txt_buf_size += ALLOC_STEP;
3150 	w_info->txt_buf = xrealloc(w_info->txt_buf, w_info->txt_buf_size);
3151     }
3152 
3153     /* Copy text into buffer, applying heuristics for special glyphs.
3154        A `\0' is always appended, so that we have a valid C string;
3155        if we have more text, this '\0' will be overwritten in the next call. */
3156 
3157     /* apply accent/linebreak heuristics */
3158     /*     fprintf(stderr, "Checking: %ld > 0, %ld > 0\n", last_dvi_h1, last_pxl_v); */
3159     if (last_dvi_h1 > 0 && last_pxl_v > 0) { /* had at least 1 character */
3160 	TRACE_FIND_VERBOSE((stderr, "++++ dvi_h: %ld, last_dvi_h1: %ld, w_info->curr_buf_idx: %ld",
3161 			    DVI_H, last_dvi_h1, (unsigned long)w_info->curr_buf_idx));
3162 
3163 	/* spaces after/before ideographic characters are ignored */
3164 	if (is_ideograph(last_u_glyph) || is_ideograph(u_glyph))
3165 	    ignore_whitespace = true;
3166 
3167 	/* first, check for linebreaks since accents are also triggered by negative hspace.
3168 	 * Usually, a linebreak is signalled by vertical movement down. However, in multicolumn
3169 	 * mode, it can also be a movement up, which we try to catch with the second condition. */
3170 	if (pxl_v2 > last_pxl_v + (int)(1.2 * currinf.fontp->pixsize + 0.5)
3171 	    || (page_bak == current_page && pxl_v2 + (int)(6 * currinf.fontp->pixsize + 0.5) < last_pxl_v)) {
3172 	    TRACE_FIND_VERBOSE((stderr, "linebreak (%ld > %ld + %d || %ld < %ld)!\n",
3173 				pxl_v2, last_pxl_v, (int)(1.2 * currinf.fontp->pixsize + 0.5),
3174 				pxl_v2 + (int)(6 * currinf.fontp->pixsize + 0.5), last_pxl_v));
3175 
3176 	    /* remove hyphen followed by newline if ignore_hyphens option is set,
3177 	       and we're scanning for string search: */
3178 	    if ((w_info->search_scan_pass || w_info->bbox_pass)
3179 		&& settings->ignore_hyphens && w_info->curr_buf_idx > 0
3180 		&& is_hyphenchar(last_u_glyph)) {
3181 
3182 		erase_prev_char(w_info);
3183 		TRACE_FIND_VERBOSE((stderr, "%d > %d + %d? offset: %lu",
3184 				    settings->searchinfo->from_pos,
3185 				    (int)w_info->curr_buf_idx,
3186 				    settings->hyphen_delta, (unsigned long)buf_offset));
3187 		if (!w_info->bbox_pass
3188 		    && settings->searchinfo->from_pos
3189 		    > (int)(w_info->curr_buf_idx + buf_offset + settings->hyphen_delta)) {
3190 		    settings->hyphen_delta += 2;
3191 		}
3192 		TRACE_FIND((stderr, "erasing hyphen %lu at pos %lu with char %c; hyphen_delta is: %d",
3193 			    (unsigned long)last_u_glyph, (unsigned long)w_info->curr_buf_idx, ch, settings->hyphen_delta));
3194 		/* If the position of this hyphen had been at the start of the bounding
3195 		   box, this bounding box info is now invalid - delete it */
3196 		if (w_info->bbox_pass) {
3197 		    int from, to;
3198 		    map_index_positions(settings->searchinfo, page_mapping, &from, &to);
3199 		    if ((int)w_info->curr_buf_idx == from) {
3200 			delete_last_bbox(w_info);
3201 		    }
3202 		}
3203 	    }
3204 	    else { /* ignore_hyphens not set, insert newline */
3205 		/* Also save hyphen_delta, in case we need to update from_pos and to_pos
3206 		   if user switched from ignore hyphens to don't ignore hyphens */
3207 		if (w_info->search_scan_pass && !w_info->bbox_pass
3208 		    && is_hyphenchar(last_u_glyph)
3209 		    && settings->searchinfo->from_pos + settings->hyphen_delta
3210 		    >= (int)(w_info->curr_buf_idx + buf_offset)) {
3211 		    settings->hyphen_delta += 2;
3212 		    TRACE_FIND((stderr, "updating delta: %d at pos %d, curr_idx %d, offset: %lu",
3213 				settings->hyphen_delta, settings->searchinfo->from_pos,
3214 				(int)w_info->curr_buf_idx, (unsigned long)buf_offset));
3215 		}
3216 		if (w_info->text_selection_pass) {
3217 		    if (inside_bbox(last_x, last_pxl_v, 5, 5, w_info->bboxes)
3218 			|| (inside_bbox_line(last_pxl_v, 5, w_info->bboxes))) {
3219 			had_newline = True;
3220 			had_chars_in_line = False;
3221 		    }
3222 		}
3223 		else if (w_info->search_scan_pass && settings->ignore_linebreaks && !ignore_whitespace)
3224 		    w_info->txt_buf[w_info->curr_buf_idx++] = ' ';
3225 		else if (!ignore_whitespace)
3226 		    w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
3227 	    }
3228 	    if (w_info->bbox_pass) {
3229 		int from, to;
3230 		map_index_positions(settings->searchinfo, page_mapping, &from, &to);
3231 		if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
3232 		    finish_bbox(w_info);
3233 		}
3234 	    }
3235 	}
3236 	else if (w_info->curr_buf_idx > 0 && last_u_glyph != 0 && last_x > 0
3237 		 && (!w_info->text_selection_pass
3238 		     || (w_info->text_selection_pass
3239 			 && inside_bbox(last_x, pxl_v2, x1 - last_x, pxl_v1 - pxl_v2, w_info->bboxes)))
3240 		 && x1 < last_x /* overlapping glyphs: check for diacritics */
3241 		 && ((new_glyph = get_accented_glyph(last_u_glyph, u_glyph)) != 0)) {
3242 	    erase_prev_char(w_info);
3243 	    /* use new glyph for next writing operation: */
3244 	    u_glyph = new_glyph;
3245 	}
3246 	else if (!ignore_whitespace && last_dvi_h2 > 0 && DVI_H > last_dvi_h2 + min_delta) {
3247 	    TRACE_FIND_VERBOSE((stderr, "space (%ld > %ld + %ld)!", DVI_H, last_dvi_h2, min_delta));
3248 	    if (!w_info->text_selection_pass
3249 		|| (w_info->text_selection_pass
3250 		    && had_chars_in_line
3251 		    && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h, w_info->bboxes))) {
3252 		w_info->txt_buf[w_info->curr_buf_idx++] = ' ';
3253 		w_info->txt_buf[w_info->curr_buf_idx] = '\0';
3254 		if (w_info->bbox_pass) {
3255 		    int from, to;
3256 		    map_index_positions(settings->searchinfo, page_mapping, &from, &to);
3257 		    if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
3258 			TRACE_FIND_VERBOSE((stderr, "bounding box for space: %ld, %ld, %ld, %ld",
3259 					    last_x, last_pxl_v, x1 - last_x, pxl_v1 - pxl_v2));
3260 			create_bbox(w_info, last_x, pxl_v2, x1 - last_x, pxl_v1 - pxl_v2);
3261 		    }
3262 		}
3263 	    }
3264 	}
3265     }
3266 
3267     last_page = current_page;
3268     if (retbuf[0] != '\0'
3269 	|| (expanded_lig = expand_ligature(u_glyph)) != NULL
3270 	/* when in search pass, normalize more characters */
3271 	|| ((w_info->bbox_pass || w_info->search_scan_pass)
3272 	    && (expanded_lig = search_normalize_chars(u_glyph)) != NULL)) {
3273 	/* expanded ligature, which is always in 7-bit ASCII -> copy into buffer */
3274 	size_t len;
3275 	if (retbuf[0] != '\0')
3276 	    expanded_lig = retbuf;
3277 	len = strlen(expanded_lig);
3278 	TRACE_FIND_VERBOSE((stderr, "I: %lu to %lu",
3279 			    (unsigned long)w_info->curr_buf_idx,
3280 			    (unsigned long)(w_info->curr_buf_idx + len)));
3281 
3282 	if (!w_info->text_selection_pass
3283 	    || (w_info->text_selection_pass && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h,
3284 							   w_info->bboxes))) {
3285 
3286 	    /* 	    fprintf(stderr, "inserting1 %s\n", expanded_lig); */
3287 	    if (had_newline) {
3288 		w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
3289 		had_newline = False;
3290 	    }
3291 	    memcpy(w_info->txt_buf + w_info->curr_buf_idx, expanded_lig, len);
3292 	    had_chars_in_line = True;
3293 	    for (i = 0; i < len; i++) {
3294 		w_info->curr_buf_idx++;
3295 		/* 		fprintf(stderr, "setting index to: %d\n", w_info->curr_buf_idx); */
3296 		if (w_info->bbox_pass) {
3297 		    int from, to;
3298 		    map_index_positions(settings->searchinfo, page_mapping, &from, &to);
3299 		    if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
3300 			create_bbox(w_info, x1, pxl_v2, x2 - x1, g->bitmap.h);
3301 		    }
3302 		}
3303 	    }
3304 	    w_info->txt_buf[w_info->curr_buf_idx] = '\0';
3305 	}
3306     }
3307     else if (!w_info->text_selection_pass
3308 	     || (w_info->text_selection_pass && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h, w_info->bboxes))) {
3309 	/* convert to utf8 */
3310 	char utf8_buf[MAX_CHARS]; /* ample ... */
3311 	size_t len;
3312 	/* convert to utf8, eventually lowercasing */
3313 	ucs4_to_utf8(u_glyph, utf8_buf, &len, convert_to_lowercase);
3314 	/* 	fprintf(stderr, "inserting2 %lu\n", u_glyph); */
3315 	if (had_newline) {
3316 	    w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
3317 	    had_newline = False;
3318 	}
3319 	memcpy(w_info->txt_buf + w_info->curr_buf_idx, utf8_buf, len);
3320 	had_chars_in_line = True;
3321 	for (i = 0; i < len; i++) {
3322 	    w_info->curr_buf_idx++;
3323 	    /* 	    fprintf(stderr, "setting index2 to: %d\n", w_info->curr_buf_idx); */
3324 	    if (w_info->bbox_pass) {
3325 		int from, to;
3326 #if 0
3327 		int j;
3328 		fprintf(stderr, "current page_mapping:\n");
3329 		for (j = 0; j <= total_pages; j++) {
3330 		    fprintf(stderr, "%d: %d\n", j, page_mapping[j]);
3331 		}
3332 #endif /* 0 */
3333 		/* 		fprintf(stderr, "mapping!\n"); */
3334 		map_index_positions(settings->searchinfo, page_mapping, &from, &to);
3335 		if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
3336 		    create_bbox(w_info, x1, pxl_v2, x2 - x1, g->bitmap.h);
3337 		}
3338 	    }
3339 	}
3340 	w_info->txt_buf[w_info->curr_buf_idx] = '\0'; /* ensure termination */
3341     }
3342 
3343     last_dvi_h1 = DVI_H;
3344     last_u_glyph = u_glyph;
3345     last_pxl_v = pxl_v1;
3346 #ifdef PTEX
3347     if (currinf.fontp->flags & FONT_KANJI) {
3348     last_dvi_h2 = DVI_H + currinf.fontp->kglyph[ch]->dvi_adv;
3349     } else {
3350 #endif /* PTEX */
3351     last_dvi_h2 = DVI_H + currinf.fontp->glyph[ch].dvi_adv;
3352 #ifdef PTEX
3353     }
3354 #endif /* PTEX */
3355     last_x = x2;
3356 }
3357 
3358 /* handle a character in the text scanning routine */
3359 long
text_do_char(FILE * fp,struct scan_info * info,wide_ubyte ch)3360 text_do_char(FILE *fp, struct scan_info *info, wide_ubyte ch)
3361 {
3362     if (currinf.set_char_p == set_no_char) {
3363 	if (currinf.virtual == NULL
3364 	    || (currinf.fontp = currinf.virtual->first_font) == NULL)
3365 	    return 0;	/* error; we'll catch it later */
3366 	maxchar = currinf.fontp->maxchar;
3367 	currinf.set_char_p = currinf.fontp->set_char_p;
3368 #if FREETYPE
3369         if (currinf.set_char_p == set_ft_char)
3370 	    do_load_freetype_font();
3371 #endif
3372     }
3373 
3374     if (currinf.set_char_p == set_empty_char)
3375 	return 0;	/* error; we'll catch it later */
3376 
3377 #if FREETYPE
3378     if (currinf.set_char_p == set_ft_char)
3379 	do_load_freetype_font();
3380 #endif
3381 
3382     if (currinf.set_char_p == load_n_set_char) {
3383 	if (globals.ev.flags & EV_GE_NEWDOC)	/* if abort */
3384 	    return 0;
3385 	if (!load_font(currinf.fontp
3386 #if DELAYED_MKTEXPK
3387 		       , True
3388 #endif
3389 		       )) {	/* if not found */
3390 	    if (globals.ev.flags & EV_GE_NEWDOC)	/* if abort */
3391 		return 0;
3392 
3393 	    currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
3394 	    warn_setting_empty_char();
3395 	    return 0;
3396 	}
3397 	maxchar = currinf.fontp->maxchar;
3398 	currinf.set_char_p = currinf.fontp->set_char_p;
3399     }
3400 
3401     if (currinf.set_char_p == set_char) {
3402 	struct glyph *g;
3403 	long x, y;
3404 
3405 	if (ch > maxchar)
3406 	    return 0;	/* catch the error later */
3407 	if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
3408 	    if (g->addr == 0)
3409 		return 0;	/* catch the error later */
3410 	    if (g->addr == -1)
3411 		return 0;	/* previously flagged missing char */
3412 #if FREETYPE
3413 	    if (currinf.fontp->ft == NULL)	/* if not freetype font */
3414 #endif
3415 	    {
3416 		open_font_file(currinf.fontp);
3417 		fseek(currinf.fontp->file, g->addr, SEEK_SET);
3418 	    }
3419 	    (*currinf.fontp->read_char) (currinf.fontp, ch);
3420 	    if (globals.debug & DBG_BITMAP)
3421 		print_char((ubyte) ch, g);
3422 	    currinf.fontp->timestamp = ++current_timestamp;
3423 	}
3424 #ifdef TEXXET
3425 	if (geom_scan_frame == NULL) {
3426 	    DEFINE_POSITION_VAL;
3427 	    PUSH_POSITION;
3428 	    if (! TATE && currinf.dir < 0)
3429 		moveH(1, -g->dvi_adv);
3430 #endif
3431 	    x = G_PXL_H - g->x;
3432 	    y = PXL_V - g->y;
3433 	    do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
3434 #ifdef TEXXET
3435 	    POP_POSITION;
3436 	}
3437 #endif
3438 	return DIR * g->dvi_adv;
3439     }
3440 #ifdef PTEX
3441     else if (currinf.set_char_p == set_char2) {
3442 	struct glyph *g;
3443 	long x, y;
3444 
3445 	g = currinf.fontp->kglyph[ch];
3446 	if (g == NULL || g->bitmap.bits == NULL) {
3447 	    (*currinf.fontp->read_char)(currinf.fontp, ch);
3448 	    g = currinf.fontp->kglyph[ch];
3449 	    free_bitmap2(g);
3450 	    g->tdir = currinf.fontp->dir;
3451 	}
3452 
3453 #ifdef TEXXET
3454 	if (geom_scan_frame == NULL) {
3455 	    DEFINE_POSITION_VAL;
3456 	    PUSH_POSITION;
3457 	    if (! TATE && currinf.dir < 0)
3458 		moveH(1, -g->dvi_adv);
3459 #endif
3460 	    x = G_PXL_H - g->x;
3461 	    y = PXL_V - g->y;
3462 	    do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
3463 #ifdef TEXXET
3464 	    POP_POSITION;
3465 	}
3466 #endif
3467 	return DIR * g->dvi_adv;
3468     }
3469 #endif /* PTEX */
3470     else if (currinf.set_char_p == set_vf_char) {
3471 	struct macro *m;
3472 	struct drawinf oldinfo;
3473 	wide_ubyte oldmaxchar;
3474 #ifdef TEXXET
3475 	DEFINE_POSITION_VAL;
3476 #endif
3477 
3478 	if (ch > maxchar)
3479 	    return 0;	/* catch the error later */
3480 	if ((m = &currinf.fontp->macro[ch])->pos == NULL)
3481 	    return 0;	/* catch the error later */
3482 #ifdef TEXXET
3483 	PUSH_POSITION;
3484 	if (! TATE && currinf.dir < 0)
3485 	    moveH(1, -m->dvi_adv);
3486 	if (geom_scan_frame == NULL) {
3487 #endif
3488 	    oldinfo = currinf;
3489 	    oldmaxchar = maxchar;
3490 	    WW = XX = YY = ZZ = 0;
3491 	    currinf.tn_table_len = VFTABLELEN;
3492 	    currinf.tn_table = currinf.fontp->vf_table;
3493 	    currinf.tn_head = currinf.fontp->vf_chain;
3494 	    currinf.pos = m->pos;
3495 	    currinf.end = m->end;
3496 	    currinf.virtual = currinf.fontp;
3497 	    geom_scan_part(text_do_char, fp, info, geom_current_frame, currinf.fontp->dimconv);
3498 	    currinf = oldinfo;
3499 	    maxchar = oldmaxchar;
3500 #ifdef TEXXET
3501 	    POP_POSITION;
3502 	}
3503 #endif
3504 	return DIR * m->dvi_adv;
3505     }
3506     else {
3507 	XDVI_FATAL((stderr, "currinf.set_char_p is not a registered routine!"));
3508     }
3509     /* NOTREACHED */
3510     return 0;
3511 }
3512 
3513 #define xmoveH(dir,dx)   \
3514 	do { moveH(dir,dx); PXL_V = xpixel_conv(DVI_V); } while(0)
3515 #define xmoveV(dir,dy)   \
3516 	do { moveV(dir,dy); PXL_V = xpixel_conv(DVI_V); } while(0)
3517 
3518 /*
3519  *	Handle a character in geometric scanning routine.
3520  */
3521 
3522 static long
geom_do_char(FILE * fp,struct scan_info * info,wide_ubyte ch)3523 geom_do_char(FILE *fp, struct scan_info *info, wide_ubyte ch)
3524 {
3525     struct geom_info *g_info = info->data;
3526 
3527     if (currinf.set_char_p == set_no_char) {
3528 	if (currinf.virtual == NULL
3529 	    || (currinf.fontp = currinf.virtual->first_font) == NULL)
3530 	    return 0;	/* error; we'll catch it later */
3531 	maxchar = currinf.fontp->maxchar;
3532 	currinf.set_char_p = currinf.fontp->set_char_p;
3533 #if FREETYPE
3534         if (currinf.set_char_p == set_ft_char)
3535 	    do_load_freetype_font();
3536 #endif
3537     }
3538 
3539     if (currinf.set_char_p == set_empty_char)
3540 	return 0;	/* error; we'll catch it later */
3541 
3542 #if FREETYPE
3543     if (currinf.set_char_p == set_ft_char)
3544 	do_load_freetype_font();
3545 #endif
3546 
3547     if (currinf.set_char_p == load_n_set_char) {
3548 	if (globals.ev.flags & EV_GE_NEWDOC)	/* if abort */
3549 	    return 0;
3550 	if (!load_font(currinf.fontp
3551 #if DELAYED_MKTEXPK
3552 		       , True
3553 #endif
3554 		       )) {	/* if not found */
3555 	    if (globals.ev.flags & EV_GE_NEWDOC)	/* if abort */
3556 		return 0;
3557 
3558 	    currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
3559 	    warn_setting_empty_char();
3560 	    return 0;
3561 	}
3562 	maxchar = currinf.fontp->maxchar;
3563 	currinf.set_char_p = currinf.fontp->set_char_p;
3564     }
3565 
3566     if (currinf.set_char_p == set_char) {
3567 	struct glyph *g;
3568 	long x, y;
3569 
3570 	if (ch > maxchar)
3571 	    return 0;	/* catch the error later */
3572 	if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
3573 	    if (g->addr == 0)
3574 		return 0;	/* catch the error later */
3575 	    if (g->addr == -1)
3576 		return 0;	/* previously flagged missing char */
3577 #if FREETYPE
3578 	    if (currinf.fontp->ft == NULL)	/* if not freetype font */
3579 #endif
3580 	    {
3581 		open_font_file(currinf.fontp);
3582 		fseek(currinf.fontp->file, g->addr, SEEK_SET);
3583 	    }
3584 	    (*currinf.fontp->read_char) (currinf.fontp, ch);
3585 	    if (globals.debug & DBG_BITMAP)
3586 		print_char((ubyte) ch, g);
3587 	    currinf.fontp->timestamp = ++current_timestamp;
3588 	}
3589 #ifdef TEXXET
3590 	if (geom_scan_frame == NULL) {
3591 	    DEFINE_POSITION_VAL;
3592 	    PUSH_POSITION;
3593 	    if (! TATE && currinf.dir < 0)
3594 		moveH(1, -g->dvi_adv);
3595 #endif
3596 	    x = G_PXL_H - g->x;
3597 	    y = PXL_V - g->y;
3598 	    g_info->geom_box(info, x, y,
3599 			     x + g->bitmap.w - 1, y + g->bitmap.h - 1);
3600 #ifdef TEXXET
3601 	    POP_POSITION;
3602 	}
3603 #endif
3604 	return DIR * g->dvi_adv;
3605     }
3606 #ifdef PTEX
3607     else if (currinf.set_char_p == set_char2) {
3608 	struct glyph *g;
3609 	long x, y;
3610 
3611 	g = currinf.fontp->kglyph[ch];
3612 	if (g == NULL || g->bitmap.bits == NULL) {
3613 	    (*currinf.fontp->read_char)(currinf.fontp, ch);
3614 	    g = currinf.fontp->kglyph[ch];
3615 	    free_bitmap2(g);
3616 	    g->tdir = currinf.fontp->dir;
3617 	}
3618 
3619 #ifdef TEXXET
3620 	if (geom_scan_frame == NULL) {
3621 	    DEFINE_POSITION_VAL;
3622 	    PUSH_POSITION;
3623 	    if (! TATE && currinf.dir < 0)
3624 		moveH(1, -g->dvi_adv);
3625 #endif
3626 	    x = G_PXL_H - g->x;
3627 	    y = PXL_V - g->y;
3628 	    g_info->geom_box(info, x, y,
3629 			     x + g->bitmap.w - 1, y + g->bitmap.h - 1);
3630 #ifdef TEXXET
3631 	    POP_POSITION;
3632 	}
3633 #endif
3634 	return DIR * g->dvi_adv;
3635     }
3636 #endif /* PTEX */
3637     else if (currinf.set_char_p == set_vf_char) {
3638 	struct macro *m;
3639 	struct drawinf oldinfo;
3640 	wide_ubyte oldmaxchar;
3641 #ifdef TEXXET
3642 	DEFINE_POSITION_VAL;
3643 #endif
3644 
3645 	if (ch > maxchar)
3646 	    return 0;	/* catch the error later */
3647 	if ((m = &currinf.fontp->macro[ch])->pos == NULL)
3648 	    return 0;	/* catch the error later */
3649 #ifdef TEXXET
3650 	PUSH_POSITION;
3651 	if (! TATE && currinf.dir < 0)
3652 	    moveH(1, -m->dvi_adv);
3653 	if (geom_scan_frame == NULL) {
3654 #endif
3655 	    oldinfo = currinf;
3656 	    oldmaxchar = maxchar;
3657 	    WW = XX = YY = ZZ = 0;
3658 	    currinf.tn_table_len = VFTABLELEN;
3659 	    currinf.tn_table = currinf.fontp->vf_table;
3660 	    currinf.tn_head = currinf.fontp->vf_chain;
3661 	    currinf.pos = m->pos;
3662 	    currinf.end = m->end;
3663 	    currinf.virtual = currinf.fontp;
3664 	    geom_scan_part(geom_do_char, fp, info, geom_current_frame, currinf.fontp->dimconv);
3665 	    currinf = oldinfo;
3666 	    maxchar = oldmaxchar;
3667 #ifdef TEXXET
3668 	    POP_POSITION;
3669 	}
3670 #endif
3671 	return DIR * m->dvi_adv;
3672     }
3673     else {
3674 	XDVI_FATAL((stderr, "currinf.set_char_p is not a registered routine!"));
3675     }
3676     /* NOTREACHED */
3677     return 0;
3678 }
3679 
3680 /*
3681  *	Do a rule in the geometry-scanning routine.
3682  */
3683 
3684 static void
geom_do_rule(struct scan_info * info,long h,long w)3685 geom_do_rule(struct scan_info *info, long h, long w)
3686 {
3687     long x, y;
3688     struct geom_info *g_info = info->data;
3689 #ifdef TEXXET
3690     DEFINE_POSITION_VAL;
3691     PUSH_POSITION;
3692 #endif
3693 
3694     if (bbox_rotated) {
3695 	fprintf(stderr, "geom_do_rotated_rule(h, w) is not implemented!\n");
3696 	return;
3697     }
3698     h = h * bbox_matrix[1][1];
3699     w = w * bbox_matrix[0][0];
3700 
3701 #ifdef TEXXET
3702     if (! TATE && currinf.dir < 0)
3703 	moveH(1, - w + 1);
3704 #endif
3705     x = G_PXL_H;
3706     y = PXL_V;
3707 #ifdef PTEX
3708     if (TATE)
3709 	g_info->geom_box(info, x, y, x + xpixel_round(h) - 1,
3710 			 y + xpixel_round(w) - 1);
3711     else
3712 #endif /* PTEX */
3713     g_info->geom_box(info, x, y - xpixel_round(h) + 1,
3714 		     x + xpixel_round(w) - 1, y);
3715 #ifdef TEXXET
3716     POP_POSITION;
3717 #endif
3718 }
3719 
3720 /*
3721  *	Geometric dvi scanner work routine.  This does most of the work
3722  *	(a) reading from a page, and (b) executing vf macros.
3723  */
3724 
3725 void
geom_scan_part(long (* char_proc)(FILE *,struct scan_info *,wide_ubyte),FILE * fp,struct scan_info * info,struct frame * minframe,double current_dimconv)3726 geom_scan_part(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
3727 	       FILE *fp, struct scan_info *info, struct frame *minframe, double current_dimconv)
3728 {
3729     ubyte ch;
3730 #ifdef TEXXET
3731     struct drawinf oldinfo;
3732     wide_ubyte oldmaxchar = 0;
3733     off_t file_pos = 0;
3734     int refl_count = 0;
3735 #endif
3736 
3737     currinf.fontp = NULL;
3738     currinf.set_char_p = set_no_char;
3739 #ifdef TEXXET
3740     currinf.dir = 1;
3741     geom_scan_frame = NULL;	/* indicates we're not scanning */
3742 #endif
3743     for (;;) {
3744 	ch = xone(fp);
3745 	if (ch <= (ubyte)(SETCHAR0 + 127))
3746 	    xmoveH(1, char_proc(fp, info, ch));
3747 	else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63)) {
3748 	    change_font((unsigned long)(ch - FNTNUM0));
3749 	}
3750 	else {
3751 	    long a, b;
3752 
3753 	    switch (ch) {
3754 	    case SET1:
3755 	    case PUT1:
3756 		a = char_proc(fp, info, xone(fp));
3757 		if (ch != PUT1)
3758 		    xmoveH(1, a);
3759 		break;
3760 
3761 	    case SET2:
3762 	    case PUT2:
3763 		if (!resource.omega)
3764 		    dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
3765 				  __FILE__, __LINE__, ch);
3766 		else {
3767 #ifdef TEXXET
3768 		    char_proc(fp, info, xnum(fp, 2));
3769 #else
3770 		    a = char_proc(fp, info, xnum(fp, 2));
3771 		    if (ch != PUT2)
3772 			xmoveH(1, a);
3773 #endif
3774 		}
3775 		break;
3776 
3777 	    case SET3:
3778 	    case PUT3:
3779 		if (!resource.omega)
3780 		    dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
3781 				  __FILE__, __LINE__, ch);
3782 		else {
3783 #ifdef TEXXET
3784 		    char_proc(fp, info, xnum(fp, 3));
3785 #else
3786 		    a = char_proc(fp, info, xnum(fp, 3));
3787 		    if (ch != PUT3)
3788 			xmoveH(1, a);
3789 #endif
3790 		}
3791 		break;
3792 
3793 	    case SET4:
3794 	    case PUT4:
3795 		if (!resource.omega)
3796 		    dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
3797 				  __FILE__, __LINE__, ch);
3798 		else {
3799 #ifdef TEXXET
3800 		    char_proc(fp, info, xnum(fp, 4));
3801 #else
3802 		    a = char_proc(fp, info, xnum(fp, 4));
3803 		    if (ch != PUT4)
3804 			xmoveH(1, a);
3805 #endif
3806 		}
3807 		break;
3808 
3809 	    case SETRULE:
3810 		/* Be careful, dvicopy outputs rules with
3811 		   height = 0x80000000.  We don't want any
3812 		   SIGFPE here. */
3813 		a = xsfour(fp);
3814 		b = xspell_conv(xsfour(fp));
3815 		if (a >= 0 && b >= 0
3816 #ifdef TEXXET
3817 		    && geom_scan_frame == NULL
3818 #endif
3819 		    ) {
3820 		    /* is this a geom scan? */
3821 		    if (info->geom_special != NULL)
3822 			geom_do_rule(info, xspell_conv(a), b);
3823 		}
3824 		moveH(DIR, b);
3825 		break;
3826 
3827 	    case PUTRULE:
3828 		a = xspell_conv(xsfour(fp));
3829 		b = xspell_conv(xsfour(fp));
3830 		if (a >= 0 && b >= 0
3831 #ifdef TEXXET
3832 		    && geom_scan_frame == NULL
3833 #endif
3834 		    ) {
3835 		    /* is this a geom scan? */
3836 		    if (info->geom_special != NULL)
3837 			geom_do_rule(info, a, b);
3838 		}
3839 		break;
3840 
3841 	    case NOP:
3842 		break;
3843 
3844 	    case BOP:
3845 		xskip(fp, (long)11 * 4);
3846 		DVI_H = G_OFFSET_X;
3847 		DVI_V = G_OFFSET_Y;
3848 		PXL_V = xpixel_conv(DVI_V);
3849 		WW = XX = YY = ZZ = 0;
3850 		/* create pagebreak in character scan */
3851 		if (info->geom_special == NULL) {
3852 		    do_newpage(info);
3853 		}
3854 		break;
3855 
3856 	    case PUSH:
3857 		if (geom_current_frame->next == NULL) {
3858 		    struct frame *newp = xmalloc(sizeof *newp);
3859 
3860 		    geom_current_frame->next = newp;
3861 		    newp->prev = geom_current_frame;
3862 		    newp->next = NULL;
3863 		}
3864 		geom_current_frame = geom_current_frame->next;
3865 		geom_current_frame->data = currinf.data;
3866 		break;
3867 
3868 	    case POP:
3869 		if (geom_current_frame == minframe)
3870 		    dvi_fmt_error("more POPs than PUSHes");
3871 		currinf.data = geom_current_frame->data;
3872 		geom_current_frame = geom_current_frame->prev;
3873 		break;
3874 
3875 #ifdef TEXXET
3876 	    case SREFL:
3877 		if (geom_scan_frame == NULL) {
3878 		    /* we're not scanning:  save some info. */
3879 		    oldinfo = currinf;
3880 		    oldmaxchar = maxchar;
3881 		    if (!currinf.virtual)
3882 			file_pos = xtell(fp, currinf.pos);
3883 		    geom_scan_frame = geom_current_frame;	/* start scanning */
3884 		    refl_count = 0;
3885 		    break;
3886 		}
3887 		/* we are scanning */
3888 		if (geom_current_frame == geom_scan_frame)
3889 		    ++refl_count;
3890 		break;
3891 
3892 	    case EREFL:
3893 		if (geom_scan_frame != NULL) {	/* if we're scanning */
3894 		    if (geom_current_frame == geom_scan_frame
3895 			&& --refl_count < 0) {
3896 			/* we've hit the end of our scan */
3897 			geom_scan_frame = NULL;
3898 			/* first:  push */
3899 			if (geom_current_frame->next == NULL) {
3900 			    struct frame *newp = xmalloc(sizeof *newp);
3901 
3902 			    geom_current_frame->next = newp;
3903 			    newp->prev = geom_current_frame;
3904 			    newp->next = NULL;
3905 			}
3906 			geom_current_frame = geom_current_frame->next;
3907 			geom_current_frame->data = currinf.data;
3908 			/* next:  restore old file position, XX, etc. */
3909 			if (!currinf.virtual) {
3910 			    off_t bgn_pos = xtell(fp, G_dvi_buf_ptr);
3911 
3912 			    if (file_pos >= bgn_pos) {
3913 				oldinfo.pos = dvi_buffer + (file_pos - bgn_pos);
3914 				oldinfo.end = currinf.end;
3915 			    }
3916 			    else {
3917 				(void)lseek(fileno(fp), file_pos,
3918 					    SEEK_SET);
3919 				oldinfo.pos = oldinfo.end;
3920 			    }
3921 			}
3922 			currinf = oldinfo;
3923 			maxchar = oldmaxchar;
3924 			/* and then:  recover position info. */
3925 			DVI_H = geom_current_frame->data.dvi_h;
3926 			DVI_V = geom_current_frame->data.dvi_v;
3927 			PXL_V = geom_current_frame->data.pxl_v;
3928 			/* and finally, reverse direction */
3929 			currinf.dir = -currinf.dir;
3930 		    }
3931 		    break;
3932 		}
3933 		/* we're not scanning, */
3934 		/* so just reverse direction and then pop */
3935 		currinf.dir = -currinf.dir;
3936 		currinf.data = geom_current_frame->data;
3937 		geom_current_frame = geom_current_frame->prev;
3938 		break;
3939 #endif /* TEXXET */
3940 
3941 	    case RIGHT1:
3942 	    case RIGHT2:
3943 	    case RIGHT3:
3944 	    case RIGHT4:
3945 		xmoveH(DIR, xspell_conv(xsnum(fp, ch - RIGHT1 + 1)));
3946 		break;
3947 
3948 	    case W1:
3949 	    case W2:
3950 	    case W3:
3951 	    case W4:
3952 		WW = xspell_conv(xsnum(fp, ch - W0));
3953 	    case W0:
3954 		xmoveH(DIR, WW);
3955 		break;
3956 
3957 	    case X1:
3958 	    case X2:
3959 	    case X3:
3960 	    case X4:
3961 		XX = xspell_conv(xsnum(fp, ch - X0));
3962 	    case X0:
3963 		xmoveH(DIR, XX);
3964 		break;
3965 
3966 	    case DOWN1:
3967 	    case DOWN2:
3968 	    case DOWN3:
3969 	    case DOWN4:
3970 		xmoveV(1, xspell_conv(xsnum(fp, ch - DOWN1 + 1)));
3971 		break;
3972 
3973 	    case Y1:
3974 	    case Y2:
3975 	    case Y3:
3976 	    case Y4:
3977 		YY = xspell_conv(xsnum(fp, ch - Y0));
3978 	    case Y0:
3979 		xmoveV(1, YY);
3980 		break;
3981 
3982 	    case Z1:
3983 	    case Z2:
3984 	    case Z3:
3985 	    case Z4:
3986 		ZZ = xspell_conv(xsnum(fp, ch - Z0));
3987 	    case Z0:
3988 		xmoveV(1, ZZ);
3989 		break;
3990 
3991 	    case FNT1:
3992 	    case FNT2:
3993 	    case FNT3:
3994 	    case FNT4:
3995 		change_font(xnum(fp, ch - FNT1 + 1));
3996 		break;
3997 
3998 	    case XXX1:
3999 	    case XXX2:
4000 	    case XXX3:
4001 	    case XXX4:
4002 		a = xnum(fp, ch - XXX1 + 1);
4003 		if (a > 0) {
4004 		    char *str = read_special(fp, a);
4005 
4006 		    /* is this a geom scan? */
4007 		    if (info->geom_special != NULL) {
4008 			/* process the bounding box */
4009 			geom_do_special(info, str, current_dimconv);
4010 			/* process the specials we're looking for */
4011 			info->geom_special(info, str, a);
4012 		    }
4013 		}
4014 		break;
4015 
4016 	    case FNTDEF1:
4017 	    case FNTDEF2:
4018 	    case FNTDEF3:
4019 	    case FNTDEF4:
4020 		xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
4021 		a = (long)xone(fp);
4022 		xskip(fp, a + (long)xone(fp));
4023 		break;
4024 
4025 #ifdef PTEX
4026 	    case TDIR:
4027 		TATE = xone(fp);
4028 		break;
4029 #endif /* PTEX */
4030 
4031 #ifndef TEXXET
4032 	    case SREFL:
4033 	    case EREFL:
4034 #endif
4035 	    case PRE:
4036 	    case POST:
4037 	    case POSTPOST:
4038 	    case EOP:
4039 	    default:
4040 		return;
4041 
4042 	    }	/* end switch */
4043 	}	/* end else (ch not a SETCHAR or FNTNUM) */
4044     }	/* end for */
4045 }
4046 
4047 
4048 /*
4049  *	Main scanning routine.
4050  */
4051 
4052 void
geom_scan(long (* char_proc)(FILE *,struct scan_info *,wide_ubyte),FILE * fp,struct scan_info * info,int pageno)4053 geom_scan(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
4054 	  FILE *fp, struct scan_info *info, int pageno)
4055 {
4056     volatile off_t pos_save = 0;
4057     struct drawinf currinf_save;
4058     ubyte maxchar_save;
4059 
4060 #if PS
4061     if (info->geom_special != NULL && scanned_page < current_page) {
4062 	fprintf(stderr, "shouldn't happen: %d >= %d!\n", scanned_page, current_page);
4063 	return;	/* should not happen */
4064     }
4065 #endif
4066 
4067     if (dvi_pointer_frame != NULL)
4068 	pos_save = lseek(fileno(fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
4069 
4070     (void) lseek(fileno(fp), pageinfo_get_offset(pageno), SEEK_SET);
4071 
4072     currinf_save = currinf;
4073     maxchar_save = maxchar;
4074 
4075     memset((char *)&currinf.data, '\0', sizeof currinf.data);
4076     currinf.tn_table_len = TNTABLELEN;
4077     currinf.tn_table = tn_table;
4078     currinf.tn_head = tn_head;
4079     currinf.pos = currinf.end = dvi_buffer;
4080     currinf.virtual = NULL;
4081 
4082     if (!setjmp(info->done_env)) {
4083 	geom_scan_part(char_proc, fp, info, geom_current_frame = &geom_frame0, dimconv);
4084     }
4085 
4086     maxchar = maxchar_save;
4087     currinf = currinf_save;
4088 
4089     if (dvi_pointer_frame != NULL) {
4090 	(void)lseek(fileno(fp), pos_save, SEEK_SET);
4091 	dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
4092     }
4093 }
4094 
4095 
4096 /*
4097  *	Routines for source special lookup
4098  */
4099 
4100 struct src_spec_data {
4101     long x, y;				/* coordinates we're looking for */
4102     unsigned long distance;		/* best distance so far */
4103     Boolean recent_in_best;		/* most recent string == XXX->best */
4104     struct src_parsed_special best;	/* best special so far */
4105     struct src_parsed_special recent;	/* most recent special */
4106 };
4107 
4108 void
src_parse(const char * str,int str_len,struct src_parsed_special * parsed)4109 src_parse(const char *str, int str_len, struct src_parsed_special *parsed)
4110 {
4111     const char *p = str;
4112 
4113     if (*p >= '0' && *p <= '9') {
4114 	parsed->line = atoi(p);
4115 	do {
4116 	    ++p;
4117 	    str_len--;
4118 	}
4119 	while (*p >= '0' && *p <= '9');
4120     }
4121 
4122     parsed->col = 0;
4123     if (*p == ':') {
4124 	++p;
4125 	str_len--;
4126 	parsed->col = atoi(p);
4127 	while (*p >= '0' && *p <= '9') {
4128 	    ++p;
4129 	    str_len--;
4130 	}
4131     }
4132 
4133     if (*p == ' ') {
4134 	++p;
4135 	str_len--;
4136     }
4137 
4138     if (*p != '\0') {
4139 	size_t len = str_len + 1;
4140 
4141 	if (len > parsed->filename_len) {
4142 	    if (parsed->filename_len != 0)
4143 		free(parsed->filename);
4144 	    parsed->filename_len = (len & -8) + 64; /* rounding? */
4145 	    parsed->filename = xmalloc(parsed->filename_len);
4146 	}
4147 	memcpy(parsed->filename, p, len);
4148     }
4149 }
4150 
4151 static void
src_spec_box(struct scan_info * info,long ulx,long uly,long lrx,long lry)4152 src_spec_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
4153 {
4154     struct geom_info *g_info = (struct geom_info *)info->data;
4155     struct src_spec_data *data = g_info->geom_data;
4156     unsigned long distance;
4157 
4158     distance = 0;
4159 
4160     if (data->x < ulx)
4161 	distance += (ulx - data->x) * (ulx - data->x);
4162     else if (data->x > lrx)
4163 	distance += (data->x - lrx) * (data->x - lrx);
4164 
4165     if (data->y < uly)
4166 	distance += (uly - data->y) * (uly - data->y);
4167     else if (data->y > lry)
4168 	distance += (data->y - lry) * (data->y - lry);
4169 
4170     if (distance < data->distance) {
4171 	data->distance = distance;
4172 
4173 	/* Copy it over */
4174 	if (!data->recent_in_best) {
4175 	    data->best.line = data->recent.line;
4176 	    data->best.col = data->recent.col;
4177 	    if (data->recent.filename_len != 0) {
4178 		if (data->best.filename_len < data->recent.filename_len) {
4179 		    if (data->best.filename_len != 0)
4180 			free(data->best.filename);
4181 		    data->best.filename_len = data->recent.filename_len;
4182 		    data->best.filename = xmalloc(data->best.filename_len);
4183 		}
4184 		memcpy(data->best.filename, data->recent.filename,
4185 		       data->recent.filename_len);
4186 	    }
4187 
4188 	    data->recent_in_best = True;
4189 	}
4190 
4191 	/* Quit early if we've found our glyph.  */
4192 	if (distance == 0 && data->best.filename_len != 0) {
4193 	    longjmp(info->done_env, 1);
4194 	}
4195     }
4196 }
4197 
4198 static void
src_spec_special(struct scan_info * info,const char * str,int str_len)4199 src_spec_special(struct scan_info *info, const char *str, int str_len)
4200 {
4201     struct geom_info *g_info = (struct geom_info *)info->data;
4202     struct src_spec_data *data = g_info->geom_data;
4203 
4204     if (memcmp(str, "src:", 4) != 0)
4205 	return;
4206 
4207     src_parse(str + 4, str_len - 4, &data->recent);
4208 
4209     /*
4210      * If this is the first special on the page, we may already have
4211      * spotted the nearest box.
4212      */
4213 
4214     if (data->best.filename_len == 0) {
4215 	data->best.line = data->recent.line;
4216 	data->best.col = data->recent.col;
4217 	if (data->recent.filename_len != 0) {
4218 	    if (data->best.filename_len < data->recent.filename_len) {
4219 		if (data->best.filename_len != 0)
4220 		    free(data->best.filename);
4221 		data->best.filename_len = data->recent.filename_len;
4222 		data->best.filename = xmalloc(data->best.filename_len);
4223 	    }
4224 	    memcpy(data->best.filename, data->recent.filename,
4225 		   data->recent.filename_len);
4226 
4227 	    data->recent_in_best = True;
4228 	}
4229 
4230 	if (data->distance == 0) {
4231 	    longjmp(info->done_env, 1);
4232 	}
4233     }
4234     else
4235 	data->recent_in_best = False;
4236 }
4237 
4238 /*
4239  *	Routines for reverse searches on other pages.
4240  */
4241 
4242 static struct src_parsed_special found;
4243 /* static jmp_buf scan_env; */
4244 
4245 static Boolean
scan_first_src_spcl(char * str,int str_len,void * data)4246 scan_first_src_spcl(char *str, int str_len, void *data)
4247 {
4248     UNUSED(data);
4249     if (memcmp(str, "src:", 4) != 0)
4250 	return False;
4251 
4252     src_parse(str + 4, str_len - 4, &found);
4253 
4254     return True;
4255 }
4256 
4257 static Boolean
scan_last_src_spcl(char * str,int str_len,void * data)4258 scan_last_src_spcl(char *str, int str_len, void *data)
4259 {
4260     UNUSED(data);
4261     if (memcmp(str, "src:", 4) != 0)
4262 	return False;
4263 
4264     src_parse(str + 4, str_len - 4, &found);
4265 
4266     return True;
4267 }
4268 
4269 
4270 static void
src_spawn_editor(const struct src_parsed_special * parsed)4271 src_spawn_editor(const struct src_parsed_special *parsed)
4272 {
4273     char *expanded_filename;
4274     char **argv;
4275     const char *p;
4276     char *q;
4277     int i;
4278 
4279     struct stat buf;
4280 
4281     /* first, determine the editor if necessary */
4282     if (resource.editor == NULL || *resource.editor == '\0') {
4283 	p = getenv("XEDITOR");
4284 	if (p != NULL)
4285 	    resource.editor = xstrdup(p);
4286 	else {
4287 
4288 	    p = getenv("VISUAL");
4289 	    if (p == NULL) {
4290 		p = getenv("EDITOR");
4291 		if (p == NULL) {
4292 		    popup_message(globals.widgets.top_level,
4293 				  MSG_WARN,
4294 				  /* help text */
4295 				  "Use the \"-editor\" command-line opion, the X resource "
4296 				  "\"xdvi.editor\" or one of the following environment variables "
4297 				  "to select the editor for source specials: "
4298 				  "\"XEDITOR\", \"VISUAL\" or \"EDITOR\".\n"
4299 				  "See the xdvi man page for more information on source specials "
4300 				  "and the editor options.",
4301 				  /* message */
4302 				  "No custom editor set - using vi as default.");
4303 		    p = "vi";
4304 		}
4305 	    }
4306 	    q = xmalloc(strlen(p) + 10);
4307 	    memcpy(q, "xterm -e ", 9);
4308 	    strcpy(q + 9, p);
4309 	    resource.editor = q;
4310 	}
4311     }
4312 
4313     /* now try to open the file; find_file allocates space for expanded_filename */
4314     if ((expanded_filename = find_file(parsed->filename, &buf, kpse_tex_format)) == NULL) {
4315 	popup_message(globals.widgets.top_level,
4316 		      MSG_ERR, NULL,
4317 		      "File \"%s\" not found, couldn't jump to special\n\"%s:%d\"\n",
4318 		      parsed->filename, parsed->filename, parsed->line);
4319     }
4320     else {
4321 	TRACE_SRC((stderr, "source file \"%s\" expanded to \"%s\"\n", parsed->filename, expanded_filename));
4322 	if (buf.st_mtime > globals.dvi_file.time) {
4323 	    statusline_info(STATUS_FOREVER,
4324 			     "Warning: TeX file is newer than dvi file - "
4325 			     "source special information might be wrong.");
4326 	}
4327 
4328 	/* this allocates argv */
4329 	argv = src_format_arguments(get_separated_list(resource.editor, " \t", True),
4330 				    expanded_filename, parsed->line, parsed->col);
4331 
4332 	fork_process(argv[0], False, NULL, NULL, NULL, argv);
4333 
4334 	free(expanded_filename);
4335 	for (i = 0; argv[i] != NULL; i++)
4336 	    free(argv[i]);
4337 	free(argv);
4338     }
4339 }
4340 
4341 off_t
save_file_status(FILE * fp,struct drawinf * currinf_save,ubyte * maxchar_save)4342 save_file_status(FILE *fp, struct drawinf *currinf_save, ubyte *maxchar_save)
4343 {
4344     off_t pos_save = 0;
4345     if (dvi_pointer_frame != NULL)
4346 	pos_save = lseek(fileno(fp), 0L, SEEK_CUR)
4347 	    - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
4348 
4349     *currinf_save = currinf;
4350     *maxchar_save = maxchar;
4351     return pos_save;
4352 }
4353 
4354 void
restore_file_status(FILE * fp,struct drawinf currinf_save,ubyte maxchar_save,off_t pos_save)4355 restore_file_status(FILE *fp, struct drawinf currinf_save, ubyte maxchar_save, off_t pos_save)
4356 {
4357     maxchar = maxchar_save;
4358     currinf = currinf_save;
4359 
4360     if (dvi_pointer_frame != NULL) {
4361 	(void)lseek(fileno(fp), pos_save, SEEK_SET);
4362 	dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
4363     }
4364 }
4365 
4366 
4367 
4368 /*
4369  *	The main routine for source specials (reverse search).
4370  */
4371 void
source_reverse_search(int x,int y,wide_bool call_editor)4372 source_reverse_search(int x, int y, wide_bool call_editor)
4373 {
4374     struct scan_info info;
4375     struct geom_info g_info;
4376     struct src_spec_data data;
4377     struct src_parsed_special *foundp;
4378 
4379     info.geom_special = src_spec_special;
4380 
4381     g_info.geom_box = src_spec_box;
4382     g_info.geom_data = &data;
4383 
4384     info.data = &g_info;
4385 
4386     data.x = x;
4387     data.y = y;
4388     data.distance = 0xffffffff;
4389     data.recent_in_best = True;
4390     data.best.filename_len = data.recent.filename_len = 0;
4391     foundp = &data.best;
4392 
4393     geom_scan(geom_do_char, globals.dvi_file.bak_fp, &info, current_page);
4394 
4395     if (data.best.filename_len == 0) {
4396 	/*
4397 	 * nothing found on current page;
4398 	 * scan next and previous pages with increasing offset
4399 	 */
4400 	volatile int upper, lower;
4401 	volatile off_t pos_save;
4402 	struct drawinf currinf_save;
4403 	ubyte maxchar_save;
4404 
4405 	/* Save file position */
4406 	pos_save = save_file_status(globals.dvi_file.bak_fp, &currinf_save, &maxchar_save);
4407 
4408 	upper = lower = current_page;
4409 	found.filename_len = 0;	/* mark it as empty */
4410 	for (;;) {
4411 	    if (++upper < total_pages) {
4412 		(void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(upper), SEEK_SET);
4413 		memset((char *)&currinf.data, '\0', sizeof currinf.data);
4414 		currinf.tn_table_len = TNTABLELEN;
4415 		currinf.tn_table = tn_table;
4416 		currinf.tn_head = tn_head;
4417 		currinf.pos = currinf.end = dvi_buffer;
4418 		currinf.virtual = NULL;
4419 
4420 		if (spcl_scan(scan_first_src_spcl, NULL, True, globals.dvi_file.bak_fp)) {
4421 		    lower = upper;
4422 		    break;
4423 		}
4424 	    }
4425 	    else if (lower < 0)
4426 		break;
4427 
4428 	    if (--lower >= 0) {
4429 		(void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(lower), SEEK_SET);
4430 
4431 		memset((char *)&currinf.data, '\0', sizeof currinf.data);
4432 		currinf.tn_table_len = TNTABLELEN;
4433 		currinf.tn_table = tn_table;
4434 		currinf.tn_head = tn_head;
4435 		currinf.pos = currinf.end = dvi_buffer;
4436 		currinf.virtual = NULL;
4437 
4438 		(void)spcl_scan(scan_last_src_spcl, NULL, False, globals.dvi_file.bak_fp);
4439 		if (found.filename_len != 0)
4440 		    break;
4441 	    }
4442 	}
4443 
4444 	if (found.filename_len != 0)
4445 	    statusline_info(STATUS_MEDIUM,
4446 			     "No source specials on this page - nearest on page %d",
4447 			     lower + globals.pageno_correct);
4448 	else {
4449 	    /* nothing found at all; complain */
4450 	    xdvi_bell();
4451 	    popup_message(globals.widgets.top_level,
4452 			  MSG_ERR,
4453 			  /* helptext */
4454 			  reverse_search_helptext,
4455 			  /* popup */
4456 			  "No source specials in this DVI file - couldn't do reverse search.");
4457 	}
4458 
4459 	/* Restore file status.  */
4460 	restore_file_status(globals.dvi_file.bak_fp, currinf_save, maxchar_save, pos_save);
4461 
4462 	foundp = &found;
4463     }
4464 
4465     if (data.recent.filename_len != 0)
4466 	free(data.recent.filename);
4467 
4468     if (foundp->filename_len != 0) {
4469 	if (call_editor) {
4470 	    src_spawn_editor(foundp);
4471 	}
4472 	else {
4473 	    statusline_info(STATUS_MEDIUM, "nearest special at (%d,%d): \"%s:%d\"",
4474 			     x / currwin.shrinkfactor, y / currwin.shrinkfactor, foundp->filename, foundp->line);
4475 	}
4476 	free(foundp->filename);
4477     }
4478 }
4479 
4480 
4481 /*
4482  *	Debug routines for source special display (highlight the first box
4483  *	after each source special, or highlight each box).
4484  */
4485 
4486 struct src_spec_show_data {
4487     Boolean do_this_one;	/* flag set after source special */
4488     Boolean do_them_all;	/* flag to reset the above to */
4489 };
4490 
4491 static void
src_spec_show_box(struct scan_info * info,long ulx,long uly,long lrx,long lry)4492 src_spec_show_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
4493 {
4494     struct geom_info *g_info = (struct geom_info *)info->data;
4495     struct src_spec_show_data *data = g_info->geom_data;
4496 
4497     if (data->do_this_one) {
4498 	long x = ulx / mane.shrinkfactor;
4499 	long y = uly / mane.shrinkfactor;
4500 
4501 	XDrawRectangle(DISP, mane.win, globals.gc.high,
4502 		       x - mane_base_x, y - mane_base_y,
4503 		       lrx / mane.shrinkfactor - x,
4504 		       lry / mane.shrinkfactor - y);
4505 	data->do_this_one = data->do_them_all;
4506     }
4507 }
4508 
4509 static void
src_spec_show_special(struct scan_info * info,const char * str,int str_len)4510 src_spec_show_special(struct scan_info *info, const char *str, int str_len)
4511 {
4512     /*     if (memcmp(str, "src:", 4) != 0) */
4513     /* 	return; */
4514     struct geom_info *g_info = (struct geom_info *)info->data;
4515     UNUSED(str_len);
4516     XDVI_INFO((stdout, "special: %s", str));
4517     ((struct src_spec_show_data *)g_info->geom_data)->do_this_one = True;
4518 }
4519 
4520 void
source_special_show(wide_bool do_them_all)4521 source_special_show(wide_bool do_them_all)
4522 {
4523     struct scan_info info;
4524     struct geom_info g_info;
4525     struct src_spec_show_data src_data;
4526 
4527     info.geom_special = src_spec_show_special;
4528 
4529     g_info.geom_box = src_spec_show_box;
4530     g_info.geom_data = &src_data;
4531 
4532     info.data = &g_info;
4533 
4534     src_data.do_this_one = src_data.do_them_all = do_them_all;
4535 
4536     geom_scan(geom_do_char, globals.dvi_file.bak_fp, &info, current_page);
4537 }
4538 
4539 
4540 /*
4541  *	Routines for forward search (look up a source line).
4542  *
4543  *	The general procedure is:
4544  *	   (1)	Use spcl_scan() to find the page containing the line (or at
4545  *		least the closest line).  This could be optimized further.
4546  *	   (2)	Use geom_scan_part() to find the exact location of the source
4547  *		special, and the box to highlight.
4548  */
4549 
4550 /* These variables are referenced by src_scan_special().  */
4551 
4552 static int src_this_line;
4553 static Boolean src_this_file_equal;
4554 static int src_line;
4555 static int src_col;
4556 static const char *src_file;
4557 static int src_page;
4558 /* static jmp_buf src_env; */
4559 static Boolean found_src;
4560 static unsigned long best_distance;
4561 static unsigned long best_col_dist;
4562 static int best_line;
4563 static int best_page;
4564 static off_t best_offset;
4565 static off_t max_offset;
4566 
4567 /* Some of the above, plus these below, are used by geom_scan_part().  */
4568 
4569 static Boolean src_fwd_active;
4570 
4571 #define BBOX_INFO_MAXIDX 8 /* maximum number of bounding boxes */
4572 
4573 /* list of bounding boxes */
4574 struct bbox_info {
4575     long min_x, max_x, min_y, max_y;
4576     long spcl_min_x, spcl_max_x, spcl_min_y, spcl_max_y;
4577 } g_bbox_info[BBOX_INFO_MAXIDX];
4578 
4579 /* current index in g_bbox_info[] */
4580 static size_t bbox_info_idx = 0;
4581 
4582 static Boolean
src_scan_special(char * str,int str_len,void * data)4583 src_scan_special(char *str, int str_len, void *data)
4584 {
4585     char *p;
4586     int col = 0;
4587     unsigned long distance;
4588     unsigned long col_dist;
4589 
4590     UNUSED(data);
4591     if (memcmp(str, "src:", 4) != 0)
4592 	return False;
4593 
4594     found_src = True;
4595 
4596     p = str + 4;
4597     str_len -= 4;
4598 
4599     if (*p >= '0' && *p <= '9') {
4600 	src_this_line = atoi(p);
4601 	do {
4602 	    ++p;
4603 	    str_len--;
4604 	}
4605 	while (*p >= '0' && *p <= '9');
4606     }
4607 
4608     if (*p == ':') {
4609 	++p;
4610 	str_len--;
4611 	col = atoi(p);
4612 	while (*p >= '0' && *p <= '9') {
4613 	    ++p;
4614 	    str_len--;
4615 	}
4616     }
4617 
4618     if (*p == ' ') {
4619 	++p;
4620 	str_len--;
4621     }
4622 
4623     /* src specials might omit the file name when it had already
4624        been specified on the page; so skip the test when the
4625        special ends right here:
4626     */
4627     if (*p != '\0') {
4628 	ASSERT(globals.dvi_file.dirname != NULL, "DVI name should be set here");
4629 	src_this_file_equal = src_compare(p, str_len, src_file, globals.dvi_file.dirname, globals.dvi_file.dirlen);
4630     }
4631 
4632     if (!src_this_file_equal)
4633 	return False;
4634 
4635     distance = (src_line > src_this_line
4636 		? src_line - src_this_line
4637 		: 2 * (src_this_line - src_line));	/* favor earlier lines */
4638 
4639     if (distance < best_distance) {	/* found a better line */
4640 	best_distance = distance;
4641 	best_line = src_this_line;
4642 	best_page = src_page;
4643 	max_offset = best_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
4644     }
4645     else if (distance == best_distance) { /* still on a good line, remember diff */
4646 	max_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
4647     }
4648 
4649     if (distance == 0 && best_distance == 0) {	/* found a better col */
4650 	col_dist = (src_col > col ? src_col - col : 2 * (col - src_col));
4651 
4652 	if (col_dist < best_col_dist) {
4653 	    best_col_dist = col_dist;
4654 	    best_page = src_page;
4655 	    max_offset = best_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
4656 	}
4657 	else if (col_dist == best_col_dist) {
4658 	    max_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
4659 	}
4660     }
4661     return True;
4662 }
4663 
4664 static Boolean
htex_scan_special(char * str,int str_len,void * data)4665 htex_scan_special(char *str, int str_len, void *data)
4666 {
4667     UNUSED(data);
4668 
4669     if (g_anchor_pos == NULL)
4670 	return False;
4671 
4672     /* first, hypertex specials */
4673     if (memicmp(str, "html:", strlen("html:")) == 0) {
4674 	size_t offset = strlen("html:");
4675 	str += offset;
4676 	str_len -= offset;
4677 
4678 	while (*str == ' ' || *str == '\t') {
4679 	    str++;
4680 	    str_len--;
4681 	}
4682 
4683 	if (memicmp(str, "<a name", strlen("<a name")) != 0)
4684 	    return False;
4685 
4686 	offset = strlen("<a name");
4687 	str += offset;
4688 	str_len -= offset;
4689 	str_len--; /* for the closing > */
4690 
4691 	/* skip over spaces, = and open quotes */
4692 	while (*str == ' ' || *str == '=') {
4693 	    str++;
4694 	    str_len--;
4695 	}
4696 	if (*str == '"') {
4697 	    str++;
4698 	    str_len -= 2; /* don't compare closing quote */
4699 	}
4700 
4701 	/* fprintf(stderr, "comparing: |%s|%s|%d\n", str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)); */
4702 	if (memcmp(str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)) == 0)
4703 	    return True;
4704 	else
4705 	    return False;
4706     }
4707     /* then, hdvips specials */
4708     else if (memicmp(str, "ps:", 3) == 0 && g_anchor_pos != NULL) {
4709 	str += 3;
4710 	if (memicmp(str, "sdict begin ", strlen("sdict begin ")) == 0) {
4711 	    char *ptr = NULL, *pptr = NULL;
4712 	    str += strlen("sdict begin ");
4713 	    if ((ptr = strstr(str, "/View")) != NULL
4714 		&& (ptr = strchr(ptr, '(')) != NULL
4715 		&& (pptr = strchr(ptr + 1, ')')) != NULL) {
4716 		if (memcmp(ptr + 1, g_anchor_pos, pptr - ptr - 1) == 0
4717 		    && g_anchor_pos[pptr - ptr - 1] == '\0') {
4718 		    return True;
4719 		}
4720 	    }
4721 	}
4722 	return False;
4723     }
4724     else {
4725 	return False;
4726     }
4727 }
4728 
4729 static void
htex_scan_special_noreturn(struct scan_info * info,const char * str,int str_len)4730 htex_scan_special_noreturn(struct scan_info *info, const char *str, int str_len)
4731 {
4732     struct geom_info *g_info = (struct geom_info *)info->data;
4733 
4734     /* first, hypertex specials */
4735     if (memcmp(str, "html:", strlen("html:")) == 0) {
4736 	size_t offset = strlen("html:");
4737 	str += offset;
4738 	str_len -= offset;
4739 
4740 	while (*str == ' ' || *str == '\t') {
4741 	    str++;
4742 	    str_len--;
4743 	}
4744 
4745 	if (memicmp(str, "<a name", strlen("<a name")) != 0)
4746 	    return;
4747 
4748 	offset = strlen("<a name");
4749 	str += offset;
4750 	str_len -= offset;
4751 	str_len--; /* for the closing > */
4752 
4753 	/* skip over spaces, = and open quotes */
4754 	while (*str == ' ' || *str == '=') {
4755 	    str++;
4756 	    str_len--;
4757 	}
4758 	if (*str == '"') {
4759 	    str++;
4760 	    str_len -= 2; /* don't compare closing quote */
4761 	}
4762 
4763 	if (g_anchor_pos != NULL
4764 	    && memcmp(str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)) == 0) {
4765 	    *((int *)g_info->geom_data) = pixel_conv(DVI_V);
4766 	    longjmp(info->done_env, 1);
4767 	}
4768     }
4769     /* then, hdvips specials */
4770     else if (memicmp(str, "ps:", 3) == 0 && g_anchor_pos != NULL) {
4771 	str += 3;
4772 	if (memicmp(str, "sdict begin ", strlen("sdict begin ")) == 0) {
4773 	    char *ptr = NULL, *pptr = NULL;
4774 	    str += strlen("sdict begin ");
4775 	    if ((ptr = strstr(str, "/View")) != NULL
4776 		&& (ptr = strchr(ptr, '(')) != NULL
4777 		&& (pptr = strchr(ptr + 1, ')')) != NULL) {
4778 		if (memcmp(ptr + 1, g_anchor_pos, pptr - ptr - 1) == 0
4779 		    && g_anchor_pos[pptr - ptr - 1] == '\0') {
4780 		    *((int *)g_info->geom_data) = pixel_conv(DVI_V);
4781 		    longjmp(info->done_env, 1);
4782 		}
4783 	    }
4784 	}
4785     }
4786 }
4787 
4788 static void
src_spec_fwd_box(struct scan_info * info,long ulx,long uly,long lrx,long lry)4789 src_spec_fwd_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
4790 {
4791     /* Heuristic value to detect column breaks: A negative vertical
4792        offset to the next glyph larger than BBOX_OFF will create a new
4793        bounding box. The amount is in unshrunken pixels, i.e. 120
4794        \approx 1 Line of 12pt Text. */
4795     static const int BBOX_OFF = 360;
4796 
4797     UNUSED(info);
4798     if (src_fwd_active) {
4799 	/* probably a column break, create new box */
4800 	if (lry < g_bbox_info[bbox_info_idx].max_y - BBOX_OFF
4801 	    && lrx > g_bbox_info[bbox_info_idx].max_x + 50) {
4802 	    if (bbox_info_idx < BBOX_INFO_MAXIDX - 1) {
4803 		bbox_info_idx++;
4804 
4805 		g_bbox_info[bbox_info_idx].min_y = g_bbox_info[bbox_info_idx].min_x = LONG_MAX;
4806 		g_bbox_info[bbox_info_idx].max_x = g_bbox_info[bbox_info_idx].max_y = 0;
4807 	    }
4808 	}
4809 	if (ulx < g_bbox_info[bbox_info_idx].min_x) {
4810 	    g_bbox_info[bbox_info_idx].min_x = ulx;
4811 	}
4812 	if (uly < g_bbox_info[bbox_info_idx].min_y) {
4813 	    g_bbox_info[bbox_info_idx].min_y = uly;
4814 	}
4815 	if (lrx > g_bbox_info[bbox_info_idx].max_x)
4816 	    g_bbox_info[bbox_info_idx].max_x = lrx;
4817 	if (lry > g_bbox_info[bbox_info_idx].max_y) {
4818 	    g_bbox_info[bbox_info_idx].max_y = lry;
4819 	}
4820     }
4821 }
4822 
4823 /* dummy procedure for hyperlinks; we don't need geometry info for these. */
4824 static void
htex_dummy_box(struct scan_info * info,long ulx,long uly,long lrx,long lry)4825 htex_dummy_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
4826 {
4827     UNUSED(info);
4828     UNUSED(ulx);
4829     UNUSED(uly);
4830     UNUSED(lrx);
4831     UNUSED(lry);
4832     return;
4833 }
4834 
4835 static void
src_spec_fwd_special(struct scan_info * info,const char * str,int str_len)4836 src_spec_fwd_special(struct scan_info *info, const char *str, int str_len)
4837 {
4838     long pos;
4839     UNUSED(str_len);
4840 
4841     if (memcmp(str, "src:", 4) != 0)	/* if no source special */
4842 	return;
4843 
4844     pos = xtell(globals.dvi_file.bak_fp, currinf.pos);
4845     if (pos >= best_offset)
4846 	src_fwd_active = True;
4847 
4848     if (src_fwd_active) {
4849 	if (pos > max_offset)
4850 	    longjmp(info->done_env, 1);
4851 
4852 	if (G_PXL_H < g_bbox_info[bbox_info_idx].spcl_min_x)
4853 	    g_bbox_info[bbox_info_idx].spcl_min_x = G_PXL_H;
4854 	if (G_PXL_H > g_bbox_info[bbox_info_idx].spcl_max_x)
4855 	    g_bbox_info[bbox_info_idx].spcl_max_x = G_PXL_H;
4856 	if (PXL_V < g_bbox_info[bbox_info_idx].spcl_min_y)
4857 	    g_bbox_info[bbox_info_idx].spcl_min_y = PXL_V;
4858 	if (PXL_V > g_bbox_info[bbox_info_idx].spcl_max_y)
4859 	    g_bbox_info[bbox_info_idx].spcl_max_y = PXL_V;
4860 
4861     }
4862 }
4863 
4864 /*
4865  *	Routine to actually draw the box.
4866  */
4867 
4868 static void
source_fwd_draw_box(void)4869 source_fwd_draw_box(void)
4870 {
4871     if (globals.src.fwd_box_page != current_page) {
4872 	globals.src.fwd_box_page = -1;	/* different page---clear it */
4873     }
4874     else {
4875 	size_t i;
4876 	static const int padding = 15;
4877 
4878 	/* fix oversplitting by heuristics, by merging box n with box n+1 if they overlap */
4879 	for (i = 0; i < bbox_info_idx; i++) {
4880 	    if (g_bbox_info[i].min_x == LONG_MAX)
4881 		continue;
4882 	    if ((g_bbox_info[i+1].min_x < g_bbox_info[i].max_x
4883 		 && g_bbox_info[i+1].min_y < g_bbox_info[i].max_y) ||
4884 		(g_bbox_info[i].min_x < g_bbox_info[i+1].max_x
4885 		 && g_bbox_info[i].min_y < g_bbox_info[i+1].max_y)) { /* overlap */
4886 		g_bbox_info[i].min_x = MIN(g_bbox_info[i].min_x, g_bbox_info[i+1].min_x);
4887 		g_bbox_info[i].min_y = MIN(g_bbox_info[i].min_y, g_bbox_info[i+1].min_y);
4888 		g_bbox_info[i].max_x = MAX(g_bbox_info[i].max_x, g_bbox_info[i+1].max_x);
4889 		g_bbox_info[i].max_y = MAX(g_bbox_info[i].max_y, g_bbox_info[i+1].max_y);
4890 		bbox_info_idx--;
4891 	    }
4892 	}
4893 
4894 	for (i = 0; i <= bbox_info_idx; i++) {
4895 	    int min_x, min_y, max_x, max_y;
4896 
4897 	    volatile XPoint ul, ur, ll, lr;
4898 
4899 	    if (g_bbox_info[i].min_x == LONG_MAX) {
4900 		/* If no glyphs or rules, use hot point of special instead.  */
4901 		g_bbox_info[i].min_x = g_bbox_info[i].spcl_min_x;
4902 		g_bbox_info[i].min_y = g_bbox_info[i].spcl_min_y;
4903 		g_bbox_info[i].max_x = g_bbox_info[i].spcl_max_x;
4904 		g_bbox_info[i].max_y = g_bbox_info[i].spcl_max_y;
4905 	    }
4906 
4907 	    min_x = (g_bbox_info[i].min_x - padding) / mane.shrinkfactor - mane_base_x;
4908 	    min_y = (g_bbox_info[i].min_y - padding) / mane.shrinkfactor - mane_base_y;
4909 	    max_x = (g_bbox_info[i].max_x + padding) / mane.shrinkfactor - mane_base_x;
4910 	    max_y = (g_bbox_info[i].max_y + padding) / mane.shrinkfactor - mane_base_y;
4911 
4912 	    ul.x = min_x;
4913 	    ul.y = min_y;
4914 
4915 	    ur.x = max_x;
4916 	    ur.y = min_y;
4917 
4918 	    ll.x = min_x;
4919 	    ll.y = max_y;
4920 
4921 	    lr.x = max_x;
4922 	    lr.y = max_y;
4923 
4924 	    if (i == 0 && bbox_info_idx == 0) { /* only 1 bounding box */
4925 		/* (2009-08-23) XDrawRectangle is broken in some X
4926 		   implementations (see sourceforge bug #2841005),
4927 		   so use XDrawLines instead
4928 		   XDrawRectangle(DISP, mane.win, globals.gc.high,
4929 		                  min_x, min_y, max_x - min_x, max_y - min_y);
4930 		*/
4931 		XPoint points[5];
4932 		points[0] = ll;
4933 		points[1] = ul;
4934 		points[2] = ur;
4935 		points[3] = lr;
4936 		points[4] = ll;
4937 		XDrawLines(DISP, mane.win, globals.gc.high, points, 5, CoordModeOrigin);
4938 	    }
4939 	    else if (i == 0) { /* draw first bbox with open bottom */
4940 		XPoint points[4];
4941 		points[0] = ll;
4942 		points[1] = ul;
4943 		points[2] = ur;
4944 		points[3] = lr;
4945 		XDrawLines(DISP, mane.win, globals.gc.high, points, 4, CoordModeOrigin);
4946 	    }
4947 	    else if (i > 0 && i < bbox_info_idx) { /* draw middle box with open top and open bottom */
4948 		XPoint points[2];
4949 		points[0] = ul;
4950 		points[1] = ll;
4951 		XDrawLines(DISP, mane.win, globals.gc.high, points, 2, CoordModeOrigin);
4952 		points[0] = ur;
4953 		points[1] = lr;
4954 		XDrawLines(DISP, mane.win, globals.gc.high, points, 2, CoordModeOrigin);
4955 	    }
4956 	    else { /* draw last box with open top */
4957 		XPoint points[4];
4958 		points[0] = ul;
4959 		points[1] = ll;
4960 		points[2] = lr;
4961 		points[3] = ur;
4962 		XDrawLines(DISP, mane.win, globals.gc.high, points, 4, CoordModeOrigin);
4963 	    }
4964 	}
4965     }
4966 }
4967 
4968 #if 0
4969 #include<asm/msr.h>
4970 unsigned long time_start=0, time_end=0;
4971 #endif
4972 
4973 void
source_forward_search(const char * str)4974 source_forward_search(const char *str)
4975 {
4976     volatile off_t pos_save = 0;
4977     struct drawinf currinf_save;
4978     ubyte maxchar_save;
4979     struct scan_info info;
4980     struct geom_info g_info;
4981 
4982     TRACE_CLIENT((stderr, "Entering source_forward_search(%s)", str));
4983 
4984     max_offset = 0;
4985     src_file = str;
4986     while (*src_file == '0')
4987 	++src_file;
4988     if (*src_file < '1' || *src_file > '9') {
4989 	XDVI_WARNING((stderr, "Ignoring malformed source special \"%s\"", str));
4990 	return;
4991     }
4992     src_line = atoi(src_file);
4993     while (*src_file >= '0' && *src_file <= '9')
4994 	++src_file;
4995 
4996     src_col = 0;
4997     if (*src_file == ':') {
4998 	++src_file;
4999 	src_col = atoi(src_file);
5000 	while (*src_file >= '0' && *src_file <= '9')
5001 	    ++src_file;
5002     }
5003 
5004     if (*src_file == ' ')
5005 	++src_file;
5006 
5007     TRACE_CLIENT((stderr, "File = \"%s\", line = %d, col = %d", src_file, src_line, src_col));
5008 
5009     /* Save status of dvi_file reading (in case we hit an error and resume
5010        drawing).  */
5011 
5012     if (dvi_pointer_frame != NULL)
5013 	pos_save = lseek(fileno(globals.dvi_file.bak_fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
5014     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(0), SEEK_SET);
5015 
5016     currinf_save = currinf;
5017     maxchar_save = maxchar;
5018 
5019     memset((char *)&currinf.data, '\0', sizeof currinf.data);
5020     currinf.tn_table_len = TNTABLELEN;
5021     currinf.tn_table = tn_table;
5022     currinf.tn_head = tn_head;
5023     currinf.pos = currinf.end = dvi_buffer;
5024     currinf.virtual = NULL;
5025 
5026     /* Start search over pages */
5027 #if 0
5028     rdtscl(time_start);
5029 #endif
5030 
5031     found_src = False;
5032     best_distance = best_col_dist = ULONG_MAX;
5033     src_this_line = 0;	/* initialize things that are kept as defaults */
5034     src_this_file_equal = False;
5035 
5036     /* These two lines do the actual scanning (first pass).  */
5037     for (src_page = 0; src_page < total_pages; ++src_page)
5038 	(void)spcl_scan(src_scan_special, NULL, False, globals.dvi_file.bak_fp);
5039 
5040     if (best_distance == ULONG_MAX) {
5041 	if (!found_src) {
5042 	    popup_message(globals.widgets.top_level,
5043 			  MSG_WARN,
5044 			  /* helptext */
5045 			  reverse_search_helptext,
5046 			  /* popup */
5047 			  "No source specials in this DVI file - couldn't do reverse search.");
5048 	}
5049 	else {
5050 	    popup_message(globals.widgets.top_level,
5051 			  MSG_WARN,
5052 			  /* helptext */
5053 			  "To enable reverse search, the TeX file has to be compiled with source specials. "
5054 			  "See the xdvi man page (section SOURCE SPECIALS) for details.",
5055 			  /* popup */
5056 			  "No references to source file \"%s\" in DVI file.",
5057 			  src_file);
5058 	}
5059 
5060 	/* Restore file position.  */
5061 	maxchar = maxchar_save;
5062 	currinf = currinf_save;
5063 
5064 	if (dvi_pointer_frame != NULL) {
5065 	    (void)lseek(fileno(globals.dvi_file.bak_fp), pos_save, SEEK_SET);
5066 	    dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
5067 	}
5068 
5069 	return;
5070     }
5071     TRACE_CLIENT((stderr, "Match:  line %d on page %d, offset %lu",
5072 		  best_line, best_page + globals.pageno_correct, (unsigned long)best_offset));
5073 
5074     /*
5075      * In this case we don't need to restore maxchar and currinf, since
5076      * we won't resume drawing -- we'll jump to a new page instead.
5077      */
5078 
5079     /* Move to that page.  */
5080     goto_page(best_page, resource.keep_flag ? NULL : home, False);
5081     page_history_insert(best_page);
5082     globals.ev.flags |= EV_NEWPAGE; /* so that existing mark gets erased */
5083     /* Now search that particular page.  */
5084 
5085     info.geom_special = src_spec_fwd_special;
5086 
5087     g_info.geom_box = src_spec_fwd_box;
5088     g_info.geom_data = NULL;
5089 
5090     src_fwd_active = False;
5091     bbox_info_idx = 0;
5092 
5093     g_bbox_info[bbox_info_idx].min_x =
5094 	g_bbox_info[bbox_info_idx].min_y =
5095 	g_bbox_info[bbox_info_idx].spcl_min_x =
5096 	g_bbox_info[bbox_info_idx].spcl_min_y = LONG_MAX;
5097     g_bbox_info[bbox_info_idx].max_x =
5098 	g_bbox_info[bbox_info_idx].max_y =
5099 	g_bbox_info[bbox_info_idx].spcl_max_x =
5100 	g_bbox_info[bbox_info_idx].spcl_max_y = 0;
5101     globals.src.fwd_box_page = -1;	/* in case of error, suppress box */
5102 
5103     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(best_page), SEEK_SET);
5104     currinf.tn_table_len = TNTABLELEN;
5105     currinf.tn_table = tn_table;
5106     currinf.tn_head = tn_head;
5107     currinf.pos = currinf.end = dvi_buffer;
5108     currinf.virtual = NULL;
5109 
5110     info.data = &g_info;
5111 
5112     if (!setjmp(info.done_env))
5113 	geom_scan_part(geom_do_char, globals.dvi_file.bak_fp, &info, geom_current_frame = &geom_frame0, dimconv);
5114 
5115     if (!src_fwd_active) {
5116 	XDVI_ERROR((stderr, "%s:%d: shouldn't happen: geom_scan_part() failed to re-find the special.", __FILE__, __LINE__));
5117     }
5118     else {
5119 	long x_min = g_bbox_info[bbox_info_idx].min_x;
5120 	long y_min = g_bbox_info[bbox_info_idx].min_y;
5121 	long x_max = g_bbox_info[bbox_info_idx].max_x;
5122 	long y_max = g_bbox_info[bbox_info_idx].max_y;
5123 	do_autoscroll = True;
5124 	globals.src.fwd_box_page = current_page;
5125 	if (x_min == LONG_MAX || x_max == LONG_MAX) {
5126 	    /* If no glyphs or rules, use hot point of special instead.  */
5127 	    x_min = g_bbox_info[bbox_info_idx].spcl_min_x;
5128 	    y_min = g_bbox_info[bbox_info_idx].spcl_min_y;
5129 	    x_max = g_bbox_info[bbox_info_idx].spcl_max_x;
5130 	    y_max = g_bbox_info[bbox_info_idx].spcl_max_y;
5131 	}
5132 	scroll_page_if_needed((int)(x_min / currwin.shrinkfactor) + 2, (int)(x_max / currwin.shrinkfactor) - 2,
5133 			      (int)(y_min / currwin.shrinkfactor) + 10, (int)(y_max / currwin.shrinkfactor) - 10);
5134     }
5135 #if 0
5136     rdtscl(time_end);
5137     printf("time search: %lu\n", time_end - time_start);
5138 #endif
5139 }
5140 
5141 
5142 void
anchor_search(const char * str)5143 anchor_search(const char *str)
5144 {
5145     off_t pos_save = 0;
5146     struct drawinf currinf_save;
5147     ubyte maxchar_save;
5148     volatile int test_page = 0;
5149     Boolean found_anchor = False;
5150     int y_pos = -1;
5151     struct scan_info info;
5152     struct geom_info g_info;
5153 
5154     ASSERT(str != NULL, "Argument to anchor_search() musn't be NULL");
5155     TRACE_HTEX((stderr, "Entering anchor_search(%s)", str));
5156 
5157     /* Save status of dvi_file reading (in case we hit an error and resume drawing).  */
5158     if (dvi_pointer_frame != NULL)
5159 	pos_save = lseek(fileno(globals.dvi_file.bak_fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
5160     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(0), SEEK_SET);
5161 
5162     currinf_save = currinf;
5163     maxchar_save = maxchar;
5164 
5165     memset((char *)&currinf.data, '\0', sizeof currinf.data);
5166     currinf.tn_table_len = TNTABLELEN;
5167     currinf.tn_table = tn_table;
5168     currinf.tn_head = tn_head;
5169     currinf.pos = currinf.end = dvi_buffer;
5170     currinf.virtual = NULL;
5171 
5172     /* Start search over pages */
5173     for (test_page = 0; test_page < total_pages; test_page++) {
5174 	if (spcl_scan(htex_scan_special, NULL, True, globals.dvi_file.bak_fp)) {
5175 	    TRACE_HTEX((stderr, "Found anchor on page %d", test_page));
5176 	    found_anchor = True;
5177 	    break;
5178 	}
5179     }
5180 
5181     if (!found_anchor) {
5182 	TRACE_HTEX((stderr, "Anchor not found"));
5183 	/* Restore file position.  */
5184 	maxchar = maxchar_save;
5185 	currinf = currinf_save;
5186 
5187 	if (dvi_pointer_frame != NULL) {
5188 	    (void)lseek(fileno(globals.dvi_file.bak_fp), pos_save, SEEK_SET);
5189 	    dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
5190 	}
5191 	xdvi_bell();
5192 	statusline_error(STATUS_MEDIUM, "Error: Anchor \"%s\" not found.", str);
5193 	return;
5194     }
5195 
5196     /*
5197      * In this case we don't need to restore maxchar and currinf, since
5198      * we won't resume drawing -- we'll jump to a new page instead.
5199      */
5200 
5201     /* Move to that page.  */
5202     (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(test_page), SEEK_SET);
5203     currinf.tn_table_len = TNTABLELEN;
5204     currinf.tn_table = tn_table;
5205     currinf.tn_head = tn_head;
5206     currinf.pos = currinf.end = dvi_buffer;
5207     currinf.virtual = NULL;
5208 
5209     info.geom_special = htex_scan_special_noreturn;
5210 
5211     g_info.geom_box = htex_dummy_box;
5212     g_info.geom_data = &y_pos;
5213 
5214     info.data = &g_info;
5215 
5216     if (!setjmp(info.done_env))
5217 	geom_scan_part(geom_do_char, globals.dvi_file.bak_fp, &info, geom_current_frame = &geom_frame0, dimconv);
5218 
5219     if (y_pos == -1) { /* not found */
5220 	XDVI_ERROR((stderr, "%s:%d: shouldn't happen: geom_scan_part() failed to re-find the link.", __FILE__, __LINE__));
5221     }
5222     else {
5223 	goto_page(test_page, resource.keep_flag ? NULL : home, False);
5224 	page_history_insert(test_page);
5225 	do_autoscroll = True;
5226 	TRACE_HTEX((stderr, "Found anchor on position %d", y_pos));
5227 	htex_set_anchormarker(y_pos);
5228     }
5229     /* reset info */
5230     free(g_anchor_pos);
5231     g_anchor_pos = NULL;
5232     g_anchor_len = 0;
5233 }
5234 
5235 
5236 #if GREY
5237 
5238 extern	double	pow();
5239 
5240 static void
mask_shifts(Pixel mask,int * pshift1,int * pshift2)5241 mask_shifts(Pixel mask, int *pshift1, int *pshift2)
5242 {
5243     int k, l;
5244 
5245     for (k = 0; (mask & 1) == 0; ++k)
5246 	mask >>= 1;
5247     for (l = 0; (mask & 1) == 1; ++l)
5248 	mask >>= 1;
5249     *pshift1 = sizeof(short) * 8 - l;
5250     *pshift2 = k;
5251 }
5252 
5253 /*
5254  *	Try to allocate 4 color planes for 16 colors (for GXor drawing).
5255  *	Not called if the visual type is TrueColor.
5256  *	When color specials are active, this is called exactly once.
5257  *	It is used for the first foreground/background pair displayed in
5258  *	the document.  For other documents, we act as if this call had failed.
5259  */
5260 
5261 
5262 void
init_plane_masks(void)5263 init_plane_masks(void)
5264 {
5265     Pixel pixel;
5266 
5267     if (globals.gc.do_copy || plane_masks[0] != 0)
5268 	return;
5269 
5270     if (XAllocColorCells(DISP, G_colormap, False, plane_masks, 4, &pixel, 1)) {
5271 	/* Make sure fore_Pixel and back_Pixel are a part of the palette */
5272 	resource.back_Pixel = pixel;
5273 	resource.fore_Pixel = pixel | plane_masks[0] | plane_masks[1]
5274 	    | plane_masks[2] | plane_masks[3];
5275 	if (mane.win != (Window) 0)
5276 	    XSetWindowBackground(DISP, mane.win, resource.back_Pixel);
5277     }
5278     else {
5279 	globals.gc.do_copy = True;
5280 	warn_overstrike();
5281     }
5282 }
5283 
5284 #endif /* GREY */
5285 
5286 #if COLOR
5287 
5288 /*
5289  *	Insert into list of colors to be freed upon opening new document.
5290  */
5291 
5292 static	void
color_list_insert(Pixel pixel)5293 color_list_insert(Pixel pixel)
5294 {
5295     if (color_list_len >= color_list_max) {
5296 	if (color_list_max == 0)
5297 	    color_list = xmalloc((color_list_max += 16) * sizeof *color_list);
5298 	else
5299 	    color_list = xrealloc(color_list,
5300 				  (color_list_max += 16) * sizeof *color_list);
5301     }
5302     color_list[color_list_len++] = pixel;
5303 }
5304 
5305 
5306 /*
5307  *	Warn about colors not being correct.
5308  */
5309 
5310 static	void
color_warn(void)5311 color_warn(void)
5312 {
5313     if (!color_warned) {
5314 	color_warned = True;
5315 	popup_message(globals.widgets.top_level,
5316 		      MSG_WARN,
5317 		      /* helptext */
5318 		      "Either this document is using too many "
5319 		      "colors, or some other application is. "
5320 		      "In the latter case, try to close that "
5321 		      "application and re-read the DVI file.",
5322 		      /* msg */
5323 		      "Cannot allocate colormap entry, "
5324 		      "displayed colors will not be exact.");
5325     }
5326 }
5327 
5328 
5329 /*
5330  *	Allocate a color and add it to our list of pixels to be returned
5331  *	upon opening a new document.
5332  */
5333 
5334 #define	SHIFTIFY(x, shift1, shift2)	((((Pixel)(x)) >> (shift1)) << (shift2))
5335 
5336 static	int	shift1_r, shift1_g, shift1_b;
5337 static	int	shift2_r, shift2_g, shift2_b;
5338 static	Boolean	shifts_good	= False;
5339 
5340 Pixel
alloc_color(const struct rgb * colorp,Pixel fallback_pixel)5341 alloc_color(const struct rgb *colorp, Pixel fallback_pixel)
5342 {
5343     XColor xcol;
5344 
5345     if (G_visual->class == TrueColor) {
5346 	if (!shifts_good) {
5347 	    mask_shifts(G_visual->red_mask,   &shift1_r, &shift2_r);
5348 	    mask_shifts(G_visual->green_mask, &shift1_g, &shift2_g);
5349 	    mask_shifts(G_visual->blue_mask,  &shift1_b, &shift2_b);
5350 	    shifts_good = True;
5351 	}
5352 	return SHIFTIFY(colorp->r, shift1_r, shift2_r)
5353 	    | SHIFTIFY(colorp->g, shift1_g, shift2_g)
5354 	    | SHIFTIFY(colorp->b, shift1_b, shift2_b);
5355     }
5356     else {
5357 	xcol.red = colorp->r;
5358 	xcol.green = colorp->g;
5359 	xcol.blue = colorp->b;
5360 	xcol.flags = DoRed | DoGreen | DoBlue;
5361 	if (XAllocColor(DISP, G_colormap, &xcol)) {
5362 	    color_list_insert(xcol.pixel);
5363 	    if (globals.debug & DBG_DVI)
5364 		printf("alloc_color%6d%6d%6d --> %ld\n",
5365 		       xcol.red, xcol.green, xcol.blue, xcol.pixel);
5366 	    return xcol.pixel;
5367 	}
5368 	else {
5369 	    if (globals.debug & DBG_DVI)
5370 		printf("alloc_color%6d%6d%6d --> failed\n",
5371 		       xcol.red, xcol.green, xcol.blue);
5372 	    color_warn();
5373 	    return fallback_pixel;
5374 	}
5375     }
5376 }
5377 
5378 #undef SHIFTIFY
5379 
5380 
5381 /*
5382  *	Switch colors of GCs, etc.  Called when we're about to use a GC.
5383  */
5384 
5385 void
do_color_change(void)5386 do_color_change(void)
5387 {
5388     static int shrink_allocated_for = 0;
5389     Pixel set_bits;
5390     Pixel clr_bits;
5391 
5392     ASSERT(fg_current != NULL, "Current foreground mustn't be NULL");
5393     ASSERT(bg_current != NULL, "Current background mustn't be NULL");
5394 #if GREY
5395     if (resource.use_grey) {
5396 	if (G_visual->class == TrueColor) {
5397 	    if (!fg_current->pixel_good) {
5398 		fg_current->pixel = alloc_color(&fg_current->color,
5399 						color_data[0].pixel);
5400 		fg_current->pixel_good = True;
5401 	    }
5402 
5403 	    set_bits = fg_current->pixel & ~bg_current->pixel;
5404 	    clr_bits = bg_current->pixel & ~fg_current->pixel;
5405 
5406 	    if (set_bits & G_visual->red_mask)
5407 		set_bits |= G_visual->red_mask;
5408 	    if (clr_bits & G_visual->red_mask)
5409 		clr_bits |= G_visual->red_mask;
5410 	    if (set_bits & G_visual->green_mask)
5411 		set_bits |= G_visual->green_mask;
5412 	    if (clr_bits & G_visual->green_mask)
5413 		clr_bits |= G_visual->green_mask;
5414 	    if (set_bits & G_visual->blue_mask)
5415 		set_bits |= G_visual->blue_mask;
5416 	    if (clr_bits & G_visual->blue_mask)
5417 		clr_bits |= G_visual->blue_mask;
5418 
5419 	    /*
5420 	     * Make the GCs
5421 	     */
5422 
5423 	    globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->pixel, bg_current->pixel);
5424 	    globals.gc.fore2 = NULL;
5425 
5426 	    if (resource.copy
5427 		|| (set_bits && clr_bits && !resource.thorough)) {
5428 		if (!resource.copy) {
5429 		    warn_overstrike();
5430 		}
5431 		globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->pixel, bg_current->pixel);
5432 	    }
5433 	    else {
5434 		if (set_bits) {
5435 		    globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, fg_current->pixel & set_bits, 0);
5436 		    if (clr_bits) {
5437 			globals.gc.fore2 = globals.gc.fore2_bak = set_or_make_gc(globals.gc.fore2_bak, GXandInverted,
5438 										 ~fg_current->pixel & clr_bits, 0);
5439 		    }
5440 		}
5441 		else {
5442 		    globals.gc.fore = set_or_make_gc(globals.gc.fore, GXandInverted,
5443 						     ~fg_current->pixel & clr_bits, 0);
5444 		}
5445 	    }
5446 
5447 	    if (globals.debug & DBG_DVI)
5448 		printf("do_color_change: fg = %lx, bg = %lx, with%s globals.gc.fore2\n",
5449 		       fg_current->pixel, bg_current->pixel,
5450 		       globals.gc.fore2 == NULL ? "out" : "");
5451 
5452 	    if (mane.shrinkfactor > 1) {
5453 		unsigned int i;
5454 		unsigned int sf_squared;
5455 
5456 		sf_squared = mane.shrinkfactor * mane.shrinkfactor;
5457 
5458 		if (shrink_allocated_for < mane.shrinkfactor) {
5459 		    if (pixeltbl != NULL) {
5460 			free((char *) pixeltbl);
5461 			if (pixeltbl_gc2 != NULL) {
5462 			    free((char *) pixeltbl_gc2);
5463 			    pixeltbl_gc2 = NULL;
5464 			}
5465 		    }
5466 		    pixeltbl = xmalloc((sf_squared + 1) * sizeof *pixeltbl);
5467 		    shrink_allocated_for = mane.shrinkfactor;
5468 		}
5469 		if (globals.gc.fore2 != NULL && pixeltbl_gc2 == NULL) {
5470 		    /* Can't use sf_squared (or mane.shrinkfactor) here */
5471 		    pixeltbl_gc2 = xmalloc((shrink_allocated_for * shrink_allocated_for + 1) * sizeof *pixeltbl_gc2);
5472 		}
5473 
5474 		/*
5475 		 * Initialize the pixel lookup table according to the gamma values.
5476 		 */
5477 #define	SHIFTIFY(x, shift1, shift2)	((((Pixel)(x)) >> (shift1)) << (shift2))
5478 
5479 		for (i = 0; i <= sf_squared; ++i) {
5480 		    double frac = resource.gamma > 0
5481 			? pow((double)i / sf_squared, 1 / resource.gamma)
5482 			: 1 - pow((double) (sf_squared - i) / sf_squared, -resource.gamma);
5483 		    unsigned int red, green, blue;
5484 		    Pixel pixel;
5485 		    /*  		    fprintf(stderr, "frac: %f\n", frac); */
5486 		    /* 		    fprintf(stderr, "fg_current: %d, bg_current: %d\n", fg_current->color.r, bg_current->color.r); */
5487 		    red = frac
5488 			* ((double) fg_current->color.r - bg_current->color.r)
5489 			+ bg_current->color.r;
5490 		    green = frac
5491 			* ((double) fg_current->color.g - bg_current->color.g)
5492 			+ bg_current->color.g;
5493 		    blue = frac
5494 			* ((double) fg_current->color.b - bg_current->color.b)
5495 			+ bg_current->color.b;
5496 
5497 		    pixel = SHIFTIFY(red,   shift1_r, shift2_r)
5498 			| SHIFTIFY(green, shift1_g, shift2_g)
5499 			| SHIFTIFY(blue,  shift1_b, shift2_b);
5500 
5501 		    if (globals.gc.fore2 != NULL) {	/* if thorough */
5502 			/*	fprintf(stderr, "++++++ pixeltable at %d: %ld\n", i, pixel & ~bg_current->pixel); */
5503 			pixeltbl[i] = pixel & ~bg_current->pixel;
5504 			pixeltbl_gc2[i] = ~pixel & bg_current->pixel;
5505 		    }
5506 		    else if (resource.copy || (set_bits && clr_bits)) {
5507 			/*	fprintf(stderr, "++++++ pixeltable2 at %d: %ld\n", i, pixel); */
5508 			pixeltbl[i] = pixel;
5509 		    }
5510 		    else {
5511 			/*	fprintf(stderr, "++++++ pixeltable3 at %d: 0x%lx\n", i, ~pixel & clr_bits); */
5512 			/*	fprintf(stderr, "++++++ pixeltable3 at %d: %ld\n", i, pixel & set_bits); */
5513 			pixeltbl[i] = set_bits ? pixel & set_bits : ~pixel & clr_bits;
5514 		    }
5515 		}
5516 #undef	SHIFTIFY
5517 	    }
5518 
5519 	}
5520 	else {	/* not TrueColor */
5521 	    int	i;
5522 	    Boolean	using_planes;
5523 
5524 	    using_planes = (fg_current == bg_head->fg_head && !globals.gc.do_copy);
5525 	    if (!fg_current->palette_good) {
5526 		XColor color;
5527 
5528 		/*
5529 		 * Initialize the pixel lookup table according to the gamma values.
5530 		 */
5531 		for (i = 0; i < 16; ++i) {
5532 		    double frac;
5533 
5534 		    frac = resource.gamma > 0
5535 			? pow((double) i / 15, 1 / resource.gamma)
5536 			: 1 - pow((double) (15 - i) / 15, -resource.gamma);
5537 		    color.red = frac
5538 			* ((double) fg_current->color.r - bg_current->color.r)
5539 			+ bg_current->color.r;
5540 		    color.green = frac
5541 			* ((double) fg_current->color.g - bg_current->color.g)
5542 			+ bg_current->color.g;
5543 		    color.blue = frac
5544 			* ((double) fg_current->color.b - bg_current->color.b)
5545 			+ bg_current->color.b;
5546 
5547 		    color.flags = DoRed | DoGreen | DoBlue;
5548 
5549 		    if (using_planes) {
5550 			color.pixel = resource.back_Pixel;	/* start of block */
5551 			if (i & 1) color.pixel |= plane_masks[0];
5552 			if (i & 2) color.pixel |= plane_masks[1];
5553 			if (i & 4) color.pixel |= plane_masks[2];
5554 			if (i & 8) color.pixel |= plane_masks[3];
5555 			XStoreColor(DISP, G_colormap, &color);
5556 			fg_current->palette[i] = color.pixel;
5557 		    }
5558 		    else {
5559 			if (XAllocColor(DISP, G_colormap, &color)) {
5560 			    fg_current->palette[i] = color.pixel;
5561 			    color_list_insert(color.pixel);
5562 			}
5563 			else {
5564 			    color_warn();
5565 			    fg_current->palette[i] =
5566 				(i * 100 >= resource.density * 15)
5567 				? resource.fore_Pixel : bg_current->pixel;
5568 			}
5569 		    }
5570 		}
5571 
5572 		if (using_planes && bg_current->pixel != resource.back_Pixel) {
5573 		    bg_current->pixel = resource.back_Pixel;
5574 		    /* 		    XSetWindowBackground(DISP, mane.win, bg_current->pixel); */
5575 #if MOTIF
5576 		    fprintf(stderr, "setting window background!\n");
5577 		    XSetWindowBackground(DISP, XtWindow(globals.widgets.main_window), bg_current->pixel);
5578 		    XtVaSetValues(globals.widgets.main_window, XmNbackground, bg_current->pixel, NULL);
5579 #else
5580 		    XSetWindowBackground(DISP, mane.win, bg_current->pixel);
5581 #endif
5582 		    XClearWindow(DISP, mane.win);
5583 		}
5584 
5585 		fg_current->palette_good = True;
5586 	    }
5587 
5588 	    if (globals.debug & DBG_DVI)
5589 		printf("do_color_change: fg = %ld, bg = %ld, using_planes = %d\n",
5590 		       fg_current->palette[15], bg_current->pixel, using_planes);
5591 
5592 	    if (using_planes) {
5593 		globals.gc.rule = set_or_make_gc(globals.gc.rule, GXor, fg_current->palette[15],
5594 						 bg_current->pixel);
5595 		globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, fg_current->palette[15],
5596 						 bg_current->pixel);
5597 	    }
5598 	    else {
5599 		globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->palette[15],
5600 						 bg_current->pixel);
5601 		globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->palette[15],
5602 						 bg_current->pixel);
5603 	    }
5604 
5605 	    globals.gc.fore2 = NULL;
5606 
5607 	    if (mane.shrinkfactor > 1) {
5608 		if (shrink_allocated_for < mane.shrinkfactor) {
5609 		    if (pixeltbl != NULL)
5610 			free((char *) pixeltbl);
5611 		    pixeltbl = xmalloc((unsigned)(mane.shrinkfactor * mane.shrinkfactor + 1)
5612 				       * sizeof *pixeltbl);
5613 		    shrink_allocated_for = mane.shrinkfactor;
5614 		}
5615 
5616 		for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i) {
5617 		    pixeltbl[i] = fg_current->palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
5618 						      / (2 * mane.shrinkfactor * mane.shrinkfactor)];
5619 		}
5620 	    }
5621 	}
5622     }	/* end if resource.use_grey */
5623     else
5624 #endif /* GREY */
5625     {
5626 	if (!fg_current->pixel_good) {
5627 	    fg_current->pixel = alloc_color(&fg_current->color,
5628 					    color_data[0].pixel);
5629 	    fg_current->pixel_good = True;
5630 	}
5631 
5632 	if (globals.debug & DBG_DVI)
5633 	    printf("do_color_change: fg = %lx, bg = %lx\n",
5634 		   fg_current->pixel, bg_current->pixel);
5635 
5636 	globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->pixel, bg_current->pixel);
5637 
5638 	set_bits = (Pixel) (fg_current->pixel & ~bg_current->pixel);
5639 	clr_bits = (Pixel) (bg_current->pixel & ~fg_current->pixel);
5640 	globals.gc.fore2 = NULL;
5641 
5642 	if (resource.copy
5643 	    || (set_bits && clr_bits && !resource.thorough)) {
5644 	    if (!resource.copy) {
5645 		/* I used to get a warning here which I didn't get for
5646 		   xdvi-22.64/events.c, l.1330, but I can't reproduce
5647 		   it any more ...
5648 		*/
5649 		warn_overstrike();
5650 	    }
5651 	    globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->pixel, bg_current->pixel);
5652 	}
5653 	else {
5654 	    if (set_bits) {
5655 		globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, set_bits, 0);
5656 		if (clr_bits) {
5657 		    globals.gc.fore2 = globals.gc.fore2_bak1 = set_or_make_gc(globals.gc.fore2_bak1, GXandInverted, clr_bits, 0);
5658 		}
5659 	    }
5660 	    else
5661 		globals.gc.fore = set_or_make_gc(globals.gc.fore, GXandInverted, clr_bits, 0);
5662 	}
5663     }
5664 
5665     fg_active = fg_current;
5666 }
5667 
5668 #elif GREY /* if COLOR */
5669 
5670 void
init_pix(void)5671 init_pix(void)
5672 {
5673     static int shrink_allocated_for = 0;
5674     static float oldgamma = 0.0;
5675     static Pixel palette[17];
5676     int i;
5677 
5678     if (G_visual->class == TrueColor) {
5679 	/* This mirrors the non-grey code in xdvi.c */
5680 	static int shift1_r, shift1_g, shift1_b;
5681 	static int shift2_r, shift2_g, shift2_b;
5682 	static Pixel set_bits;
5683 	static Pixel clr_bits;
5684 	unsigned int sf_squared;
5685 
5686 	if (oldgamma == 0.0) {
5687 	    mask_shifts(G_visual->red_mask, &shift1_r, &shift2_r);
5688 	    mask_shifts(G_visual->green_mask, &shift1_g, &shift2_g);
5689 	    mask_shifts(G_visual->blue_mask, &shift1_b, &shift2_b);
5690 
5691 	    set_bits = color_data[0].pixel & ~(color_data[1].pixel);
5692 	    clr_bits = color_data[1].pixel & ~(color_data[0].pixel);
5693 
5694 	    if (set_bits & G_visual->red_mask)
5695 		set_bits |= G_visual->red_mask;
5696 	    if (clr_bits & G_visual->red_mask)
5697 		clr_bits |= G_visual->red_mask;
5698 	    if (set_bits & G_visual->green_mask)
5699 		set_bits |= G_visual->green_mask;
5700 	    if (clr_bits & G_visual->green_mask)
5701 		clr_bits |= G_visual->green_mask;
5702 	    if (set_bits & G_visual->blue_mask)
5703 		set_bits |= G_visual->blue_mask;
5704 	    if (clr_bits & G_visual->blue_mask)
5705 		clr_bits |= G_visual->blue_mask;
5706 
5707 	    /*
5708 	     * Make the GCs
5709 	     */
5710 
5711 	    globals.gc.fore = globals.gc.fore2 = globals.gc.rule = 0;
5712 	    globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel);
5713 	    if (globals.gc.do_copy || (set_bits && clr_bits)) {
5714 		globals.gc.rule = globals.gc.copy;
5715 		if (!resource.thorough)
5716 		    globals.gc.do_copy = True;
5717 	    }
5718 	    if (globals.gc.do_copy) {
5719 		globals.gc.fore = globals.gc.rule;
5720 		if (!resource.copy) {
5721 		    warn_overstrike();
5722 		}
5723 	    }
5724 	    else {
5725 		if (set_bits) {
5726 		    globals.gc.fore = set_or_make_gc(NULL, GXor, set_bits & color_data[0].pixel, 0);
5727 		}
5728 		if (clr_bits || !set_bits) {
5729 		    /* 		    fprintf(stderr, "using GXandInverted!\n"); */
5730 		    *(globals.gc.fore ? &globals.gc.fore2 : &globals.gc.fore) =
5731 			set_or_make_gc(NULL, GXandInverted, clr_bits & ~(color_data[0].pixel), 0);
5732 		}
5733 		if (!globals.gc.rule)
5734 		    globals.gc.rule = globals.gc.fore;
5735 	    }
5736 
5737 	    oldgamma = resource.gamma;
5738 	}
5739 
5740 	if (mane.shrinkfactor == 1)
5741 	    return;
5742 	sf_squared = mane.shrinkfactor * mane.shrinkfactor;
5743 
5744 	if (shrink_allocated_for < mane.shrinkfactor) {
5745 	    if (pixeltbl != NULL) {
5746 		free((char *)pixeltbl);
5747 		if (pixeltbl_gc2 != NULL)
5748 		    free((char *)pixeltbl_gc2);
5749 	    }
5750 	    pixeltbl = xmalloc((sf_squared + 1) * sizeof *pixeltbl);
5751 	    shrink_allocated_for = mane.shrinkfactor;
5752 	    if (globals.gc.fore2 != NULL) {
5753 		pixeltbl_gc2 = xmalloc((sf_squared + 1) * sizeof *pixeltbl_gc2);
5754 	    }
5755 	}
5756 
5757 	/*
5758 	 * Initialize the pixel lookup table according to the gamma values.
5759 	 */
5760 #define	SHIFTIFY(x, shift1, shift2)	((((Pixel)(x)) >> (shift1)) << (shift2))
5761 
5762 	for (i = 0; i <= sf_squared; ++i) {
5763 	    double frac = resource.gamma > 0
5764 		? pow((double)i / sf_squared, 1 / resource.gamma)
5765 		: 1 - pow((double)(sf_squared - i) / sf_squared, -resource.gamma);
5766 	    unsigned int red, green, blue;
5767 	    Pixel pixel;
5768 
5769 	    red = frac * ((double)color_data[0].red - color_data[1].red)
5770 		+ color_data[1].red;
5771 	    green = frac
5772 		* ((double)color_data[0].green - color_data[1].green)
5773 		+ color_data[1].green;
5774 	    blue = frac * ((double)color_data[0].blue - color_data[1].blue)
5775 		+ color_data[1].blue;
5776 
5777 	    pixel = SHIFTIFY(red, shift1_r, shift2_r) |
5778 		SHIFTIFY(green, shift1_g, shift2_g) |
5779 		SHIFTIFY(blue, shift1_b, shift2_b);
5780 
5781 	    if (globals.gc.do_copy) {
5782 		pixeltbl[i] = pixel;
5783 	    }
5784 	    else if (globals.gc.fore2 != NULL) {	/* if thorough */
5785 		pixeltbl[i] = pixel & ~(color_data[1].pixel);
5786 		pixeltbl_gc2[i] = ~pixel & color_data[1].pixel;
5787 	    }
5788 	    else {
5789 		pixeltbl[i] = set_bits ? pixel & set_bits : ~pixel & clr_bits;
5790 	    }
5791 	}
5792 
5793 #undef	SHIFTIFY
5794 
5795 	return;
5796     }
5797 
5798     /* if not TrueColor ... */
5799 
5800     if (resource.gamma != oldgamma) {
5801 	XColor color;
5802 
5803 	for (i = 0; i < 16; ++i) {
5804 	    double frac = resource.gamma > 0
5805 		? pow((double)i / 15, 1 / resource.gamma)
5806 		: 1 - pow((double)(15 - i) / 15, -resource.gamma);
5807 
5808 	    color.red = frac
5809 		* ((double)color_data[0].red - color_data[1].red)
5810 		+ color_data[1].red;
5811 	    color.green = frac
5812 		* ((double)color_data[0].green - color_data[1].green)
5813 		+ color_data[1].green;
5814 	    color.blue = frac
5815 		* ((double)color_data[0].blue - color_data[1].blue)
5816 		+ color_data[1].blue;
5817 
5818 	    color.pixel = resource.back_Pixel;
5819 	    color.flags = DoRed | DoGreen | DoBlue;
5820 
5821 	    if (!globals.gc.do_copy) {
5822 		if (i & 1)
5823 		    color.pixel |= plane_masks[0];
5824 		if (i & 2)
5825 		    color.pixel |= plane_masks[1];
5826 		if (i & 4)
5827 		    color.pixel |= plane_masks[2];
5828 		if (i & 8)
5829 		    color.pixel |= plane_masks[3];
5830 		XStoreColor(DISP, G_colormap, &color);
5831 		palette[i] = color.pixel;
5832 	    }
5833 	    else {
5834 		if (XAllocColor(DISP, G_colormap, &color))
5835 		    palette[i] = color.pixel;
5836 		else
5837 		    palette[i] = (i * 100 >= resource.density * 15)
5838 			? resource.fore_Pixel : resource.back_Pixel;
5839 	    }
5840 	}
5841 
5842 	globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel);
5843 	globals.gc.rule = globals.gc.do_copy
5844 	    ? globals.gc.copy
5845 	    : set_or_make_gc(NULL, GXor, resource.fore_Pixel, resource.back_Pixel);
5846 	globals.gc.fore = globals.gc.rule;
5847 	globals.gc.fore2 = NULL;
5848 	oldgamma = resource.gamma;
5849     }
5850 
5851     if (mane.shrinkfactor == 1)
5852 	return;
5853 
5854     if (shrink_allocated_for < mane.shrinkfactor) {
5855 	if (pixeltbl != NULL)
5856 	    free((char *)pixeltbl);
5857 	pixeltbl = xmalloc((unsigned)
5858 			   (mane.shrinkfactor * mane.shrinkfactor + 1) * sizeof *pixeltbl);
5859 	shrink_allocated_for = mane.shrinkfactor;
5860     }
5861 
5862     for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i) {
5863 	pixeltbl[i] = palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
5864 			      / (2 * mane.shrinkfactor * mane.shrinkfactor)];
5865     }
5866 }
5867 
5868 #endif /* COLOR */
5869