home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / s / stex2-18.zip / SeeTeX / libtex / dvistuff.c < prev    next >
C/C++ Source or Header  |  1990-07-10  |  25KB  |  1,189 lines

  1. /*
  2.  * Copyright 1989 Dirk Grunwald
  3.  * 
  4.  * Permission to use, copy, modify, distribute, and sell this software
  5.  * and its documentation for any purpose is hereby granted without fee,
  6.  * provided that the above copyright notice appear in all copies and that
  7.  * both that copyright notice and this permission notice appear in
  8.  * supporting documentation, and that the name of Dirk Grunwald or M.I.T.
  9.  * not be used in advertising or publicity pertaining to distribution of
  10.  * the software without specific, written prior permission.  Dirk
  11.  * Grunwald and M.I.T. makes no representations about the suitability of
  12.  * this software for any purpose.  It is provided "as is" without express
  13.  * or implied warranty.
  14.  * 
  15.  * DIRK GRUNWALD AND M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  16.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17.  * FITNESS, IN NO EVENT SHALL M.I.T.  BE LIABLE FOR ANY SPECIAL, INDIRECT
  18.  * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  19.  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  20.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  21.  * OR PERFORMANCE OF THIS SOFTWARE.
  22.  * 
  23.  * Author:
  24.  *     Dr. Dirk Grunwald
  25.  *     Dept. of Computer Science
  26.  *     Campus Box 430
  27.  *     Univ. of Colorado, Boulder
  28.  *     Boulder, CO 80309
  29.  * 
  30.  *     grunwald@colorado.edu
  31.  *     
  32.  */ 
  33.  
  34. #include <stdio.h>
  35. #include <ctype.h>
  36.  
  37. #include "dvistuff.h"    /* includes types & fonts */
  38.  
  39. static char *rcsid="$Header: /home/reed/grunwald/Iptex/drivers/RCS/dvistuff.c,v 1.17 88/07/07 23:25:32 grunwald Exp Locker: grunwald $" ;
  40.  
  41. #include "dviclass.h"
  42. #include "dvicodes.h"
  43. #include "postamble.h"
  44. #include "search.h"
  45. #include "fio.h"
  46.  
  47. int    dviHH = -1;        /* current horizontal position, in DEVs */
  48. int    dviVV = -1;        /* current vertical position, in DEVs */
  49. long    *dviCount[DVI_COUNT];    /* values of count */
  50. DviStack dvi_current;
  51. int    dviHHMargin = -1;    /* horizontal margin (in DEVs) */
  52. int    dviVVMargin = -1;    /* vertical margin (in DEVs) */
  53. int    dviTallestPage = -1;
  54. int    dviWidestPage = -1 ;
  55. int    dviCurrentPage = -1;
  56. int    dviTotalPages = -1;
  57. int    dviDPI = -1;
  58. int    dviMaxDrift = -1;
  59. int    dviUserMag = -1;    /* user-specified magnification */
  60. int    dviBlackness = -1;
  61. int    dviFontRotation = -1;
  62. char    *DVIFileName;
  63. static char *dviTmpFileName = 0;
  64. static char dviTmpFileNameBuffer[256];
  65. FILE    *dviFile;                /* users file */
  66. char    *dviPrintEngine = "canon";
  67.  
  68. char    *ProgName;
  69.  
  70. /*
  71.  * Similar to dvi_stack, but includes `dviHH and `dviVV, which are usually
  72.  * but not always the same as fromSP(h) and fromSP(v):
  73.  */
  74. struct localstack {
  75.     int stack_hh;
  76.     int stack_vv;
  77.     struct dvi_stack stack_dvi;
  78. };
  79.  
  80. static struct localstack *dvi_stack = 0;/* base of stack */
  81. static struct localstack *dvi_stackp;    /* current place in stack */
  82.  
  83. /*
  84.  * DVI preamble and postamble information.
  85.  */
  86.  
  87. static long Magnification;
  88. static long    Numerator;        /* numerator from DVI file */
  89. static long    Denominator;        /* denominator from DVI file */
  90.  
  91. /*
  92.  *    Font related things.
  93.  *    We keep track of the current font, use the fontfiner
  94.  *    and record errors in the dvi postable in FontErros. 
  95.  *    the NoFont is a used when we cant find a font,
  96.  *    to avoid errors.
  97.  */
  98.  
  99. struct fontinfo *dviCurrentFont = 0;
  100.  
  101. /*
  102.  *    imagen1-special uses the NextFamilyNumber. *sigh*
  103.  */
  104.  
  105. int NextFamilyNumber = 0;
  106. static int MaxFontFamily = MAX_FONTFAMILY;
  107.  
  108. static struct search *FontFinder = 0;
  109. int FontErrors = 0;
  110. static struct fontinfo NoFont;
  111. /*
  112.  *    We keep a list of pointers to the beginning of pages.
  113.  *    Each page is headed by a DVI_BOP + 44 bytes of information.
  114.  */
  115.  
  116. static long *pageOffset = 0;
  117.  
  118. #undef FIXDRIFT
  119. /*
  120.  * Correct devpos (the actual device position) to be within MaxDrift pixels
  121.  * of dvipos (the virtual DVI position).
  122.  */
  123. #define FIXDRIFT(devpos, dvipos) \
  124.     if (ABS((devpos) - (dvipos)) <= dviMaxDrift) \
  125.         /* void */; \
  126.     else \
  127.         if ((devpos) < (dvipos)) \
  128.             (devpos) = (dvipos) - dviMaxDrift; \
  129.         else \
  130.             (devpos) = (dvipos) + dviMaxDrift
  131.  
  132. #define    ABS(X)    ( (X) < 0 ? -(X) : (X) )
  133.  
  134.  
  135. /*
  136.  * Store the relevant information from the DVI postamble, and set up
  137.  * various internal things.
  138.  */
  139. static void
  140. PostAmbleHeader(p)
  141.     register struct PostAmbleInfo *p;
  142. {
  143.     int i;
  144.     int page;
  145.     int pageSize;
  146.     int stackSize;
  147.     long prevPagePointer;
  148.     long wuzAt;
  149.     
  150.     Numerator = p->pai_Numerator;
  151.     Denominator = p->pai_Denominator;
  152.     Magnification = p->pai_DVIMag;
  153.     
  154. /*
  155.  *    Set the conversion factor.  This must be done before using
  156.  *    any fonts or the fromSP routine.
  157.  */
  158.     
  159.     SetConversion(dviDPI, dviUserMag, Numerator, Denominator, Magnification);
  160.     
  161.     dviTotalPages = p -> pai_NumberOfPages;
  162.     dviWidestPage = fromSP(p -> pai_WidestPageWidth);
  163.     dviTallestPage = fromSP(p -> pai_TallestPageHeight);
  164.  
  165. /*
  166.  *    Set up the DVI stack
  167.  */
  168.     stackSize = p -> pai_DVIStackSize * sizeof(*dvi_stack);
  169.     if (dvi_stack != 0) {
  170.     free(dvi_stack);
  171.     }
  172.     dvi_stack = (struct localstack *) malloc((unsigned) stackSize);  
  173.  
  174. /*
  175.  *    Set of the table of pointers to pages and room for the
  176.  *    count variables.
  177.  */
  178.     
  179.     pageSize = dviTotalPages * sizeof(long);
  180.     if (pageOffset != 0) {
  181.     free(pageOffset);
  182.     }
  183.     pageOffset = (long *) malloc(pageSize);
  184.     
  185.     if (pageOffset == NULL) {
  186.     fprintf(stderr,"xdvi: Can not allocate page directory (%d pages)",
  187.         dviTotalPages);
  188.     exit(1);
  189.     }
  190.  
  191.     for (i = 0; i < DVI_COUNT; i++) {
  192.     if (dviCount[i] != 0) {
  193.         free(dviCount[i]);
  194.     }
  195.     dviCount[i] = (long*) malloc(pageSize);
  196.     if (dviCount[i] == NULL) {
  197.         fprintf(stderr,"xdvi: Can not allocate count directory (%d pages)",
  198.             dviTotalPages);
  199.         exit(1);
  200.     }
  201.     }
  202.         
  203.     
  204. /*
  205.  * Follow back pointers through pages in the DVI file,
  206.  * storing the offsets in the pageOffset table.
  207.  */
  208.  
  209.     prevPagePointer = p->pai_PrevPagePointer;
  210.     wuzAt = (long) ftell(dviFile);
  211.     
  212.     for (page = dviTotalPages - 1; page >= 0 ; page--) {
  213.  
  214. /*
  215.  *    Skip to previous page, but skip over BOP marker.
  216.  */
  217.     pageOffset[page] = prevPagePointer;
  218.     if( fseek(dviFile, prevPagePointer+1, 0) < 0) {
  219.         perror("fseek");
  220.         fprintf(stderr,"[postamble] improper seek looking up pages\n");
  221.         fprintf(stderr,"prevPagePointer = %lx\n",
  222.             prevPagePointer);
  223.         exit(1);
  224.     }
  225.  
  226. /*
  227.  *    Read the other counters at the beginning of the page
  228.  */
  229.  
  230.     for (i = 0; i < DVI_COUNT; i++) {
  231.         long value;
  232.         fGetLong(dviFile, value);
  233.         dviCount[i][page] = value;
  234.         }
  235.     fGetLong(dviFile, prevPagePointer);
  236.     }
  237.     fseek(dviFile, wuzAt, 0);
  238. }
  239.  
  240. static void
  241. PostAmbleFontDef(p)
  242. register struct PostAmbleFont *p;
  243. {
  244.     register struct fontinfo *fi;
  245.     register struct font *f;
  246.     
  247.     char *fname;
  248.     int def = S_CREATE | S_EXCL;
  249.     
  250.     fi = (struct fontinfo *) SSearch(FontFinder, p->paf_DVIFontIndex,
  251.                      &def);
  252.     if (fi == NULL) {
  253. /*
  254.  *    If the font already exists, lets just check that its really the
  255.  *    same thing & return
  256.  */
  257.  
  258.     if ((def & S_FOUND) | (def & S_COLL)) {
  259.  
  260.         def = S_LOOKUP;
  261.         if ((fi = (struct fontinfo *) SSearch(FontFinder,
  262.                           p -> paf_DVIFontIndex,
  263.                           &def)) == 0){
  264.         GripeNoSuchFont(p -> paf_DVIFontIndex);
  265.         exit(1);
  266.         }
  267.  
  268.         if (fi -> f == NULL) {
  269.         GripeCannotGetFont(p->paf_name, p->paf_DVIMag,
  270.                    p->paf_DVIDesignSize,
  271.                    dviPrintEngine, fname);
  272.         }
  273.         f = fi -> f;
  274.         if (p->paf_DVIChecksum && f->f_checksum &&
  275.         p->paf_DVIChecksum != f->f_checksum) {
  276.             GripeDifferentChecksums(fname, p->paf_DVIChecksum,
  277.                         f->f_checksum);
  278.             exit(1);
  279.         }
  280.         return;    /* font already defined */
  281.     }
  282.     else {
  283.         fprintf(stderr, "Can not stash font %ld (out of memory?)\n",
  284.             p -> paf_DVIFontIndex);
  285.         exit(1);
  286.     }
  287.     }
  288.  
  289.     if (NextFamilyNumber == MaxFontFamily) {
  290.     fprintf(stderr,"Out of font family!\n");
  291.     exit(1);
  292.     }
  293.  
  294.     fi->family = NextFamilyNumber;
  295.     NextFamilyNumber++;
  296.  
  297.     f = GetFont(p->paf_name, p->paf_DVIMag, p->paf_DVIDesignSize,
  298.         dviPrintEngine, &fname);
  299.  
  300. /*
  301.  *    Give the application a chance to bang on this if they want to.
  302.  */
  303.  
  304.     f = applicationNewFont(f, fi -> family);
  305.  
  306.     if ((fi->f = f) == NULL) {
  307.     GripeCannotGetFont(p->paf_name, p->paf_DVIMag,
  308.                p->paf_DVIDesignSize, dviPrintEngine, fname);
  309.     FontErrors++;
  310.     return;
  311.     }
  312.  
  313.     /* match checksums, if not zero */
  314.     if (p->paf_DVIChecksum && f->f_checksum &&
  315.     p->paf_DVIChecksum != f->f_checksum)
  316.     GripeDifferentChecksums(fname, p->paf_DVIChecksum,
  317.                 f->f_checksum);
  318.     
  319.     fi->pspace = p->paf_DVIMag / 6;    /* a three-unit "thin space" */
  320.     fi->nspace = -4 * fi->pspace;
  321.     fi->vspace = 5 * fi->pspace;
  322. }
  323.  
  324. static void
  325. ReadPostAmble()
  326. {
  327.     
  328.     if (FontFinder == 0) {
  329.     if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0) {
  330.         fprintf(stderr, "can not create FontFinder (out of memory?)");
  331.         exit(1);
  332.     }
  333.     }
  334.  
  335.     ScanPostAmble(dviFile, PostAmbleHeader, PostAmbleFontDef);
  336.  
  337.     if (FontErrors)
  338.     GripeMissingFontsPreventOutput(FontErrors);
  339. }
  340.  
  341. /*
  342.  *    Read the preamble and do a few sanity checks
  343.  */
  344.  
  345. static void
  346. ReadPreAmble()
  347. {
  348.     register int n;
  349.  
  350.     rewind(dviFile);
  351.     if (GetByte(dviFile) != Sign8(DVI_PRE))
  352.         GripeMissingOp("PRE");
  353.  
  354.     if (GetByte(dviFile) != Sign8(DVI_VERSION))
  355.         GripeMismatchedValue("version numbers");
  356.  
  357.     if (GetLong(dviFile) != Numerator)
  358.         GripeMismatchedValue("numerator");
  359.  
  360.     if (GetLong(dviFile) != Denominator)
  361.         GripeMismatchedValue("denominator");
  362.  
  363.     if (GetLong(dviFile) != Magnification)
  364.         GripeMismatchedValue("\\magfactor");
  365.  
  366.     n = UnSign8(GetByte(dviFile));
  367.     while (--n >= 0)
  368.         (void) GetByte(dviFile);
  369. }
  370.  
  371. int
  372. dviInit()
  373. {
  374.     extern char *ProgName;
  375.     FILE *tmpFile;
  376.     char *mktemp();
  377.  
  378.     dviFini();    /* clean up the old files */
  379.  
  380.     if (DVIFileName == 0) {
  381.     dviFile = stdin;
  382.     DVIFileName = "<stdin>";
  383.     }else if ((dviFile = fopen(DVIFileName, "r")) == NULL) {
  384.     int n = strlen(DVIFileName);
  385.     char *dvi_name;
  386.     
  387.     if (strcmp(DVIFileName + n - sizeof(".dvi") + 1, ".dvi") == 0) {
  388.         perror(DVIFileName);
  389.         return(1);
  390.     }
  391.  
  392.     dvi_name = (char *) malloc((unsigned) n + sizeof(".dvi"));
  393.     sprintf(dvi_name, "%s.dvi", DVIFileName);
  394.  
  395.     if ((dviFile = fopen(dvi_name, "r")) == NULL) {
  396.         perror(dvi_name);
  397.         return(1);
  398.     }
  399.     DVIFileName = dvi_name;
  400.     }
  401.  
  402. /*
  403.  *    node, copy the file to a temporary location. This lets the person
  404.  *    peruse the file while theyre re-texing it
  405.  */
  406.     strcpy(dviTmpFileNameBuffer,"/tmp/dvistuff.XXXXXX");
  407.     dviTmpFileName = mktemp(dviTmpFileNameBuffer);
  408.  
  409.     if (!(tmpFile = fopen(dviTmpFileName,"w+"))) {
  410.     perror("fopen");
  411.     fprintf(stderr,"Unable to create temporary file");
  412.     dviTmpFileName = 0;
  413.     } else {
  414.     char buffer[BUFSIZ];
  415.     int b;
  416.  
  417.     rewind(dviFile);
  418.     do {
  419.         b = fread(buffer, 1, BUFSIZ, dviFile);
  420.         fwrite(buffer, 1, b, tmpFile);
  421.     } while (! feof(dviFile));
  422.  
  423.     fclose(dviFile);
  424.     dviFile = tmpFile;
  425.     rewind(dviFile);
  426.     }
  427. /*
  428.  *    Unlink the temporary file. This keeps tmp files from cluddering
  429.  *    up /tmp and it does it in a very application-independent way.
  430.  *    You can't reopen the tmp file, but we don't really allow that
  431.  *    anyway (the tmp file is hidden from the user).
  432.  */
  433.     if (dviTmpFileName != 0 &&
  434.     strncmp(dviTmpFileName,"/tmp/",5) == 0) {
  435.         unlink(dviTmpFileName);
  436.     }
  437.  
  438.     if (dviUserMag == -1) {
  439.     dviUserMag = 1000;
  440.     }
  441.  
  442.     if (dviMaxDrift == -1) {
  443.     dviMaxDrift = DEFAULT_MAX_DRIFT;
  444.     }
  445.  
  446.     if (dviDPI == -1) {
  447.     dviDPI = DEFAULT_DPI;
  448.     }
  449.  
  450.     if (dviBlackness == -1) {
  451.     dviBlackness = DEFAULT_BLACKNESS;
  452.     }
  453.  
  454.     if (dviFontRotation == -1) {
  455.     dviFontRotation = ROT_NORM;
  456.     }
  457.  
  458.     ReadPostAmble();
  459.     ReadPreAmble();
  460.  
  461.     /* Margins -- needs work! */
  462.  
  463.     if (dviHHMargin == -1) {
  464.     dviHHMargin = DEFAULT_HHMARGIN;
  465.     }
  466.  
  467.     if (dviVVMargin == -1) {
  468.     dviVVMargin = DEFAULT_VVMARGIN;
  469.     }
  470.  
  471.     dviCurrentFont = &NoFont; /* fake font, all zeros */
  472.  
  473.     return(0);
  474. }
  475.  
  476. void
  477. dviFini()
  478. {
  479.     if (dviFile != 0) {
  480.     fclose(dviFile);
  481.     }
  482.  
  483.     if (dviTmpFileName != 0 &&
  484.     strncmp(dviTmpFileName,"/tmp/",5) == 0) {
  485.         unlink(dviTmpFileName);
  486.     }
  487. }
  488.     
  489.  
  490. static void
  491. SelectFont(n)
  492. i32 n;
  493. {
  494.     int x = S_LOOKUP;
  495.  
  496.     if ((dviCurrentFont = (struct fontinfo *)SSearch(FontFinder, n, &x)) == 0)
  497.     GripeNoSuchFont(n);
  498. }
  499.  
  500. /* Read the postamble. */
  501.  
  502. static void
  503. doDviChar(c, advance)
  504. int c;
  505. int advance;
  506. {
  507.     register struct glyph *g;
  508.     register struct font *f;
  509.     int p;
  510.  
  511.     f = dviCurrentFont->f;
  512.  
  513.     if (c < f -> f_lowch || c > f -> f_highch) {
  514.     fprintf(stderr,"Character out of range: %d\n",
  515.         c);
  516.     return;
  517.     }
  518.  
  519.     g = GLYPH(f, c);
  520.     if (!GVALID(g)) {
  521.     fprintf(stderr, "there is no character %d in %s",
  522.           c, f->f_path);
  523.     exit(1);
  524.     } else {
  525.  
  526.     if (HASRASTER(g)) {    /* workaround for Imagen bug */
  527.         applicationPutChar(dviHH,dviVV,c);
  528.     }
  529.     
  530.     if (advance) {
  531.         dviHH += g->g_pixwidth;
  532.         dvi_h += g->g_tfmwidth;
  533.         p = fromSP(dvi_h);
  534.         FIXDRIFT(dviHH, p);
  535.     }
  536.     }
  537. }
  538.  
  539. /*
  540.  *    The next two routines are used to reset all the glyphs.
  541.  *    the dviResetFont routine is called for each font in the font table.
  542.  *    It de-allocates the rasters & glyphs for the shrunken fonts, leaving
  543.  *    the original glyph data untouched.
  544.  */
  545.  
  546.  
  547. static void
  548. dviResetFont(fi, key)
  549. struct fontinfo *fi;
  550. int key;
  551. {
  552.     if (fi != 0) {
  553.     applicationResetFont(fi, fi -> family);
  554.     }
  555. }
  556.         
  557. void
  558. dviResetAll()
  559. {
  560.     SEnumerate(FontFinder, dviResetFont);
  561. }
  562.  
  563. /*
  564.  *    Process the DVI commands for page #page. If the page number is
  565.  *    out of range, it is cropped to the end.
  566.  *
  567.  *    Updates dviCurrentPage
  568.  */
  569. void
  570. dviPreparePage(page)
  571. int page;
  572. {
  573.     register int c;
  574.     register i32 p;
  575.     int advance;
  576.  
  577.     if (page < 0) {
  578.     page = 0;
  579.     }
  580.  
  581.     if (page >= dviTotalPages) {
  582.     page = dviTotalPages - 1;
  583.     }
  584.  
  585.     dviCurrentPage = page;
  586.  
  587.     fseek(dviFile, (long) pageOffset[page], 0);
  588.  
  589.     dviHH = dviHHMargin;
  590.     dviVV = dviVVMargin;
  591.  
  592.     dvi_h = toSP(dviHH);
  593.     dvi_v = toSP(dviVV);
  594.  
  595.     dvi_w = 0;
  596.     dvi_x = 0;
  597.     dvi_y = 0;
  598.     dvi_z = 0;
  599.  
  600.     dvi_stackp = dvi_stack;
  601.     
  602.     for(;;) {
  603. /*
  604.  * Get the DVI byte, and switch on its parameter length and type.
  605.  * Note that getchar() returns unsigned values.
  606.  */
  607.  
  608.     if (feof(dviFile)) {
  609.         fprintf(stderr,"Unexpected end-of-file\n");
  610.         exit(1);
  611.     }
  612.  
  613.     c = getc(dviFile);
  614.  
  615.     if (DVI_IsChar(c)) {
  616.         advance = 1;
  617.         doDviChar(c, advance);
  618.     } else {
  619.     
  620.     switch (DVI_OpLen(c)) {
  621.         
  622.     case DPL_NONE:
  623.         break;
  624.         
  625.     case DPL_SGN1:
  626.         p = getc(dviFile);
  627.         p = Sign8(p);
  628.         break;
  629.         
  630.     case DPL_SGN2:
  631.         fGetWord(dviFile, p);
  632.         p = Sign16(p);
  633.         break;
  634.         
  635.     case DPL_SGN3:
  636.         fGet3Byte(dviFile, p);
  637.         p = Sign24(p);
  638.         break;
  639.         
  640.     case DPL_SGN4:
  641.         fGetLong(dviFile, p);
  642.         break;
  643.         
  644.     case DPL_UNS1:
  645.         p = UnSign8(getc(dviFile));
  646.         break;
  647.         
  648.     case DPL_UNS2:
  649.         fGetWord(dviFile, p);
  650.         p = UnSign16(p);
  651.         break;
  652.         
  653.     case DPL_UNS3:
  654.         fGet3Byte(dviFile, p);
  655.         p = UnSign24(p);
  656.         break;
  657.         
  658.     default:
  659.         panic("DVI_OpLen(%d) = %d", c, DVI_OpLen(c));
  660.         /* NOTREACHED */
  661.     }
  662.     
  663.     switch (DVI_DT(c)) {
  664.         
  665.     case DT_SET:
  666.         c = p;
  667.         doDviChar(c, 1);
  668.         break;
  669.         
  670.     case DT_PUT:
  671.         c = p;
  672.         doDviChar(c, 0);
  673.         break;
  674.  
  675.     case DT_SETRULE:
  676.     case DT_PUTRULE:
  677.         
  678.     {
  679.         i32 h, w, rw;
  680.         
  681.         fGetLong(dviFile, h);
  682.         fGetLong(dviFile, rw);
  683.         
  684.         h = ConvRule(h);
  685.         w = ConvRule(rw);
  686.         
  687.         applicationSetRule(dviHH, dviVV, h,w);
  688.         
  689.         if (DVI_DT(c) == DT_SETRULE)  {
  690.         dviHH += w;
  691.         dvi_h += rw;
  692.         w = fromSP(dvi_h);
  693.         FIXDRIFT(dviHH, w);
  694.         }
  695.     }
  696.         break;
  697.         
  698.     case DT_NOP:
  699.         break;
  700.         
  701.     case DT_BOP:
  702. /*
  703.  *    Each beginning of page has 11 4-byte words telling us things
  704.  *    about the page. We ignore them.
  705.  */
  706.     {
  707.         fseek(dviFile, (long) (11 * 4), 1);
  708.     }
  709.  
  710.         break;
  711.         
  712.     case DT_EOP:
  713.         return;
  714.         
  715.     case DT_PUSH:
  716.         dvi_stackp->stack_hh = dviHH;
  717.         dvi_stackp->stack_vv = dviVV;
  718.         dvi_stackp->stack_dvi = dvi_current;
  719.         dvi_stackp++;
  720.         break;
  721.         
  722.     case DT_POP:
  723.         dvi_stackp--;
  724.         dviHH = dvi_stackp->stack_hh;
  725.         dviVV = dvi_stackp->stack_vv;
  726.         dvi_current = dvi_stackp->stack_dvi;
  727.         break;
  728.         
  729.     case DT_W0:    /* there should be a way to make these pretty */
  730.         p = dvi_w;
  731.         goto move_right;
  732.         
  733.     case DT_W:
  734.         dvi_w = p;
  735.         goto move_right;
  736.         
  737.     case DT_X0:
  738.         p = dvi_x;
  739.         goto move_right;
  740.         
  741.     case DT_X:
  742.         dvi_x = p;
  743.         goto move_right;
  744.         
  745.     case DT_RIGHT:
  746.     move_right:
  747.         dvi_h += p;
  748. /*
  749.  * DVItype tells us that we must round motions in this way:
  750.  * `When the horizontal motion is small, like a kern, hh
  751.  * changes by rounding the kern; but when the motion is
  752.  * large, hh changes by rounding the true position so that
  753.  * accumulated rounding errors disappear. 
  754.  */
  755.         if (p >= dviCurrentFont->pspace || p <= dviCurrentFont->nspace)
  756.         dviHH = fromSP(dvi_h);
  757.         else {
  758.         dviHH += fromSP(p);
  759.         p = fromSP(dvi_h);
  760.         FIXDRIFT(dviHH, p);
  761.         }
  762.         break;
  763.         
  764.     case DT_Y0:
  765.         p = dvi_y;
  766.         goto move_down;
  767.         
  768.     case DT_Y:
  769.         dvi_y = p;
  770.         goto move_down;
  771.         
  772.     case DT_Z0:
  773.         p = dvi_z;
  774.         goto move_down;
  775.         
  776.     case DT_Z:
  777.         dvi_z = p;
  778.         goto move_down;
  779.         
  780.     case DT_DOWN:
  781.     move_down:
  782.         dvi_v += p;
  783. /*
  784.  * `Vertical motion is done similarly, but with the threshold
  785.  * between ``small and ``large increased by a factor of
  786.  * 5.  The idea is to make fractions like $1\over2$ round
  787.  * consistently, but to absorb accumulated rounding errors in
  788.  * the baseline-skip moves. 
  789.  */
  790.         if (ABS(p) >= dviCurrentFont->vspace)
  791.         dviVV = fromSP(dvi_v);
  792.         else {
  793.         dviVV += fromSP(p);
  794.         p = fromSP(dvi_v);
  795.         FIXDRIFT(dviVV, p);
  796.         }
  797.         break;
  798.         
  799.     case DT_FNTNUM:
  800.         SelectFont((i32) (c - DVI_FNTNUM0));
  801.         break;
  802.         
  803.     case DT_FNT:
  804.         SelectFont(p);
  805.         break;
  806.         
  807.     case DT_XXX:
  808.     {
  809.         char specialBuffer [2048];
  810.         register char *cp;
  811.         int sweetp = 0;
  812.  
  813.         if (p > 2047) {
  814.         sweetp = p - 2047;
  815.         p = 2047;
  816.         }
  817.         
  818.         for (cp = specialBuffer ; p > 0; p--) {
  819.         *cp = getc(dviFile);
  820.         cp++;
  821.         }
  822.         *(cp) = 0;
  823.  
  824.         while(sweetp > 0) {
  825.         getc(dviFile);
  826.         }
  827.  
  828.         applicationDoSpecial(specialBuffer);
  829.     }
  830.         break;
  831.         
  832.     case DT_FNTDEF:
  833.         SkipFontDef(dviFile);
  834.         break;
  835.         
  836.     case DT_PRE:
  837.         GripeUnexpectedOp("PRE");
  838.         /* NOTREACHED */
  839.         
  840.     case DT_POST:
  841.         GripeUnexpectedOp("POST");
  842.         /* NOTREACHED */
  843.         
  844.     case DT_POSTPOST:
  845.         GripeUnexpectedOp("POSTPOST");
  846.         /* NOTREACHED */
  847.         
  848.     case DT_UNDEF:
  849.         GripeUndefinedOp(c);
  850.         /* NOTREACHED */
  851.         
  852.     default:
  853.         panic("DVI_DT(%d) = %d", c, DVI_DT(c));
  854.         /* NOTREACHED */
  855.     }
  856.     }
  857.     }
  858. }
  859.  
  860. /* Transpose bytes in each pair of bytes  (0123 -> 1032) */
  861. /* Reverse bits in a byte  (01234567 -> 76543210) */
  862. /* needed for sun386i */
  863. /* Gerhard Fleischanderl & Wolfgang Nejdl */
  864.  
  865. #ifdef sun386
  866. static unsigned char pow2[]={1,2,4,8,16,32,64,128};
  867.  
  868. unsigned char reverseByte(oldByte)
  869.      unsigned char oldByte;
  870. {
  871.   unsigned short i;
  872.   unsigned char newByte=0;
  873.  
  874.   /*  build newByte with bits mirrored */
  875.  
  876.   for(i=0;i<8;i++)
  877.      if (oldByte & pow2[i])
  878.         newByte |= pow2[7-i];
  879.  
  880.   return newByte;
  881. }
  882.  
  883. #ifdef UNDEF
  884. #define transposeBytesMirrorBits(pairPtr) \
  885. /* B16 *pairPtr; */ \
  886. /* B16 comprises 2 bytes */ \
  887. { \
  888.   unsigned char c0,c1, *bP = (unsigned char *) pairPtr; \
  889.  \
  890.   /* transpose neighbouring bytes and \
  891.      reverse bits in each byte */ \
  892.  \
  893.   c0 = *bP; \
  894.   c1 = *(bP+1); \
  895.   *bP = ReverseByteTable[c1]; \
  896.   *(bP+1) = ReverseByteTable[c0]; \
  897. }
  898.  
  899. #else
  900. #define transposeBytesMirrorBits(ptr) {*ptr = ReverseByteTable[ (*ptr)&0xff ];}
  901. #endif /* undef */
  902.  
  903. #endif
  904.   
  905.  
  906. /*
  907.  *    The following routine is used to shrink a glyph by some
  908.  *    shrink factor (in the width & height dimension).
  909.  *
  910.  *    These shrunken glyphs are more appropriate for previewers.
  911.  *
  912.  *    To do this, we simple scan the original raster, counting the
  913.  *    number of pixels within a given area. If the number of on pixels is
  914.  *    at least twice the total number of pixels, we turn the pixel in
  915.  *    the shrunken glyph ON, else OFF.
  916.  *
  917.  *    We use a lookup table to hasten the process of counting pixels.
  918.  *
  919.  *    The method used should be independent of byte-order (I think).
  920.  *
  921.  *    You need to define two types. One should be 32-bits long, and
  922.  *    the other 16 bits long.
  923.  */
  924.  
  925. typedef unsigned char B8;
  926. typedef unsigned short B16;
  927. typedef unsigned long B32;
  928.  
  929. #define LOOKUP_BYTES    256
  930. #define    LOOKUP_BITS    8
  931. #define LOOKUP_MASK    0xff
  932.  
  933. static char dviLookUpTable[LOOKUP_BYTES];
  934. static char tableNotInitialized = 1;
  935.  
  936. #ifdef sun386
  937. static unsigned char ReverseByteTable[LOOKUP_BYTES];
  938. #endif
  939.  
  940. struct glyph *
  941. dviShrinkGlyph(gly, shrinkH, shrinkW)
  942. DviGlyph *gly;
  943. int shrinkH;
  944. int shrinkW;
  945. {
  946.     int shrunkHeight;
  947.     int shrunkWidth;
  948.     int glyphWide;
  949.     int glyphHigh;
  950.     int glyphAdvance;
  951.     int shrunkAdvance;
  952.  
  953.     int bytesWide;
  954.     int shrunkBytesWide;
  955.  
  956.     struct glyph *ngly;
  957.  
  958.     B16 *shrunkRaster;
  959.     int rasterSize;
  960.  
  961.     int x,y;
  962.     B8 *cp;
  963.     B8 *ptr;
  964.  
  965.     B32 shrinkMask;
  966.  
  967.     int sampleSize;
  968.  
  969.     if (gly == 0 || !HASRASTER(gly)) {
  970.     return(0);
  971.     }
  972.  
  973.     if (gly -> g_raster == 0) {
  974.     gly-> g_raster = RASTER(gly, dviCurrentFont -> f, dviFontRotation);
  975.     }
  976.  
  977. /*
  978.  *    Initialize the lookup table of the number of bits in a given byte
  979.  */
  980.  
  981.     if (tableNotInitialized) {
  982.     register int i;
  983.     register int j;
  984.     register int k;
  985.     register int acc;
  986.     for (i = 0; i < LOOKUP_BYTES; i++) {
  987.         j = i;
  988.         acc = 0;
  989.         for (k = 0; j != 0 && k < LOOKUP_BITS ; k++) {
  990.         acc += (j & 1);
  991.         j >>= 1;
  992.         }
  993.         dviLookUpTable[i] = acc;
  994.     }
  995.  
  996. #ifdef sun386
  997.         for (i = 0; i < LOOKUP_BYTES; i++) {
  998.           ReverseByteTable[i] = reverseByte(i);
  999.         }
  1000. #endif
  1001.  
  1002.     tableNotInitialized = 0;
  1003.     }
  1004.  
  1005. /*
  1006.  *    When shrinking the fonts, we convert them from byte alligned
  1007.  *    to 16 bit-aligned fonts. I think that this is needed by X,
  1008.  *    and also SunWindows. This is done rather than changing the
  1009.  *    library routines because some device drivers, i.e. imagen1,
  1010.  *    depend on the byte-alligned fonts.
  1011.  */
  1012.     glyphHigh = gly -> g_height;
  1013.     glyphWide = gly -> g_width;
  1014.  
  1015.     gly -> g_pixwidth = fromSP(gly -> g_tfmwidth);
  1016.     glyphAdvance = gly -> g_pixwidth;
  1017.  
  1018.     shrunkHeight = (glyphHigh + shrinkH - 1) / shrinkH;
  1019.     shrunkWidth =  (glyphWide + shrinkW - 1) / shrinkW;
  1020.     shrunkAdvance =  (glyphAdvance + shrinkW - 1) / shrinkW;
  1021.  
  1022.     bytesWide = (gly -> g_width + 7) >> 3;
  1023.     
  1024.     shrunkBytesWide = ((shrunkWidth + 15) >> 4) * 2;
  1025.  
  1026.     rasterSize = (shrunkHeight + 1) * shrunkBytesWide;
  1027.     shrunkRaster = (B16 *) malloc(rasterSize);
  1028.     bzero(shrunkRaster, rasterSize);
  1029.     ptr = (B8 *) shrunkRaster;
  1030.     
  1031.     if (shrunkRaster == NULL) {
  1032.     fprintf(stderr, "Out of memory!\n");
  1033.     exit(1);
  1034.     }
  1035.  
  1036.     for (y = 0; y < glyphHigh; y+= shrinkH) {
  1037.     cp = (B8 *) ptr;
  1038.     shrinkMask = 0x80;
  1039.     for (x = 0; x < glyphWide; x += shrinkW) {
  1040.         int i;
  1041.         int samples;
  1042.         B8 *baseP;
  1043.         int upper;
  1044.         register int thisShrinkW;
  1045.  
  1046.         baseP = (B8 *) gly -> g_raster + (y * bytesWide);
  1047.  
  1048. /*
  1049.  *    Set the upper limit on the height iteration so we dont count
  1050.  *    off the end of the raster
  1051.  */
  1052.  
  1053.         upper = y + shrinkH;
  1054.         if (upper > glyphHigh) {
  1055.         upper = glyphHigh;
  1056.         }
  1057.  
  1058.         if (x + shrinkW > glyphWide) {
  1059.         thisShrinkW = glyphWide - x;
  1060.         } else {
  1061.         thisShrinkW = shrinkW;
  1062.         }
  1063.  
  1064.         samples = 0;
  1065.         sampleSize = thisShrinkW * (upper - y);
  1066.  
  1067.         for (i = y; i < upper; i++) {
  1068.         register int acc;
  1069.         register B8 *p;
  1070.         register B8 *ep;
  1071. /*
  1072.  *    Determine how many bytes our shrink window crosses (we might
  1073.  *    overlap on byte-edges)
  1074.  */
  1075.  
  1076.         p = baseP + (x >> 3);
  1077.         ep = baseP + ( (x + thisShrinkW - 1) >> 3);
  1078.         baseP += bytesWide;
  1079.  
  1080. /*
  1081.  *    stuff everything in the accumulator
  1082.  */
  1083.  
  1084.         acc = 0;
  1085.         while (p <= ep) {
  1086.             acc = ((acc << 8) & ~0xff) | *p;
  1087.             p++;
  1088.         }
  1089.  
  1090. /*
  1091.  *    clean off the right hand-side of extra bits, then clean off
  1092.  *    the left hand side of extra bits, and then count them.
  1093.  */
  1094.  
  1095.         acc = acc >> ( 7 - ((x + thisShrinkW - 1) & 0x7));
  1096.         acc &= ~(-1 << thisShrinkW);
  1097.         while (acc != 0) {
  1098.             samples += dviLookUpTable[ acc & LOOKUP_MASK ];
  1099.             acc >>= LOOKUP_BITS;
  1100.         }
  1101.         }
  1102. /*
  1103.  *    If at least 1/blackness of the bits are on, treat this entire sample as
  1104.  *    being on.
  1105.  */
  1106.  
  1107.         if ((samples * dviBlackness) >= sampleSize) {
  1108.         *ptr |= shrinkMask;
  1109.         } else {
  1110.         *ptr &= ~ shrinkMask;
  1111.         }
  1112.         shrinkMask >>= 1;
  1113.         if (shrinkMask == 0) {
  1114.         shrinkMask = 0x80;
  1115. #ifdef sun386
  1116.         transposeBytesMirrorBits(ptr)
  1117. #endif
  1118.         ptr ++;
  1119.         }
  1120.     }
  1121. #ifdef sun386
  1122.     transposeBytesMirrorBits(ptr)
  1123. #endif
  1124.     ptr = (B8 *) (cp + shrunkBytesWide);
  1125.     }
  1126.  
  1127. /*
  1128.  *    Build a new glyph from the shrunken raster
  1129.  */
  1130.  
  1131. #ifdef    UNDEF
  1132.     if ( shrunkBytesWide != 2 )
  1133.       {
  1134.         printf("Old glyph:\n");
  1135.         seeGlyph(gly -> g_raster, glyphHigh, bytesWide);
  1136.         printf("%d ", shrunkBytesWide);
  1137.         printf("New glyph:\n");
  1138.         seeGlyph(shrunkRaster, shrunkHeight, shrunkBytesWide);
  1139.       }
  1140. #endif    UNDEF
  1141.  
  1142.     ngly = (struct glyph *) malloc(sizeof(struct glyph));
  1143.     bzero(ngly, sizeof(struct glyph));
  1144.  
  1145.     ngly -> g_raster = (char * ) shrunkRaster;
  1146.     ngly -> g_width = shrunkWidth;
  1147.     ngly -> g_pixwidth = shrunkAdvance;
  1148.     ngly -> g_height = shrunkHeight;
  1149.  
  1150.     ngly -> g_xorigin = gly -> g_xorigin / shrinkH;
  1151.     ngly -> g_yorigin = gly -> g_yorigin / shrinkW;
  1152.  
  1153.     ngly -> g_flags |= GF_SHRUNK;    /* yes, its been shrunk */
  1154.  
  1155.     return(ngly);
  1156. }
  1157.  
  1158. #ifdef    UNDEF
  1159.  
  1160. seeGlyph(c, h, w)
  1161. char *c;
  1162. int h;
  1163. int w;
  1164. {
  1165.     int i,j;
  1166.  
  1167.     for (i = 0; i < h; i++ ) {
  1168.     for (j = 0; j < w; j++) {
  1169.         int k;
  1170.         register int ch;
  1171.         register int m;
  1172.         char str[9];
  1173.  
  1174.         ch = *(c++);
  1175.         m = 0x80;
  1176.         for (k = 0; k < 8; k++) {
  1177.         str[k] = '"' + ( (ch & m) ? 1 : 0 );
  1178.         m >>= 1;
  1179.         }
  1180.         str[8] = 0;
  1181.         printf("%s", str);
  1182.     }
  1183.     printf("\n");
  1184.     }
  1185. }
  1186.         
  1187.         
  1188. #endif    UNDEF
  1189.