Back to index

tetex-bin  3.0
color.c
Go to the documentation of this file.
00001 /*  
00002  *  This is a set of routines for dvips that are used to process color 
00003  *  commands in the TeX file (passed by \special commands).  This was
00004  *  orignally written by J. Hafner, E. Blanz and M. Flickner of IBM
00005  *  Research, Almaden Research Center.  Contact hafner@almaden.ibm.com.
00006  *  And then it was completely rewritten by Tomas Rokicki to:
00007  *
00008  *      - Be easier on the memory allocator (malloc/free)
00009  *      - Use less memory overall (by a great deal) and be faster
00010  *      - Work with the -C, -a, and other options
00011  *      - Be more adaptable to other drivers and previewers.
00012  *
00013  *  The motivating idea:  we want to be able to process 5,000 page
00014  *  documents using lots of colors on each page on a 640K IBM PC
00015  *  relatively quickly.
00016  */
00017 #include "dvips.h" /* The copyright notice in that file is included too! */
00018 #include <stdio.h>
00019 /*
00020  *   Externals we use.
00021  */
00022 #include "protos.h"
00023 extern integer pagenum ;
00024 extern FILE *dvifile ;
00025 /*
00026  *   Here we set some limits on some color stuff.
00027  */
00028 #define COLORHASH (89)
00029 #define MAXCOLORLEN (120)     /* maximum color length for background */
00030 #define INITCOLORLEN (3000)   /* initial stack size in chars */
00031 /*
00032  *   This is where we store the color information for a particular page.
00033  *   If we free all of these, we free all of the allocated color
00034  *   stuff; we do no allocations (but one) other than when we allocate
00035  *   these.
00036  */
00037 static struct colorpage {
00038    struct colorpage *next ;
00039    integer boploc ; /* we use the bop loc as a page indicator */
00040    char *bg ;
00041    char colordat[2] ;
00042 } *colorhash[COLORHASH] ;
00043 static char *cstack, *csp, *cend, *bg ;
00044 /*
00045  *   This routine sends a color command out.  If the command is a
00046  *   single `word' or starts with a double quote, we send it out
00047  *   exactly as is (except for any double quote.)  If the command
00048  *   is a word followed by arguments, we send out the arguments and
00049  *   then the word prefixed by "TeXcolor".
00050  */
00051 void colorcmdout P1C(char *, s)
00052 {
00053    char *p ;
00054    char tempword[100] ;
00055 
00056    while (*s && *s <= ' ')
00057       s++ ;
00058    if (*s == '"') {
00059       cmdout(s+1) ;
00060       return ;
00061    }
00062    for (p=s; *p && *p > ' '; p++) ;
00063    for (; *p && *p <= ' '; p++) ;
00064    if (*p == 0) {
00065       cmdout(s) ;
00066       return ;
00067    }
00068    cmdout(p) ;
00069    strcpy(tempword, "TeXcolor") ;
00070    for (p=tempword + strlen(tempword); *s && *s > ' '; p++, s++)
00071       *p = *s ;
00072    *p = 0 ;
00073    cmdout(tempword) ;
00074    return ;
00075 }
00076 /*
00077  *   For a new dvi file, call this.  Frees all allocated memory.
00078  */
00079 #define DEFAULTCOLOR "Black"
00080 void initcolor() {
00081    int i ;
00082    struct colorpage *p, *q ;
00083 
00084    for (i=0; i<COLORHASH; i++) {
00085       for (p=colorhash[i]; p; p = q) {
00086          q = p->next ;
00087          free(p) ;
00088       }
00089       colorhash[i] = 0 ;
00090    }
00091    cstack = (char *)mymalloc(INITCOLORLEN) ;
00092    strcpy(cstack, "\n") ;
00093    strcat(cstack, DEFAULTCOLOR) ;
00094    csp = cstack + strlen(cstack) ;
00095    cend = cstack + INITCOLORLEN - 3 ; /* for conservativeness */
00096    bg = 0 ;
00097 }
00098 /*
00099  * This takes a call from predospecial to set the background color for
00100  * the current page.  It is saved in stackdepth and backed down the
00101  * stack during popcolors.
00102  */
00103 void
00104 background P1C(char *, bkgrnd)
00105 {
00106    if (bkgrnd && *bkgrnd) {
00107       if (strlen(bkgrnd) > MAXCOLORLEN)
00108          error(" color name too long; ignored") ;
00109       else
00110          strcpy(bg, bkgrnd) ;
00111    }
00112 }
00113 /*
00114  * This routine puts a call from \special for color on the colorstack
00115  * and sets the color in the PostScript.
00116  */
00117 void
00118 pushcolor P2C(char *, p, Boolean, outtops)
00119 {
00120    while (strlen(p) + csp > cend) {
00121       int newlen = 3 * (cend - cstack) ;
00122       char *newcs = (char *)mymalloc(newlen) ;
00123       strcpy(newcs, cstack) ;
00124       csp = newcs + (csp - cstack) ;
00125       cend = newcs + newlen - 3 ;
00126       cstack = newcs ;
00127    }
00128    *csp++ = '\n' ;
00129    strcpy(csp, p) ;
00130    csp += strlen(p) ;
00131    if (outtops) {
00132       colorcmdout(p) ;
00133    }
00134 }
00135 /*
00136  * This routine removes a color from the colorstack and resets the color
00137  * in the PostScript to the previous color.
00138  */
00139 void
00140 popcolor P1C(Boolean, outtops)
00141 {
00142    char *p = csp - 1 ;
00143 
00144    while (p >= cstack && *p != '\n')
00145       p-- ;
00146    if (p == cstack)
00147       return ;  /* We don't pop the last color as that is global */
00148    *p = 0 ;
00149    csp = p ;
00150    for (p--; p >= cstack && *p != '\n'; p--) ;
00151    p++ ;
00152    if ( outtops ) {
00153       colorcmdout(p) ;
00154    }
00155 }
00156 /*
00157  * This routine clears the colorstack, pushes a new color onto the stack
00158  * (this is now the root or global color).
00159  */
00160 void
00161 resetcolorstack P2C(char *, p, int, outtops)
00162 {
00163    char *q = csp - 1 ;
00164 
00165    while (q > cstack && *q != '\n')
00166       q-- ;
00167    if (q > cstack && outtops == 0) {
00168 #ifdef SHORTINT
00169      (void)fprintf(stderr, "You've mistakenly made a global color change ") ;
00170      (void)fprintf(stderr, "to %s within nested colors\n", p) ;
00171      (void)fprintf(stderr, "on page %ld. Will try to recover.\n", pagenum) ;
00172 #else   /* ~SHORTINT */
00173      (void)fprintf(stderr, "You've mistakenly made a global color change ") ;
00174      (void)fprintf(stderr, "to %s within nested colors\n", p) ;
00175      (void)fprintf(stderr, "on page %d. Will try to recover.\n", pagenum) ;
00176 #endif  /* ~SHORTINT */
00177    }
00178    csp = cstack ;
00179    *csp = 0 ;
00180    pushcolor(p, outtops) ;
00181 }
00182 /*
00183  *   This routine is a bit magic.  It looks up the page in the current
00184  *   hash table.  If the page is already entered in the hash table, then
00185  *   it restores the color to what that page had, and sets the last
00186  *   color.  This will occur if this is not the first time that this
00187  *   page has been encountered.
00188  *
00189  *   If, on the other hand, this is the first time that the page has
00190  *   been encountered, then it will create a new hash entry and copy the
00191  *   current color information into it.  Since we can only encounter a
00192  *   new page after having just finished scanning the previous page,
00193  *   this is safe.
00194  */
00195 void
00196 bopcolor P1C(int, outtops)
00197 {
00198    integer pageloc = ftell(dvifile) ;
00199    int h = pageloc % COLORHASH ;
00200    struct colorpage *p = colorhash[h] ;
00201 
00202    while (p) {
00203       if (p->boploc == pageloc)
00204          break ;
00205       else
00206          p = p->next ;
00207    }
00208    if (p) {
00209       strcpy(cstack, p->colordat) ;
00210       csp = cstack + strlen(cstack) ;
00211       bg = p->bg ;
00212       if (outtops && strcmp(bg, "White")!=0 && bg[0]) {
00213          cmdout("gsave") ;
00214          colorcmdout(bg) ;
00215          cmdout("clippath fill grestore") ;
00216       }
00217    } else {
00218       p = (struct colorpage *)mymalloc((integer)
00219                   (strlen(cstack) + sizeof(struct colorpage) + MAXCOLORLEN)) ;
00220       p->next = colorhash[h] ;
00221       p->boploc = pageloc ;
00222       strcpy(p->colordat, cstack) ;
00223       p->bg = p->colordat + strlen(cstack) + 1 ;
00224       if (bg)
00225          strcpy(p->bg, bg) ;
00226       else
00227          *(p->bg) = 0 ;
00228       bg = p->bg ;
00229       colorhash[h] = p ;
00230    }
00231    if (outtops) {
00232       char *pp = csp - 1 ;
00233       while (pp >= cstack && *pp != '\n')
00234          pp-- ;
00235       pp++ ;
00236       if (strcmp(pp, DEFAULTCOLOR)!=0) {
00237          colorcmdout(pp) ;
00238       }
00239    }
00240 }