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