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