1: /* 2: * DVI previewer for X. 3: * 4: * Eric Cooper, CMU, September 1985. 5: * 6: * Code derived from dvi-imagen.c. 7: * 8: * Modified for X.10 by Bob Scheifler, MIT LCS, January 1986. 9: * 10: */ 11: #ifndef lint 12: static char *dv_c = "$Header: dv.c,v 10.5 86/02/01 15:44:22 tony Rel $"; 13: #endif lint 14: 15: #include <sys/types.h> 16: #include <X/Xlib.h> 17: #include <stdio.h> 18: #include <ctype.h> 19: #include "dvi.h" 20: #include "pxl.h" 21: 22: /* These are probably site dependent */ 23: #define FONT_DIRECTORY "/usr/lib/tex/fonts" 24: #define FONT_SUFFIX ".%dpxl" 25: 26: #define PAPER_WIDTH ROUNDUP(17*pixels_per_inch,shrink_factor*2) 27: #define PAPER_HEIGHT ROUNDUP(11*pixels_per_inch,shrink_factor) 28: #define X_PAGE_OFFSET ROUNDUP(pixels_per_inch,shrink_factor) 29: #define Y_PAGE_OFFSET ROUNDUP(pixels_per_inch,shrink_factor) 30: 31: #define pixel_round(x) ((long) (conv * (double) (x) + 0.5)) 32: #define dvi_round(x) ((long) ((double) (x) / conv + 0.5)) 33: 34: #define one(fp) num (fp, 1) 35: #define two(fp) num (fp, 2) 36: #define stwo(fp) snum(fp, 2) 37: #define four(fp) num (fp, 4) 38: #define sfour(fp) snum(fp, 4) 39: 40: typedef unsigned char ubyte; 41: 42: struct frame { 43: long pxl_h, dvi_h, pxl_v, dvi_v, w, x, y, z; 44: }; 45: 46: struct frame *stack; 47: int stackp; 48: 49: #define PXL_H stack[stackp].pxl_h 50: #define PXL_V stack[stackp].pxl_v 51: #define DVI_H stack[stackp].dvi_h 52: #define DVI_V stack[stackp].dvi_v 53: #define WW stack[stackp].w 54: #define XX stack[stackp].x 55: #define YY stack[stackp].y 56: #define ZZ stack[stackp].z 57: 58: #define DBG_BITMAP 0x1 59: #define DBG_DVI 0x2 60: #define DBG_ALL (DBG_BITMAP|DBG_DVI) 61: 62: /* 63: * Command line flags. 64: */ 65: int debug = 0; 66: int list_fonts = 0; 67: 68: int pixels_per_inch = 300; 69: int shrink_factor = 4; 70: 71: FILE *dvi_file; /* user's file */ 72: 73: int font_not_found = 0; 74: struct font *current_font = NULL; /* ptr into circular list of fonts */ 75: #define MAX_OPEN_FONTS 12 76: int n_open_fonts = 0; /* for LRU management of fonts */ 77: 78: /* 79: * DVI preamble and postamble information. 80: */ 81: char job_id[300]; 82: int total_pages, maxstack; 83: int current_page; 84: double fraction, conv; 85: long numerator, denominator, magnification; 86: 87: /* 88: * Offset in DVI file of last page, set in read_postamble(). 89: */ 90: long last_page_offset; 91: 92: /* 93: * Table of page offsets in DVI file, indexed by page number - 1. 94: * Initialized in prepare_pages(). 95: */ 96: long *page_offset; 97: 98: #define xdvi_width 15 99: #define xdvi_height 15 100: #define xdvi_x_hot 7 101: #define xdvi_y_hot 7 102: static short xdvi_bits[] = { 103: 0x0080, 0x01c0, 0x03e0, 0x06b0, 104: 0x0c98, 0x188c, 0x3086, 0x7fff, 105: 0x3086, 0x188c, 0x0c98, 0x06b0, 106: 0x03e0, 0x01c0, 0x0080}; 107: 108: Window win; 109: int forepix, backpix, highpix; 110: 111: long screen_w, screen_h, page_w, page_h; 112: long min_x, max_x, min_y, max_y, base_x, base_y; 113: long smin_x, smax_x, smin_y, smax_y; 114: int redisplay = 0; 115: 116: unsigned long num(); 117: long snum(); 118: 119: extern char reverse_byte[]; 120: char *malloc(), *calloc(), *index(); 121: 122: main(argc, argv) 123: int argc; 124: char **argv; 125: { 126: char *prog, *file; 127: char *display = NULL; 128: char *option; 129: OpaqueFrame frame; 130: int reverse = 0; 131: int bwidth = 2; 132: char *fore_color; 133: char *back_color; 134: char *high_color; 135: char *brdr_color; 136: char *mous_color; 137: char *geometry = NULL, def[32]; 138: int backmap, bdrmap, mouspix; 139: Color cdef; 140: 141: prog = *argv++; 142: argc--; 143: if ((option = XGetDefault(prog, "ReverseVideo")) && 144: strcmp(option, "on") == 0) 145: reverse = 1; 146: if (option = XGetDefault(prog, "BorderWidth")) 147: bwidth = atoi(option); 148: fore_color = XGetDefault(prog, "ForeGround"); 149: back_color = XGetDefault(prog, "BackGround"); 150: high_color = XGetDefault(prog, "Highlight"); 151: brdr_color = XGetDefault(prog, "Border"); 152: mous_color = XGetDefault(prog, "Mouse"); 153: file = NULL; 154: while (argc) { 155: if (strncmp(*argv, "-d", 2) == 0) 156: debug = isdigit(argv[0][2]) ? atoi(&argv[0][2]) : DBG_ALL; 157: else if (strcmp(*argv, "-l") == 0) 158: list_fonts = 1; 159: else if (strcmp(*argv, "-s") == 0 && argc > 1) { 160: argv++; 161: argc--; 162: shrink_factor = atoi(*argv); 163: if (shrink_factor <= 0) goto usage; 164: } else if (strcmp(*argv, "-p") == 0 && argc > 1) { 165: argv++; 166: argc--; 167: pixels_per_inch = atoi(*argv); 168: if (pixels_per_inch <= 0) goto usage; 169: } else if (strcmp(*argv, "-rv") == 0) { 170: reverse = 1; 171: } else if (strcmp(*argv, "-fg") == 0 && argc > 1) { 172: argv++; 173: argc--; 174: fore_color = *argv; 175: } else if (strcmp(*argv, "-bg") == 0 && argc > 1) { 176: argv++; 177: argc--; 178: back_color = *argv; 179: } else if (strcmp(*argv, "-hl") == 0 && argc > 1) { 180: argv++; 181: argc--; 182: high_color = *argv; 183: } else if (strcmp(*argv, "-bd") == 0 && argc > 1) { 184: argv++; 185: argc--; 186: brdr_color = *argv; 187: } else if (strcmp(*argv, "-ms") == 0 && argc > 1) { 188: argv++; 189: argc--; 190: mous_color = *argv; 191: } else if (**argv == '=') { 192: geometry = *argv; 193: } else if (**argv != '-') { 194: if (index(*argv, ':') != NULL) 195: display = *argv; 196: else 197: file = *argv; 198: } else { 199: usage: 200: fprintf(stderr, "Usage: xdvi [-s <shrink>] [-p <pixels>] [-l] [-rv] [-fg <color>] [-bg <color>] [-hl <color>] [-bd <color>] [-ms <color>] [=<geometry>] [host:display] dvi_file\n"); 201: exit(1); 202: } 203: argv++; 204: argc--; 205: } 206: if (file == NULL) 207: goto usage; 208: if ((dvi_file = fopen(file, "r")) == NULL) { 209: int n = strlen(file); 210: char *dvi_name; 211: 212: if (strcmp(file + n - sizeof(".dvi") + 1, ".dvi") == 0) { 213: perror(file); 214: exit(1); 215: } 216: dvi_name = malloc((unsigned) n + sizeof(".dvi")); 217: sprintf(dvi_name, "%s.dvi", file); 218: if ((dvi_file = fopen(dvi_name, "r")) == NULL) { 219: perror(dvi_name); 220: exit(1); 221: } 222: } 223: process_preamble(); 224: find_postamble(); 225: read_postamble(); 226: prepare_pages(); 227: init_page(); 228: if (XOpenDisplay(display) == NULL) { 229: fprintf(stderr, "Can't open display %s!\n", display); 230: exit(1); 231: } 232: if (reverse) { 233: forepix = WhitePixel; 234: highpix = WhitePixel; 235: backpix = BlackPixel; 236: backmap = BlackPixmap; 237: bdrmap = WhitePixmap; 238: mouspix = WhitePixel; 239: } else { 240: forepix = BlackPixel; 241: highpix = BlackPixel; 242: backpix = WhitePixel; 243: backmap = WhitePixmap; 244: bdrmap = BlackPixmap; 245: mouspix = BlackPixel; 246: } 247: if (DisplayCells() > 2) { 248: if (fore_color && XParseColor(fore_color, &cdef) && 249: XGetHardwareColor(&cdef)) 250: forepix = cdef.pixel; 251: if (back_color && XParseColor(back_color, &cdef) && 252: XGetHardwareColor(&cdef)) { 253: backpix = cdef.pixel; 254: backmap = XMakeTile(backpix); 255: } 256: if (high_color && XParseColor(high_color, &cdef) && 257: XGetHardwareColor(&cdef)) 258: highpix = cdef.pixel; 259: if (brdr_color && XParseColor(brdr_color, &cdef) && 260: XGetHardwareColor(&cdef)) 261: bdrmap = XMakeTile(cdef.pixel); 262: if (mous_color && XParseColor(mous_color, &cdef) && 263: XGetHardwareColor(&cdef)) 264: mouspix = cdef.pixel; 265: } 266: frame.bdrwidth = bwidth; 267: frame.height = page_h; 268: if (frame.height + (bwidth << 1) > DisplayHeight()) 269: frame.height = DisplayHeight() - (bwidth << 1); 270: frame.width = page_w; 271: if (frame.width + (bwidth << 1) > DisplayWidth()) 272: frame.width = DisplayWidth() - (bwidth << 1); 273: frame.border = bdrmap; 274: frame.background = backmap; 275: frame.x = 0; 276: frame.y = 0; 277: sprintf(def, "=%dx%d+0+0", frame.width, frame.height); 278: win = XCreate("DVI Previewer", prog, geometry, def, &frame, 50, 50); 279: screen_h = frame.height; 280: screen_w = frame.width; 281: XMapWindow(win); 282: XSelectInput(win, KeyPressed|ButtonPressed|ExposeWindow|ExposeRegion); 283: XDefineCursor(win, 284: XCreateCursor(xdvi_width, xdvi_height, xdvi_bits, xdvi_bits, 285: xdvi_x_hot, xdvi_y_hot, mouspix, backpix, GXcopy)); 286: do_pages(); 287: stop_output(0); 288: } 289: 290: /* 291: ** process_preamble reads the information in the preamble and stores 292: ** it into global variables for later use. 293: */ 294: process_preamble() 295: { 296: ubyte k; 297: 298: if (one(dvi_file) != PRE) 299: error("xdvi: DVI file doesn't start with preamble"); 300: if (one(dvi_file) != 2) 301: error("xdvi: Wrong version of DVI output for this program"); 302: numerator = four(dvi_file); 303: denominator = four(dvi_file); 304: magnification = four(dvi_file); 305: fraction = (((double) numerator * magnification) 306: / ((double) denominator * 1000.)); 307: define_conv(); 308: k = one(dvi_file); 309: fread(job_id, sizeof(char), k, dvi_file); 310: job_id[k] = '\0'; 311: } 312: 313: define_conv () 314: { 315: conv = ((fraction * pixels_per_inch) / 100000) / (2.54 * shrink_factor); 316: } 317: 318: /* 319: ** find_postamble locates the beginning of the postamble 320: ** and leaves the file ready to start reading at that location. 321: */ 322: find_postamble() 323: { 324: ubyte byte; 325: long offset = -4; /* At least 4 TRAILERS */ 326: 327: do { 328: offset -= 1; 329: fseek(dvi_file, offset, 2); 330: byte = one(dvi_file); 331: } while (byte == TRAILER); 332: if (byte != 2) 333: error("xdvi: Wrong version of DVI output for this program"); 334: offset -= 4; 335: fseek(dvi_file, offset, 2); 336: fseek(dvi_file, sfour(dvi_file), 0); 337: } 338: 339: /* 340: ** read_postamble reads the information in the postamble, 341: ** storing it into global variables. 342: ** It also takes care of reading in all of the PXL files for the fonts 343: ** used in the job. 344: */ 345: read_postamble() 346: { 347: ubyte cmnd; 348: int page_width, page_height; 349: 350: if (one(dvi_file) != POST) 351: error("xdvi: Postamble doesn't begin with POST"); 352: last_page_offset = four(dvi_file); 353: if (numerator != four(dvi_file) 354: || denominator != four(dvi_file) 355: || magnification != four(dvi_file)) 356: error("xdvi: Postamble doesn't match preamble"); 357: page_height = pixel_round(four(dvi_file)); 358: page_width = pixel_round(four(dvi_file)); 359: maxstack = two(dvi_file); 360: total_pages = two(dvi_file); 361: do { 362: switch(cmnd = one(dvi_file)) { 363: case FNTDEF1: 364: case FNTDEF2: 365: case FNTDEF3: 366: case FNTDEF4: 367: define_font(cmnd); 368: break; 369: case POSTPOST: 370: break; 371: default: 372: error("xdvi: Non-fntdef cmnd found in postamble"); 373: } 374: } while (cmnd != POSTPOST); 375: if (font_not_found) 376: error("xdvi: Not all PXL files were found"); 377: list_fonts = 0; 378: } 379: 380: prepare_pages() 381: { 382: int i; 383: 384: stack = (struct frame *) malloc((unsigned) sizeof(struct frame) * (maxstack+1)); 385: if (stack == NULL) 386: error("xdvi: Can't allocate stack space (%d frames)", maxstack); 387: page_offset = (long *) malloc((unsigned) total_pages * sizeof(long)); 388: if (page_offset == NULL) 389: error("xdvi: Can't allocate page directory (%d pages)", total_pages); 390: i = total_pages; 391: page_offset[--i] = last_page_offset; 392: fseek(dvi_file, last_page_offset, 0); 393: /* 394: * Follow back pointers through pages in the DVI file, 395: * storing the offsets in the page_offset table. 396: */ 397: while (i > 0) { 398: num(dvi_file, 1+4+(9*4)); 399: fseek(dvi_file, page_offset[--i] = four(dvi_file), 0); 400: } 401: } 402: 403: /* 404: ** define_font reads the rest of the fntdef command and then reads in 405: ** the specified PXL file, adding it to the global linked-list holding 406: ** all of the fonts used in the job. 407: */ 408: define_font(cmnd) 409: ubyte cmnd; 410: { 411: register struct font *fontp; 412: int len; 413: int unmodsize; 414: float realsize; 415: int size; 416: long checksum; 417: 418: fontp = (struct font *) malloc((unsigned) sizeof(struct font)); 419: if (fontp == NULL) 420: error("xdvi: Can't allocate memory for font"); 421: fontp->TeXnumber = num(dvi_file, cmnd - FNTDEF1 + 1); 422: checksum = four(dvi_file); 423: fontp->scale = four(dvi_file); 424: fontp->design = four(dvi_file); 425: len = one(dvi_file) + one(dvi_file); 426: fontp->fontname = malloc(len + 10); /* leave space for magnification */ 427: fread(fontp->fontname, sizeof(char), len, dvi_file); 428: fontp->fontname[len] = '\0'; 429: fontp->file = NULL; 430: /* 431: ** In the actual implementation, scaled-size/design-size hasn't been 432: ** stored with sufficient precision, hence the messing around to find 433: ** its actual value. 434: */ 435: realsize = (magnification/1000.)*((float) fontp->scale / fontp->design); 436: unmodsize = (realsize * 1000) + 0.5; 437: /* a real hack to correct for rounding in some cases */ 438: switch (unmodsize) { 439: case 1095: 440: realsize = 1.095445; /* stephalf */ 441: break; 442: case 1315: 443: realsize = 1.314534; /* stepihalf */ 444: break; 445: case 2074: 446: realsize = 2.0736; /* stepiv */ 447: break; 448: case 2488: 449: realsize = 2.48832; /* stepv */ 450: break; 451: case 2986: 452: realsize = 2.985984; /* stepiv */ 453: break; 454: } 455: /* 456: * the remaining magnification steps are represented 457: * with sufficient accuracy already 458: */ 459: size = (realsize * pixels_per_inch * 5) + 0.5; 460: sprintf(&fontp->fontname[len], FONT_SUFFIX, size); 461: if (!open_pxl_file(fontp)) 462: return; 463: read_glyphs(fontp); 464: if (current_font == NULL) { 465: fontp->next = fontp; 466: fontp->prev = fontp; 467: } else { 468: fontp->next = current_font; 469: fontp->prev = current_font->prev; 470: current_font->prev->next = fontp; 471: current_font->prev = fontp; 472: } 473: current_font = fontp; 474: } 475: 476: open_pxl_file(font) 477: struct font *font; 478: { 479: char filename[300]; 480: extern int errno; 481: 482: if (font->file == NULL) { 483: sprintf(filename, "%s/%s", 484: FONT_DIRECTORY, font->fontname); 485: if (n_open_fonts == MAX_OPEN_FONTS) 486: close_lru(); 487: font->file = fopen(filename, "r"); 488: if (font->file == NULL) { 489: font_not_found = 1; 490: printf("%s [not found]\n", font->fontname); 491: return (0); 492: } 493: n_open_fonts += 1; 494: } 495: if (list_fonts) 496: printf("%s\n", font->fontname); 497: return (1); 498: } 499: 500: read_pxl_bitmap(ch, g) 501: ubyte ch; 502: register struct glyph *g; 503: { 504: register struct bitmap *bitmap; 505: register int file_bytes_wide; 506: register char *ptr; 507: register int i, j; 508: 509: bitmap = &g->bitmap; 510: 511: /* in file, bitmap rows are multiples of 32 bits wide */ 512: file_bytes_wide = ROUNDUP(bitmap->w, BITS_PER_LONG)*BYTES_PER_LONG; 513: /* width must be multiple of 16 bits for raster_op */ 514: bitmap->bytes_wide = ROUNDUP(bitmap->w, BITS_PER_SHORT)*BYTES_PER_SHORT; 515: ptr = bitmap->bits = malloc((unsigned) bitmap->h * bitmap->bytes_wide); 516: if (ptr == NULL) 517: error("xdvi: Can't allocate bitmap for character %d of font %s (%d by %d)", 518: ch, current_font->fontname, bitmap->h, bitmap->w); 519: if (!open_pxl_file(current_font)) 520: error("xdvi: Can't find font file %s", current_font->fontname); 521: fseek(current_font->file, g->addr, 0); 522: for (i = 0; i < bitmap->h; i += 1) 523: for (j = 0; j < file_bytes_wide; j += 1) 524: if (j < bitmap->bytes_wide) 525: *ptr++ = reverse_byte[one(current_font->file)]; 526: else 527: one(current_font->file); 528: if (shrink_factor != 1) 529: shrink_bitmap(bitmap, shrink_factor, shrink_factor); 530: if (debug & DBG_BITMAP) 531: print_char(ch, g); 532: } 533: 534: /* 535: * Find font #n and move it to the head of the list. 536: */ 537: change_font(n) 538: unsigned long n; 539: { 540: register struct font *fontp; 541: 542: fontp = current_font; 543: for (;;) { 544: if (fontp->TeXnumber == n) 545: break; 546: fontp = fontp->next; 547: if (fontp == current_font) 548: error("xdvi: Non-existent font #%d", n); 549: } 550: if (current_font == fontp) 551: return; 552: fontp->prev->next = fontp->next; 553: fontp->next->prev = fontp->prev; 554: fontp->next = current_font; 555: fontp->prev = current_font->prev; 556: current_font->prev->next = fontp; 557: current_font->prev = fontp; 558: current_font = fontp; 559: } 560: 561: /* 562: * Close the PXL file for the least recently used font. 563: */ 564: close_lru() 565: { 566: register struct font *f; 567: 568: f = current_font->prev; 569: for (;;) { 570: if (f->file != NULL) 571: break; 572: f = f->prev; 573: if (f == current_font->prev) 574: error("xdvi: Can't find an open PXL file to close"); 575: } 576: fclose(f->file); 577: f->file = NULL; 578: n_open_fonts -= 1; 579: } 580: 581: reset_fonts() 582: { 583: register struct font *f; 584: register struct glyph *g; 585: 586: f = current_font; 587: for (;;) { 588: open_pxl_file(f); 589: for (g = &f->glyph[0]; g < &f->glyph[MAXCHARS]; g += 1) { 590: if (g->bitmap.bits) free(g->bitmap.bits); 591: } 592: read_glyphs(f); 593: f = f->next; 594: if (f == current_font) break; 595: } 596: } 597: 598: read_glyphs (fontp) 599: register struct font *fontp; 600: { 601: register struct glyph *g; 602: long checksum, magnify, design_size, font_dir_ptr, pxl_id_word; 603: 604: /* seek to trailer info */ 605: fseek(fontp->file, (long) -(5 * BYTES_PER_LONG), 2); 606: checksum = four(fontp->file); 607: magnify = four(fontp->file); 608: design_size = four(fontp->file); 609: font_dir_ptr = sfour(fontp->file) * 4; 610: pxl_id_word = four(fontp->file); 611: #ifdef lint 612: magnify = design_size = pxl_id_word = magnify; 613: #endif 614: /* seek to font directory */ 615: fseek(fontp->file, font_dir_ptr, 0); 616: for (g = &fontp->glyph[0]; g < &fontp->glyph[MAXCHARS]; g += 1) { 617: g->bitmap.bits = NULL; 618: g->bitmap.w = two(fontp->file); /* leave this for shrink_bitmap */ 619: g->bitmap.h = two(fontp->file); /* leave this for shrink_bitmap */ 620: g->x = stwo(fontp->file) / shrink_factor; 621: g->y = stwo(fontp->file) / shrink_factor; 622: g->addr = four(fontp->file) * 4; 623: /* 624: ** The TFM-width word is kind of funny in the units 625: ** it is expressed in. It works this way: 626: ** 627: ** If a glyph has width 'w' in a font with design-size 628: ** 'd' (both in same units), the TFM-width word is 629: ** 630: ** (w/d) * 2^20 631: ** 632: ** Therefore, in order to find the glyph width in 633: ** DVI units (1 / 2^16 points), we take the design-size 634: ** 'd' (in DVI's), the magnification 'm' of the PXL file 635: ** and the TFM-width word 't' to the width (in DVI's) 636: ** as follows: 637: ** 638: ** dmt 639: ** w = ----- 640: ** 2^20 641: ** 642: ** But the magnification of the PXL file is just the 643: ** scaled size 's' over the design size, so the final 644: ** expression for the width is 645: ** 646: ** st 647: ** w = ---- 648: ** 2^20 649: ** 650: */ 651: g->dvi_adv = 652: ((double) fontp->scale * four(fontp->file)) / (1 << 20); 653: g->pxl_adv = pixel_round(g->dvi_adv); 654: } 655: } 656: 657: #define nope(str) error("xdvi: %s not implemented", str) 658: #define correct() (PXL_H = pixel_round(DVI_H)) 659: 660: do_pages() 661: { 662: ubyte ch; 663: 664: min_x = 0; 665: min_y = 0; 666: max_x = screen_w; 667: max_y = screen_h; 668: base_x = min_x; 669: base_y = min_y; 670: current_page = 0; 671: for (;;) { 672: ch = one(dvi_file); 673: if (debug & DBG_DVI) 674: print_dvi(ch); 675: if (ch <= SETCHAR0 + 127) { 676: set_char(ch); 677: DVI_H += current_font->glyph[ch].dvi_adv; 678: PXL_H += current_font->glyph[ch].pxl_adv; 679: correct(); 680: } else if (FNTNUM0 <= ch && ch <= FNTNUM0 + 63) { 681: change_font((unsigned long) (ch - FNTNUM0)); 682: } else { 683: long a, b; 684: 685: switch (ch) { 686: case SET1: 687: nope("SET1"); 688: break; 689: 690: case SETRULE: 691: a = sfour(dvi_file); b = sfour(dvi_file); 692: if (a > 0 && b > 0) { 693: correct(); 694: set_rule(pixel_round(a), pixel_round(b)); 695: } 696: DVI_H += b; 697: PXL_H = pixel_round(DVI_H); 698: break; 699: 700: case PUT1: 701: nope("PUT1"); 702: break; 703: 704: case PUTRULE: 705: a = sfour(dvi_file); b = sfour(dvi_file); 706: if (a > 0 && b > 0) { 707: correct(); 708: set_rule(pixel_round(a), pixel_round(b)); 709: } 710: break; 711: 712: case NOP: 713: break; 714: 715: case BOP: 716: num(dvi_file, 11*4); 717: stackp = 0; 718: DVI_H = dvi_round(X_PAGE_OFFSET); 719: PXL_H = X_PAGE_OFFSET; 720: DVI_V = dvi_round(Y_PAGE_OFFSET); 721: PXL_V = Y_PAGE_OFFSET; 722: WW = XX = YY = ZZ = 0; 723: begin_page(); 724: break; 725: 726: case EOP: 727: if (stackp > 0) 728: error("Stack not empty at EOP (%d)", 729: stackp); 730: end_page(); 731: if (ftell(dvi_file) > last_page_offset) 732: return; 733: break; 734: 735: case PUSH: 736: stackp++; 737: if (stackp > maxstack) 738: error("xdvi: More PUSHes than were promised"); 739: stack[stackp] = stack[stackp - 1]; 740: break; 741: 742: case POP: 743: stackp--; 744: if (stackp < 0) 745: error("xdvi: More POPs than PUSHes"); 746: break; 747: 748: case RIGHT1: 749: case RIGHT2: 750: case RIGHT3: 751: case RIGHT4: 752: DVI_H += snum(dvi_file, ch - RIGHT1 + 1); 753: PXL_H = pixel_round(DVI_H); 754: break; 755: 756: case X0: 757: case X1: 758: case X2: 759: case X3: 760: case X4: 761: if (ch != X0) 762: XX = snum(dvi_file, ch - X0); 763: DVI_H += XX; 764: PXL_H += pixel_round(XX); 765: correct(); 766: break; 767: 768: case W0: 769: case W1: 770: case W2: 771: case W3: 772: case W4: 773: if (ch != W0) 774: WW = snum(dvi_file, ch - W0); 775: DVI_H += WW; 776: PXL_H = pixel_round(DVI_H); 777: break; 778: 779: case Y0: 780: case Y1: 781: case Y2: 782: case Y3: 783: case Y4: 784: if (ch != Y0) 785: YY = snum(dvi_file, ch - Y0); 786: DVI_V += YY; 787: PXL_V = pixel_round(DVI_V); 788: break; 789: 790: case Z0: 791: case Z1: 792: case Z2: 793: case Z3: 794: case Z4: 795: if (ch != Z0) 796: ZZ = snum(dvi_file, ch - Z0); 797: DVI_V += ZZ; 798: PXL_V = pixel_round(DVI_V); 799: break; 800: 801: case DOWN1: 802: case DOWN2: 803: case DOWN3: 804: case DOWN4: 805: DVI_V += snum(dvi_file, ch - DOWN1 + 1); 806: PXL_V = pixel_round(DVI_V); 807: break; 808: 809: case FNT1: 810: case FNT2: 811: case FNT3: 812: case FNT4: 813: change_font(num(dvi_file, ch - FNT1 + 1)); 814: break; 815: 816: case XXX1: 817: case XXX2: 818: case XXX3: 819: case XXX4: 820: a = num(dvi_file, ch - XXX1 + 1); 821: if(a > 0) 822: special((unsigned long) a); 823: break; 824: 825: case FNTDEF1: 826: case FNTDEF2: 827: case FNTDEF3: 828: case FNTDEF4: 829: fseek(dvi_file, (long) (12 + ch - FNTDEF1 + 1), 1); 830: a = one(dvi_file) + one(dvi_file); 831: fseek(dvi_file, (long) a, 1); 832: break; 833: 834: case PRE: 835: error("xdvi: Shouldn't happen: PRE encountered."); 836: break; 837: 838: case POST: 839: error("xdvi: Shouldn't happen: POST encountered."); 840: break; 841: 842: case POSTPOST: 843: error("xdvi: Shouldn't happen: POSTPOST encountered."); 844: break; 845: 846: default: 847: error("xdvi: Unknown op-code %d, offset %d", 848: ch, ftell(dvi_file)); 849: } /* end switch*/ 850: } /* end else (ch not a SETCHAR or FNTNUM) */ 851: } /* end for */ 852: } 853: 854: set_char(ch) 855: ubyte ch; 856: { 857: register struct glyph *g; 858: 859: g = ¤t_font->glyph[ch]; 860: if (g->bitmap.bits == NULL) 861: read_pxl_bitmap(ch, g); 862: put_bitmap(&g->bitmap, (PXL_H - g->x), (PXL_V - g->y), forepix); 863: } 864: 865: set_rule(h, w) 866: long h, w; 867: { 868: /* (w,h) specifies lower left corner of rule box */ 869: put_rectangle(PXL_H, PXL_V - h, w, h, forepix); 870: } 871: 872: begin_page() 873: { 874: if (debug) 875: return; 876: if (!redisplay) 877: clear_page(); 878: put_border(0, 0, page_w, page_h, 1); 879: } 880: 881: end_page() 882: { 883: int ch, arg, sign, number, next_page; 884: XEvent event; 885: char *string; 886: int nbytes; 887: 888: #ifdef lint 889: number = 0; 890: #endif 891: if (debug) { 892: if (++current_page == total_pages) 893: exit(0); 894: return; 895: } 896: if (redisplay) { 897: min_x = smin_x; 898: max_x = smax_x; 899: min_y = smin_y; 900: max_y = smax_y; 901: redisplay = 0; 902: } 903: arg = 0; 904: for (;;) { 905: XNextEvent (&event); 906: switch (event.type) { 907: case ExposeWindow: 908: screen_h = ((XExposeEvent *)(&event))->height; 909: screen_w = ((XExposeEvent *)(&event))->width; 910: max_x = min_x + screen_w; 911: max_y = min_y + screen_h; 912: string = "\f"; 913: nbytes = 1; 914: break; 915: case ExposeRegion: 916: smin_x = min_x; 917: smax_x = max_x; 918: smin_y = min_y; 919: smax_y = max_y; 920: min_x = min_x + ((XExposeEvent *)(&event))->x; 921: min_y = min_y + ((XExposeEvent *)(&event))->y; 922: max_x = min_x + ((XExposeEvent *)(&event))->width; 923: max_y = min_y + ((XExposeEvent *)(&event))->height; 924: redisplay = 1; 925: string = "\f"; 926: nbytes = 1; 927: break; 928: case ButtonPressed: 929: { 930: short detail = ((XButtonPressedEvent *) (&event))->detail; 931: switch (detail & ValueMask) { 932: case LeftButton: 933: if (detail & ShiftMask) 934: string = "l"; 935: else 936: string = "b"; 937: nbytes = 1; 938: break; 939: case MiddleButton: 940: if (detail & ShiftMask) 941: string = "u"; 942: else 943: string = "d"; 944: nbytes = 1; 945: break; 946: case RightButton: 947: if (detail & ShiftMask) 948: string = "r"; 949: else 950: string = "f"; 951: nbytes = 1; 952: break; 953: } 954: } 955: break; 956: case KeyPressed: 957: string = XLookupMapping (&event, &nbytes); 958: break; 959: } 960: if (nbytes == 0) continue; 961: if (nbytes > 1) goto bad; 962: switch (ch = *string) { 963: case 'q': 964: case '\003': /* control-C */ 965: case '\004': /* control-D */ 966: stop_output(0); 967: break; 968: case 'n': 969: case 'f': 970: case ' ': 971: /* scroll forward */ 972: min_x = 0; 973: min_y = 0; 974: max_x = screen_w; 975: max_y = screen_h; 976: next_page = current_page + 1; 977: break; 978: case 'p': 979: case 'b': 980: case '\b': 981: /* scroll backward */ 982: min_x = 0; 983: min_y = 0; 984: max_x = screen_w; 985: max_y = screen_h; 986: next_page = current_page - 1; 987: break; 988: case 'u': 989: if (min_y == 0) goto bad; 990: min_y -= screen_h; 991: if (min_y < 0) 992: min_y = 0; 993: base_y = min_y; 994: max_y = min_y + screen_h; 995: next_page = current_page; 996: break; 997: case 'd': 998: if (min_y >= page_h - screen_h) goto bad; 999: min_y += screen_h; 1000: if (min_y > page_h - screen_h) 1001: min_y = page_h - screen_h; 1002: if (min_y < 0) 1003: min_y = 0; 1004: base_y = min_y; 1005: max_y = min_y + screen_h; 1006: next_page = current_page; 1007: break; 1008: case 'l': 1009: if (min_x == 0) goto bad; 1010: min_x -= screen_w; 1011: if (min_x < 0) 1012: min_x = 0; 1013: base_x = min_x; 1014: max_x = min_x + screen_w; 1015: next_page = current_page; 1016: break; 1017: case 'r': 1018: if (min_x >= page_w - screen_w) goto bad; 1019: min_x += screen_w; 1020: if (min_x > page_w - screen_w) 1021: min_x = page_w - screen_w; 1022: if (min_x < 0) 1023: min_x = 0; 1024: base_x = min_x; 1025: max_x = min_x + screen_w; 1026: next_page = current_page; 1027: break; 1028: case 's': 1029: if (!arg) { 1030: int shrink = shrink_factor; 1031: long fac1, fac2; 1032: shrink_factor = 1; 1033: fac1 = ROUNDUP(PAPER_WIDTH, screen_w); 1034: fac2 = ROUNDUP(PAPER_HEIGHT, screen_h); 1035: if (fac1 < fac2) 1036: number = fac2; 1037: else 1038: number = fac1; 1039: shrink_factor = shrink; 1040: } 1041: if (number <= 0) goto bad; 1042: if (number != shrink_factor) { 1043: shrink_factor = number; 1044: min_x = 0; 1045: min_y = 0; 1046: max_x = screen_w; 1047: max_y = screen_h; 1048: init_page(); 1049: define_conv(); 1050: reset_fonts(); 1051: } 1052: case '\f': 1053: /* redisplay current page */ 1054: next_page = current_page; 1055: break; 1056: case '\r': 1057: case '\n': 1058: /* go to relative page */ 1059: min_x = 0; 1060: min_y = 0; 1061: max_x = screen_w; 1062: max_y = screen_h; 1063: next_page = current_page + (arg ? number : 1); 1064: break; 1065: case 'g': 1066: /* go to absolute page */ 1067: min_x = 0; 1068: min_y = 0; 1069: max_x = screen_w; 1070: max_y = screen_h; 1071: next_page = (arg ? number : total_pages) - 1; 1072: break; 1073: case '0': case '1': case '2': case '3': case '4': 1074: case '5': case '6': case '7': case '8': case '9': 1075: if (! arg) { 1076: arg = 1; 1077: sign = 1; 1078: number = 0; 1079: } 1080: number = 10*number + sign*(ch - '0'); 1081: continue; 1082: case '-': 1083: if (! arg) { 1084: arg = 1; 1085: sign = -1; 1086: number = 0; 1087: continue; 1088: } else 1089: goto bad; 1090: default: 1091: goto bad; 1092: } 1093: if (0 <= next_page && next_page < total_pages) { 1094: current_page = next_page; 1095: fseek(dvi_file, page_offset[current_page], 0); 1096: break; 1097: } 1098: bad: 1099: XFeep(0); 1100: arg = 0; /* throw away numeric argument */ 1101: continue; 1102: } 1103: } 1104: 1105: special(nbytes) 1106: unsigned long nbytes; 1107: { 1108: char *cmd; 1109: int i; 1110: 1111: cmd = malloc((unsigned) nbytes+1); 1112: if (cmd == NULL) 1113: error("xdvi: Can't allocate memory for special (%d bytes)", nbytes); 1114: for (i = 0; i < nbytes; i += 1) 1115: cmd[i] = getc(dvi_file); 1116: cmd[i] = '\0'; 1117: fprintf(stderr, "special ``%s'' not implemented\n", cmd); 1118: free(cmd); 1119: } 1120: 1121: /* 1122: ** 1123: ** Read size bytes from the FILE fp, constructing them into a 1124: ** signed/unsigned integer. 1125: ** 1126: */ 1127: unsigned long 1128: num(fp, size) 1129: register FILE *fp; 1130: register int size; 1131: { 1132: register int i; 1133: register long x; 1134: 1135: x = 0; 1136: for (i = 0; i < size; i += 1) 1137: x = x * 0x100 + (unsigned) getc(fp); 1138: return (x); 1139: } 1140: 1141: long 1142: snum(fp, size) 1143: register FILE *fp; 1144: register int size; 1145: { 1146: register int i; 1147: register long x; 1148: 1149: x = getc(fp) & 0xff; 1150: if (x & 0x80) 1151: x -= 0x100; 1152: for (i = 1; i < size; i += 1) 1153: x = x * 0x100 + (unsigned) getc(fp); 1154: return (x); 1155: } 1156: 1157: stop_output(sig) 1158: { 1159: exit(sig); 1160: } 1161: 1162: /* VARARGS1 */ 1163: error(message, a, b, c, d, e, f) 1164: char *message; 1165: { 1166: fprintf(stderr, message, a, b, c, d, e, f); 1167: putc('\n', stderr); 1168: exit(1); 1169: } 1170: 1171: init_page() 1172: { 1173: page_h = PAPER_HEIGHT; 1174: page_w = PAPER_WIDTH; 1175: } 1176: 1177: clear_page() 1178: { 1179: XClear(win); 1180: } 1181: 1182: put_border(x, y, w, h, t) 1183: long x, y, w, h, t; 1184: { 1185: put_rectangle(x, y, w, t, highpix); 1186: put_rectangle(x, y, t, h, highpix); 1187: put_rectangle(x, y + h - t, w, t, highpix); 1188: put_rectangle(x + w - t, y, t, h, highpix); 1189: } 1190: 1191: put_rectangle(x, y, w, h, pix) 1192: long x, y, w, h; 1193: int pix; 1194: { 1195: if (x < max_x && x + w >= min_x && y < max_y && y + h >= min_y) 1196: XPixSet(win, x - base_x, y - base_y, w, h, pix); 1197: } 1198: 1199: put_bitmap(bitmap, x, y, pix) 1200: register struct bitmap *bitmap; 1201: register long x, y; 1202: int pix; 1203: { 1204: if (x < max_x && x + bitmap->w >= min_x && 1205: y < max_y && y + bitmap->h >= min_y) 1206: XBitmapBitsPut(win, x - base_x, y - base_y, 1207: bitmap->w, bitmap->h, (char *) bitmap->bits, 1208: pix, backpix, NULL, GXcopy, AllPlanes); 1209: } 1210: 1211: sample(bitmap, x, y, w, h) 1212: register struct bitmap *bitmap; 1213: int x, y, w, h; 1214: { 1215: register char *ptr, *endp; 1216: register int b, i, j, m, n; 1217: 1218: ptr = bitmap->bits 1219: + (y * bitmap->bytes_wide) 1220: + (x / BITS_PER_BYTE); 1221: endp = bitmap->bits + (bitmap->h * bitmap->bytes_wide); 1222: b = (1 << (x % BITS_PER_BYTE)); 1223: n = 0; 1224: for (i = 0; i < h && ptr < endp; i += 1, ptr += bitmap->bytes_wide) 1225: for (m = b, j = 0; j < w; j += 1, m <<= 1) 1226: if (*ptr & m) 1227: n += 1; 1228: return (n >= (i * w) / 3); 1229: } 1230: 1231: shrink_bitmap(bitmap, x_factor, y_factor) 1232: register struct bitmap *bitmap; 1233: int x_factor, y_factor; 1234: { 1235: char *shrunk_bits; 1236: int shrunk_height, shrunk_width, shrunk_bytes_wide; 1237: register char *ptr; 1238: char *cp; 1239: register int x, y, b, m; 1240: 1241: shrunk_height = ROUNDUP(bitmap->h, y_factor); 1242: shrunk_width = ROUNDUP(bitmap->w, x_factor); 1243: shrunk_bytes_wide = ROUNDUP(shrunk_width, BITS_PER_SHORT)*BYTES_PER_SHORT; 1244: /* width must be multiple of 16 bits for raster_op */ 1245: ptr = shrunk_bits = calloc((unsigned) shrunk_height * shrunk_bytes_wide, 1); 1246: if (ptr == NULL) 1247: error("Can't allocate shrunken bitmap (%d by %d)", 1248: shrunk_height, shrunk_width); 1249: for (y = 0; y < bitmap->h; y += y_factor) { 1250: b = 0; 1251: m = (1 << 0); 1252: cp = ptr; 1253: for (x = 0; x < bitmap->w; x += x_factor) { 1254: if (sample(bitmap, x, y, x_factor, y_factor)) 1255: *ptr |= m; 1256: else 1257: *ptr &= ~m; 1258: b += 1; 1259: m <<= 1; 1260: if (b % BITS_PER_BYTE == 0) { 1261: b = 0; 1262: m = (1 << 0); 1263: ptr += 1; 1264: } 1265: } 1266: ptr = cp + shrunk_bytes_wide; 1267: } 1268: free(bitmap->bits); 1269: bitmap->bits = shrunk_bits; 1270: bitmap->h = shrunk_height; 1271: bitmap->w = shrunk_width; 1272: bitmap->bytes_wide = shrunk_bytes_wide; 1273: } 1274: 1275: print_char(ch, g) 1276: ubyte ch; 1277: struct glyph *g; 1278: { 1279: printf("char %d", ch); 1280: if (isprint(ch)) 1281: printf(" (%c)", ch); 1282: putchar('\n'); 1283: printf("x = %d, y = %d, pxl = %d, dvi = %d\n", 1284: g->x, g->y, g->pxl_adv, g->dvi_adv); 1285: print_bitmap(&g->bitmap); 1286: } 1287: 1288: print_bitmap(bitmap) 1289: register struct bitmap *bitmap; 1290: { 1291: register char *ptr; 1292: register int x, y, i; 1293: 1294: ptr = bitmap->bits; 1295: if (ptr == NULL) 1296: return; 1297: printf("w = %d, h = %d, bytes wide = %d\n", 1298: bitmap->w, bitmap->h, bitmap->bytes_wide); 1299: for (y = 0; y < bitmap->h; y += 1) { 1300: for (x = 0; x < bitmap->bytes_wide; x += 1) { 1301: for (i = 0; i < BITS_PER_BYTE; i += 1) 1302: if (*ptr & (1 << i)) 1303: putchar('@'); 1304: else 1305: putchar(' '); 1306: ptr += 1; 1307: } 1308: putchar('\n'); 1309: } 1310: } 1311: 1312: print_dvi(ch) 1313: ubyte ch; 1314: { 1315: printf("%4d %4d ", PXL_H, PXL_V); 1316: if (ch <= SETCHAR0 + 127) { 1317: printf("SETCHAR%-3d", ch - SETCHAR0); 1318: if (isprint(ch)) 1319: printf(" (%c)", ch); 1320: } else if (FNTNUM0 <= ch && ch <= FNTNUM0 + 63) { 1321: printf("FNTNUM%d", ch - FNTNUM0); 1322: } else { 1323: switch (ch) { 1324: case SET1: 1325: printf("SET1"); 1326: break; 1327: case SETRULE: 1328: printf("SETRULE"); 1329: break; 1330: case PUT1: 1331: printf("PUT1"); 1332: break; 1333: case PUTRULE: 1334: printf("PUTRULE"); 1335: break; 1336: case NOP: 1337: printf("NOP"); 1338: break; 1339: case BOP: 1340: printf("BOP"); 1341: break; 1342: case EOP: 1343: printf("EOP"); 1344: break; 1345: case PUSH: 1346: printf("PUSH"); 1347: break; 1348: case POP: 1349: printf("POP"); 1350: break; 1351: case RIGHT1: 1352: case RIGHT2: 1353: case RIGHT3: 1354: case RIGHT4: 1355: printf("RIGHT%d", ch - RIGHT1 + 1); 1356: break; 1357: case X0: 1358: case X1: 1359: case X2: 1360: case X3: 1361: case X4: 1362: printf("X%d", ch - X0); 1363: break; 1364: case W0: 1365: case W1: 1366: case W2: 1367: case W3: 1368: case W4: 1369: printf("W%d", ch - W0); 1370: break; 1371: case Y0: 1372: case Y1: 1373: case Y2: 1374: case Y3: 1375: case Y4: 1376: printf("Y%d", ch - Y0); 1377: break; 1378: case Z0: 1379: case Z1: 1380: case Z2: 1381: case Z3: 1382: case Z4: 1383: printf("Z%d", ch - Z0); 1384: break; 1385: case DOWN1: 1386: case DOWN2: 1387: case DOWN3: 1388: case DOWN4: 1389: printf("DOWN%d", ch - DOWN1 + 1); 1390: break; 1391: case FNT1: 1392: case FNT2: 1393: case FNT3: 1394: case FNT4: 1395: printf("FNT%d", ch - FNT1 + 1); 1396: break; 1397: case XXX1: 1398: case XXX2: 1399: case XXX3: 1400: case XXX4: 1401: printf("XXX%d", ch - XXX1 + 1); 1402: break; 1403: case FNTDEF1: 1404: case FNTDEF2: 1405: case FNTDEF3: 1406: case FNTDEF4: 1407: printf("FNTDEF%d", ch - FNTDEF1 + 1); 1408: break; 1409: case PRE: 1410: printf("PRE"); 1411: break; 1412: case POST: 1413: printf("POST"); 1414: break; 1415: case POSTPOST: 1416: printf("POSTPOST"); 1417: break; 1418: default: 1419: error("xdvi: Unknown op-code %d, offset %d", 1420: ch, ftell(dvi_file)); 1421: } /* end switch*/ 1422: } /* end else (ch not a SETCHAR or FNTNUM) */ 1423: putchar('\n'); 1424: }