/* * Copyright (c) 1994 Paul Vojta. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * NOTE: * xdvi is based on prior work as noted in the modification history, below. */ /* * DVI previewer for X. * * Eric Cooper, CMU, September 1985. * * Code derived from dvi-imagen.c. * * Modification history: * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. * 7/1988 Modified for X.11 --Mark Eichin, MIT * 12/1988 Added 'R' option, toolkit, magnifying glass * --Paul Vojta, UC Berkeley. * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. * 3/1990 Added VMS support --Scott Allendorf, U of Iowa * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen * and Lee Hetherington, MIT * 4/1994 Added DPS support, bounding box * --Ricardo Telichevesky * and Luis Miguel Silveira, MIT RLE. */ #define DEBUG 0 #include "dviwin.h" #include #include #include extern "C" { #include #include #include #include #include #include "dvi.h" } #include "glyph.h" #include "oconfig.h" extern char *xmalloc (unsigned, _Xconst char *); #define PK_PRE 247 #define PK_ID 89 #define PK_MAGIC (PK_PRE << 8) + PK_ID #define GF_PRE 247 #define GF_ID 131 #define GF_MAGIC (GF_PRE << 8) + GF_ID #define VF_PRE 247 #define VF_ID_BYTE 202 #define VF_MAGIC (VF_PRE << 8) + VF_ID_BYTE #define dvi_oops(str) (dvi_oops_msg = (str), longjmp(dvi_env, 1)) static Boolean font_not_found; Boolean _hush_spec; Boolean _hush_chk; QDateTime dvi_time; /* * DVI preamble and postamble information. */ static char job_id[300]; static long numerator, denominator; /* * Offset in DVI file of last page, set in read_postamble(). */ static long last_page_offset; /** Release all shrunken bitmaps for all fonts. */ extern void reset_fonts(void) { kdDebug() << "Reset Fonts" << endl; struct font *f; struct glyph *g; for (f = font_head; f != NULL; f = f->next) if ((f->flags & font::FONT_LOADED) && !(f->flags & font::FONT_VIRTUAL)) for (g = f->glyphtable; g < f->glyphtable + font::max_num_of_chars_in_font; ++g) g->clearShrunkCharacter(); } /* * MAGSTEPVALUE - If the given magnification is close to a \magstep * or a \magstephalf, then return twice the number of \magsteps. * Otherwise return NOMAGSTP. */ #define NOMAGSTP (-29999) #define NOBUILD 29999 static int magstepvalue(float *mag) { int m_ret; unsigned dpi_ret = kpse_magstep_fix ((unsigned) *mag, (unsigned) pixels_per_inch, &m_ret); *mag = (float) dpi_ret; /* MAG is actually a dpi. */ return m_ret ? m_ret : NOMAGSTP; } /** define_font reads the rest of the fntdef command and then reads in * the specified pixel file, adding it to the global linked-list * holding all of the fonts used in the job. */ font *define_font(FILE *file, unsigned int cmnd, font *vfparent, QIntDict *TeXNumberTable) // FILE *file; // unsigned int cmnd; // struct font *vfparent; /* vf parent of this font, or NULL */ // struct font **tntable; /* table for low TeXnumbers */ // unsigned int tn_table_len; /* length of table for TeXnumbers */ // struct tn **tn_headpp; /* addr of head of list of TeXnumbers */ { struct font *fontp; int magstepval; int size; int TeXnumber = num(file, (int) cmnd - FNTDEF1 + 1); long checksum = four(file); int scale = four(file); int design = four(file); int len = one(file) + one(file); /* sequence point in the middle */ char *fontname = xmalloc((unsigned) len + 1, "font name"); Fread(fontname, sizeof(char), len, file); fontname[len] = '\0'; kdDebug() << "Define font \"" << fontname << "\" scale=" << scale << " design=" << design << endl; float fsize; double scale_dimconv; if (vfparent == NULL) { fsize = 0.001 * scale / design * magnification * pixels_per_inch; scale_dimconv = dimconv; } else { /* * The scaled size is given in units of vfparent->scale * 2 ** -20 * SPELL units, so we convert it into SPELL units by multiplying by * vfparent->dimconv. * The design size is given in units of 2 ** -20 pt, so we convert * into SPELL units by multiplying by * (pixels_per_inch * 2**16) / (72.27 * 2**20). */ fsize = (72.27 * (1<<4)) * vfparent->dimconv * scale / design; scale_dimconv = vfparent->dimconv; } magstepval = magstepvalue(&fsize); size = (int)(fsize + 0.5); // reuse font if possible for (fontp = font_head;; fontp = fontp->next) { if (fontp == NULL) { /* if font doesn't exist yet */ fontp = new font(fontname, fsize, checksum, magstepval, scale * scale_dimconv / (1<<20)); fontp->set_char_p = load_n_set_char; /* With virtual fonts, we might be opening another font (pncb.vf), instead of what we just allocated for (rpncb), thus leaving garbage in the structure for when close_a_file comes along looking for something. */ if (vfparent == NULL) font_not_found |= fontp->load_font(); fontp->next = font_head; font_head = fontp; break; } if (strcmp(fontname, fontp->fontname) == 0 && size == (int)(fontp->fsize + 0.5)) { /* if font already in use */ fontp->mark_as_used(); free(fontname); break; } } // Insert font in dictionary and make sure the dictionary is big // enough if (TeXNumberTable->size()-2 <= TeXNumberTable->count()) // Not quite optimal. The size of the dict. should be a prime. I // don't care TeXNumberTable->resize(TeXNumberTable->size()*2); TeXNumberTable->insert(TeXnumber, fontp); return fontp; } /* * process_preamble reads the information in the preamble and stores * it into global variables for later use. */ static void process_preamble() { unsigned char k; if (one(dvi_file) != PRE) dvi_oops("DVI file doesn't start with preamble"); if (one(dvi_file) != 2) dvi_oops("Wrong version of DVI output for this program"); numerator = four(dvi_file); denominator = four(dvi_file); magnification = four(dvi_file); dimconv = (((double) numerator * magnification) / ((double) denominator * 1000.)); dimconv = dimconv * (((long) pixels_per_inch)<<16) / 254000; tpic_conv = pixels_per_inch * magnification / 1000000.0; k = one(dvi_file); Fread(job_id, sizeof(char), (int) k, dvi_file); job_id[k] = '\0'; } /* * find_postamble locates the beginning of the postamble * and leaves the file ready to start reading at that location. */ #define TMPSIZ 516 /* 4 trailer bytes + 512 junk bytes allowed */ static void find_postamble() { long pos; unsigned char temp[TMPSIZ]; unsigned char *p; unsigned char *p1; unsigned char byte; Fseek(dvi_file, (long) 0, 2); pos = ftell(dvi_file) - TMPSIZ; if (pos < 0) pos = 0; Fseek(dvi_file, pos, 0); p = temp + fread((char *) temp, sizeof(char), TMPSIZ, dvi_file); for (;;) { p1 = p; while (p1 > temp && *(--p1) != TRAILER) ; p = p1; while (p > temp && *(--p) == TRAILER) ; if (p <= p1 - 4) break; /* found 4 TRAILER bytes */ if (p <= temp) dvi_oops("DVI file corrupted"); } pos += p - temp; byte = *p; while (byte == TRAILER) { Fseek(dvi_file, --pos, 0); byte = one(dvi_file); } if (byte != 2) dvi_oops("Wrong version of DVI output for this program"); Fseek(dvi_file, pos - 4, 0); Fseek(dvi_file, sfour(dvi_file), 0); } /* * read_postamble reads the information in the postamble, * storing it into global variables. * It also takes care of reading in all of the pixel files for the fonts * used in the job. */ static void read_postamble() { unsigned char cmnd; struct font *fontp; struct font **fontpp; if (one(dvi_file) != POST) dvi_oops("Postamble doesn't begin with POST"); last_page_offset = four(dvi_file); if (numerator != four(dvi_file) || denominator != four(dvi_file) || magnification != four(dvi_file)) dvi_oops("Postamble doesn't match preamble"); /* read largest box height and width */ unshrunk_page_h = (spell_conv(sfour(dvi_file)) >> 16) + offset_y; if (unshrunk_page_h < unshrunk_paper_h) unshrunk_page_h = unshrunk_paper_h; unshrunk_page_w = (spell_conv(sfour(dvi_file)) >> 16) + offset_x; if (unshrunk_page_w < unshrunk_paper_w) unshrunk_page_w = unshrunk_paper_w; (void) two(dvi_file); /* max stack size */ total_pages = two(dvi_file); font_not_found = False; while ((cmnd = one(dvi_file)) >= FNTDEF1 && cmnd <= FNTDEF4) (void) define_font(dvi_file, cmnd, (struct font *) NULL, &tn_table); if (cmnd != POSTPOST) dvi_oops("Non-fntdef command found in postamble"); if (font_not_found) dvi_oops("Not all pixel files were found"); // free up fonts no longer in use fontpp = &font_head; while ((fontp = *fontpp) != NULL) if (fontp->flags & font::FONT_IN_USE) // Question: Is this ever false? fontpp = &fontp->next; else delete fontp; } static void prepare_pages() { int i; page_offset = (long *) xmalloc((unsigned) total_pages * sizeof(long), "page directory"); i = total_pages; page_offset[--i] = last_page_offset; Fseek(dvi_file, last_page_offset, 0); /* * Follow back pointers through pages in the DVI file, * storing the offsets in the page_offset table. */ while (i > 0) { Fseek(dvi_file, (long) (1+4+(9*4)), 1); Fseek(dvi_file, page_offset[--i] = four(dvi_file), 0); } } void init_page() { page_w = (int)(unshrunk_page_w / mane.shrinkfactor + 0.5) + 2; page_h = (int)(unshrunk_page_h / mane.shrinkfactor + 0.5) + 2; } /** init_dvi_file is the main subroutine for reading the startup * information from the dvi file. Returns True on success. */ static Boolean init_dvi_file() { if (QFileInfo(dvi_name).isDir()) return False; tn_table.clear(); dvi_time = QFileInfo(dvi_name).lastModified(); process_preamble(); find_postamble(); read_postamble(); prepare_pages(); init_page(); if (current_page >= total_pages) current_page = total_pages - 1; hush_spec_now = hush_spec; return True; } /** ** Check for changes in dvi file. **/ extern Boolean check_dvi_file(void) { if (dvi_file == NULL || (dvi_time != QFileInfo(dvi_name).lastModified())) { if (dvi_file) { Fclose(dvi_file); dvi_file = NULL; } dvi_file = fopen(dvi_name, OPEN_MODE); if (dvi_file == NULL || !init_dvi_file()) dvi_oops("Cannot reopen dvi file."); return False; } return True; }