Back to index

tetex-bin  3.0
draw.c
Go to the documentation of this file.
00001 /* draw.c */
00002 
00003 /************************************************************************
00004 
00005   Part of the dvipng distribution
00006 
00007   This program is free software; you can redistribute it and/or modify
00008   it under the terms of the GNU General Public License as published by
00009   the Free Software Foundation; either version 2 of the License, or
00010   (at your option) any later version.
00011 
00012   This program is distributed in the hope that it will be useful, but
00013   WITHOUT ANY WARRANTY; without even the implied warranty of
00014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015   General Public License for more details.
00016 
00017   You should have received a copy of the GNU General Public License
00018   along with this program; if not, write to the Free Software
00019   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00020   02111-1307, USA.
00021 
00022   Copyright (C) 2002-2005 Jan-Åke Larsson
00023 
00024 ************************************************************************/
00025 
00026 #include "dvipng.h"
00027 
00028 /* #define NO_DRIFT */
00029 
00030 #ifdef DEBUG
00031 #include <ctype.h> /* isprint */
00032 #endif
00033 
00034 struct stack_entry {  
00035   dviunits    h, v, w, x, y, z; /* stack entry                           */
00036 #ifndef NO_DRIFT
00037   subpixels    hh,vv;
00038 #endif
00039 } stack[STACK_SIZE];           /* stack                                 */
00040 int       sp = 0;              /* stack pointer                         */
00041 
00042 dviunits    h;                   /* current horizontal position     */
00043 dviunits    v;                   /* current vertical position       */
00044 dviunits    w=0;                 /* current horizontal spacing      */
00045 dviunits    x=0;                 /* current horizontal spacing      */
00046 dviunits    y=0;                 /* current vertical spacing        */
00047 dviunits    z=0;                 /* current vertical spacing        */
00048 #ifndef NO_DRIFT
00049 subpixels   hh;                  /* current rounded horizontal position     */
00050 subpixels   vv;                  /* current rounded vertical position       */
00051 #else
00052 # define hh PIXROUND(h,dvi->conv*shrinkfactor)
00053 # define vv PIXROUND(v,dvi->conv*shrinkfactor)
00054 #endif
00055 
00056 
00057 #ifndef NO_DRIFT
00058 #define MAXDRIFT 1
00059 #define CHECK_MAXDRIFT(x,xx) if ( xx-PIXROUND(x,dvi->conv*shrinkfactor) < -MAXDRIFT ) { \
00060                                DEBUG_PRINT(DEBUG_DVI,(" add 1 to")); \
00061                             xx += 1; \
00062                              } \
00063                              if ( xx-PIXROUND(x,dvi->conv*shrinkfactor) > MAXDRIFT ) { \
00064                                DEBUG_PRINT(DEBUG_DVI,(" sub 1 to")); \
00065                             xx -= 1; \
00066                              } \
00067                              if (PIXROUND(h,dvi->conv*shrinkfactor) != hh \
00068                                  || PIXROUND(v,dvi->conv*shrinkfactor) != vv) \
00069                                 DEBUG_PRINT(DEBUG_DVI,(" drift (%d,%d)", \
00070                                              hh-PIXROUND(h,dvi->conv*shrinkfactor), \
00071                                              vv-PIXROUND(v,dvi->conv*shrinkfactor))); 
00072 #define MoveRight(x)  temp=x; h += temp; \
00073                       if ( currentfont==NULL \
00074                            || temp > currentfont->s/6 || temp < -currentfont->s/6*4 ) \
00075                         hh = PIXROUND(h,dvi->conv*shrinkfactor); \
00076                       else \
00077                         hh += PIXROUND( temp,dvi->conv*shrinkfactor ); \
00078                       CHECK_MAXDRIFT(h,hh)
00079 #define MoveDown(x)   temp=x; v += temp; \
00080                       if ( currentfont==NULL \
00081                            || temp > currentfont->s/6*5 || temp < currentfont->s/6*(-5) ) \
00082                         vv = PIXROUND(v,dvi->conv*shrinkfactor); \
00083                       else \
00084                       vv += PIXROUND( temp,dvi->conv*shrinkfactor ); \
00085                       CHECK_MAXDRIFT(v,vv)
00086 #else
00087 #define MoveRight(b)  h += (dviunits) b
00088 #define MoveDown(a)   v += (dviunits) a
00089 #endif
00090 
00091 
00092 #define DO_VFCONV(a) ((((struct font_entry*) parent)->type==DVI_TYPE)?a:\
00093     (dviunits)((int64_t) a *  ((struct font_entry*) parent)->s / (1 << 20)))
00094 
00095 
00096 dviunits SetChar(int32_t c)
00097 {
00098   struct char_entry* ptr;
00099 
00100   if (currentfont==NULL) 
00101     Fatal("faulty DVI, trying to set character from null font");
00102   ptr = currentfont->chr[c];
00103 #ifdef DEBUG
00104   switch (currentfont->type) {
00105   case FONT_TYPE_VF: DEBUG_PRINT(DEBUG_DVI,("\n  VF CHAR:\t")); break;
00106   case FONT_TYPE_PK: DEBUG_PRINT(DEBUG_DVI,("\n  PK CHAR:\t")); break;
00107   case FONT_TYPE_T1: DEBUG_PRINT(DEBUG_DVI,("\n  T1 CHAR:\t")); break;
00108   case FONT_TYPE_FT: DEBUG_PRINT(DEBUG_DVI,("\n  FT CHAR:\t")); break;
00109   }
00110   if (isprint(c))
00111     DEBUG_PRINT(DEBUG_DVI,("'%c' ",c));
00112   DEBUG_PRINT(DEBUG_DVI,("%d at (%d,%d) tfmw %d", c,hh,vv,ptr->tfmw));
00113 #endif
00114   if (currentfont->type==FONT_TYPE_VF) {
00115     return(SetVF(c));
00116   } else if (ptr) {
00117     if (ptr->data == NULL) 
00118       switch(currentfont->type) {
00119       case FONT_TYPE_PK:    LoadPK(c, ptr); break;
00120 #ifdef HAVE_LIBT1
00121       case FONT_TYPE_T1:    LoadT1(c, ptr); break;
00122 #endif
00123 #ifdef HAVE_FT2
00124       case FONT_TYPE_FT:    LoadFT(c, ptr); break;
00125 #endif
00126       default:
00127        Fatal("undefined fonttype %d",currentfont->type);
00128       }
00129     if (page_imagep != NULL)
00130       return(SetGlyph(c, hh, vv));
00131     else {
00132       /* Expand bounding box if necessary */
00133       min(x_min,hh - ptr->xOffset/shrinkfactor);
00134       min(y_min,vv - ptr->yOffset/shrinkfactor);
00135       max(x_max,hh - ptr->xOffset/shrinkfactor + ptr->w);
00136       max(y_max,vv - ptr->yOffset/shrinkfactor + ptr->h);
00137       return(ptr->tfmw);
00138     }
00139   }
00140   return(0);
00141 }
00142 
00143 void DrawCommand(unsigned char* command, void* parent /* dvi/vf */)
00144      /* To be used both in plain DVI drawing and VF drawing */
00145 {
00146   dviunits temp;
00147 
00148   if (/*command >= SETC_000 &&*/ *command <= SETC_127) {
00149     temp = SetChar((int32_t)*command);
00150     h += temp;
00151 #ifndef NO_DRIFT
00152     hh += PIXROUND(temp,dvi->conv*shrinkfactor);
00153     CHECK_MAXDRIFT(h,hh);
00154 #endif
00155   } else if (*command >= FONT_00 && *command <= FONT_63) {
00156     SetFntNum((int32_t)*command - FONT_00,parent);
00157   } else switch (*command)  {
00158   case PUT1: case PUT2: case PUT3: case PUT4:
00159     DEBUG_PRINT(DEBUG_DVI,(" %d",
00160                UNumRead(command+1, dvi_commandlength[*command]-1)));
00161     (void) SetChar(UNumRead(command+1, dvi_commandlength[*command]-1));
00162     break;
00163   case SET1: case SET2: case SET3: case SET4:
00164     DEBUG_PRINT(DEBUG_DVI,(" %d",
00165                UNumRead(command+1, dvi_commandlength[*command]-1)));
00166     {
00167       temp = SetChar(UNumRead(command+1, dvi_commandlength[*command]-1));
00168       h += temp;
00169 #ifndef NO_DRIFT
00170       hh += PIXROUND(temp,dvi->conv*shrinkfactor);
00171       CHECK_MAXDRIFT(h,hh);
00172 #endif
00173     }    
00174     break;
00175   case SET_RULE:
00176     DEBUG_PRINT(DEBUG_DVI,(" %d %d",
00177                UNumRead(command+1, 4), UNumRead(command+5, 4)));
00178     temp = SetRule(DO_VFCONV(UNumRead(command+1, 4)),
00179                  DO_VFCONV(UNumRead(command+5, 4)),
00180                  hh, vv);
00181     h += temp;
00182 #ifndef NO_DRIFT
00183     hh += PIXROUND(temp,dvi->conv*shrinkfactor);
00184     CHECK_MAXDRIFT(h,hh);
00185 #endif
00186     break;
00187   case PUT_RULE:
00188     DEBUG_PRINT(DEBUG_DVI,(" %d %d",
00189                UNumRead(command+1, 4), UNumRead(command+5, 4)));
00190     (void) SetRule(DO_VFCONV(UNumRead(command+1, 4)),
00191                  DO_VFCONV(UNumRead(command+5, 4)),
00192                  hh, vv);
00193     break;
00194   case BOP:
00195     Fatal("BOP occurs within page");
00196     break;
00197   case EOP:
00198     break;
00199   case PUSH:
00200     if (sp >= STACK_SIZE)
00201       Fatal("stack overflow");
00202     stack[sp].h = h;
00203     stack[sp].v = v;
00204     stack[sp].w = w;
00205     stack[sp].x = x;
00206     stack[sp].y = y;
00207     stack[sp].z = z;
00208 #ifndef NO_DRIFT
00209     stack[sp].hh = hh;
00210     stack[sp].vv = vv;
00211 #endif
00212     sp++;
00213     break;
00214   case POP:
00215     --sp;
00216     if (sp < 0)
00217       Fatal("stack underflow");
00218     h = stack[sp].h;
00219     v = stack[sp].v;
00220     w = stack[sp].w;
00221     x = stack[sp].x;
00222     y = stack[sp].y;
00223     z = stack[sp].z;
00224 #ifndef NO_DRIFT
00225     hh = stack[sp].hh;
00226     vv = stack[sp].vv;
00227 #endif
00228     break;
00229   case RIGHT1: case RIGHT2: case RIGHT3: case RIGHT4:
00230     DEBUG_PRINT(DEBUG_DVI,(" %d",
00231                SNumRead(command+1, dvi_commandlength[*command]-1)));
00232     MoveRight(DO_VFCONV(SNumRead(command+1, dvi_commandlength[*command]-1)));
00233     break;
00234   case W1: case W2: case W3: case W4:
00235     w = SNumRead(command+1, dvi_commandlength[*command]-1);
00236     DEBUG_PRINT(DEBUG_DVI,(" %d",w));
00237   case W0:
00238     MoveRight(DO_VFCONV(w));
00239     break;
00240   case X1: case X2: case X3: case X4:
00241     x = SNumRead(command+1, dvi_commandlength[*command]-1);
00242     DEBUG_PRINT(DEBUG_DVI,(" %d",x));
00243   case X0:
00244     MoveRight(DO_VFCONV(x));
00245     break;
00246   case DOWN1: case DOWN2: case DOWN3: case DOWN4:
00247     DEBUG_PRINT(DEBUG_DVI,(" %d",
00248                SNumRead(command+1, dvi_commandlength[*command]-1)));
00249     MoveDown(DO_VFCONV(SNumRead(command+1, dvi_commandlength[*command]-1)));
00250     break;
00251   case Y1: case Y2: case Y3: case Y4:
00252     y = SNumRead(command+1, dvi_commandlength[*command]-1);
00253     DEBUG_PRINT(DEBUG_DVI,(" %d",y));
00254   case Y0:
00255     MoveDown(DO_VFCONV(y));
00256     break;
00257   case Z1: case Z2: case Z3: case Z4:
00258     z = SNumRead(command+1, dvi_commandlength[*command]-1);
00259     DEBUG_PRINT(DEBUG_DVI,(" %d",z));
00260   case Z0:
00261     MoveDown(DO_VFCONV(z));
00262     break;
00263   case FNT1: case FNT2: case FNT3: case FNT4:
00264     DEBUG_PRINT(DEBUG_DVI,(" %d",
00265                UNumRead(command+1, dvi_commandlength[*command]-1)));
00266     SetFntNum(UNumRead(command+1, dvi_commandlength[*command]-1),parent);
00267     break;
00268   case XXX1: case XXX2: case XXX3: case XXX4:
00269     DEBUG_PRINT(DEBUG_DVI,(" %d",
00270                UNumRead(command+1, dvi_commandlength[*command]-1)));
00271     SetSpecial((char*)command + dvi_commandlength[*command], 
00272               UNumRead(command+1, dvi_commandlength[*command]-1),
00273               hh,vv);
00274     break;
00275   case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4:
00276     if (((struct font_entry*)parent)->type==DVI_TYPE) {
00277       FontDef(command, parent); 
00278     } else {
00279       Fatal("%s within VF macro from %s",dvi_commands[*command],
00280            ((struct font_entry*)parent)->name);
00281     }
00282     break;
00283   case PRE: case POST: case POST_POST:
00284     Fatal("%s occurs within page",dvi_commands[*command]);
00285     break;
00286   case NOP:
00287     break;
00288   default:
00289     Fatal("%s is an undefined command",dvi_commands[*command]);
00290     break;
00291   }
00292 }
00293 
00294 void BeginVFMacro(struct font_entry* currentvf)
00295 {
00296   if (sp >= STACK_SIZE)
00297     Fatal("stack overflow");
00298   stack[sp].h = h;
00299   stack[sp].v = v;
00300   stack[sp].w = w;
00301   stack[sp].x = x;
00302   stack[sp].y = y;
00303   stack[sp].z = z;
00304 #ifndef NO_DRIFT
00305   stack[sp].hh = hh;
00306   stack[sp].vv = vv;
00307 #endif
00308   sp++;
00309   w = x = y = z = 0;
00310   DEBUG_PRINT(DEBUG_DVI,("\n  START VF:\tPUSH, W = X = Y = Z = 0"));
00311   SetFntNum(currentvf->defaultfont,currentvf);
00312 }
00313 
00314 void EndVFMacro(void)
00315 {
00316   --sp;
00317   if (sp < 0)
00318     Fatal("stack underflow");
00319   h = stack[sp].h;
00320   v = stack[sp].v;
00321   w = stack[sp].w;
00322   x = stack[sp].x;
00323   y = stack[sp].y;
00324   z = stack[sp].z;
00325 #ifndef NO_DRIFT
00326   hh = stack[sp].hh;
00327   vv = stack[sp].vv;
00328 #endif
00329   DEBUG_PRINT(DEBUG_DVI,("\n  END VF:\tPOP                                  "));
00330 }
00331 
00332 
00333 void DrawPage(dviunits hoffset, dviunits voffset) 
00334      /* To be used after having read BOP and will exit cleanly when
00335       * encountering EOP.
00336       */
00337 {
00338   unsigned char*  command;  /* current command                  */
00339 
00340   h = hoffset;
00341   v = voffset;
00342   w = x = y = z = 0;
00343 #ifndef NO_DRIFT
00344   hh = PIXROUND( h , dvi->conv*shrinkfactor );
00345   vv = PIXROUND( v , dvi->conv*shrinkfactor );
00346 #endif
00347   currentfont = NULL;    /* No default font                  */
00348 
00349   command=DVIGetCommand(dvi);
00350   DEBUG_PRINT(DEBUG_DVI,("DRAW CMD:\t%s", dvi_commands[*command]));
00351   while (*command != EOP)  {
00352     DrawCommand(command,dvi);
00353     command=DVIGetCommand(dvi);
00354     DEBUG_PRINT(DEBUG_DVI,("DRAW CMD:\t%s", dvi_commands[*command]));
00355   } 
00356 }
00357 
00358 void DrawPages(void)
00359 {
00360   struct page_list *dvi_pos;
00361   pixels x_width,y_width,x_offset,y_offset;
00362 
00363   dvi_pos=NextPPage(dvi,NULL);
00364   if (dvi_pos!=NULL) {
00365     while(dvi_pos!=NULL) {
00366       SeekPage(dvi,dvi_pos);
00367       x_max = y_max = INT32_MIN;
00368       x_min = y_min = INT32_MAX;
00369       DrawPage((dviunits)0,(dviunits)0);
00370       /* Store background color. Background color of a page is given
00371         by the color at EOP rather than the color at BOP. */
00372       StoreBackgroundColor(dvi_pos);
00373       /* Store pagesize */
00374       if (flags & PREVIEW_LATEX_TIGHTPAGE) {
00375        x_width_def=x_width_tightpage;
00376        y_width_def=y_width_tightpage;
00377        x_offset_def=x_offset_tightpage;
00378        y_offset_def=y_offset_tightpage;
00379       }
00380       if (x_width_def >= 0) { /* extend BBOX */
00381        min(x_min,-x_offset_def); 
00382        max(x_max,x_min + x_width_def);
00383        min(y_min,-y_offset_def);
00384        max(y_max,y_min + y_width_def);
00385       }
00386       if (x_width_def <= 0 || flags & EXPAND_BBOX) {
00387        x_width = x_max-x_min;
00388        y_width = y_max-y_min;
00389        x_offset = -x_min; /* offset by moving topleft corner */ 
00390        y_offset = -y_min; /* offset by moving topleft corner */
00391       } else {
00392        x_width=x_width_def;
00393        y_width=y_width_def;
00394        x_offset=x_offset_def;
00395        y_offset=y_offset_def;
00396       }
00397       DEBUG_PRINT(DEBUG_DVI,("\n  IMAGE:\t%dx%d",x_width,y_width));
00398       SeekPage(dvi,dvi_pos);
00399       CreateImage(x_width,y_width);
00400 #ifdef DEBUG
00401       DEBUG_PRINT(DEBUG_DVI,("\n@%d PAGE START:\tBOP",dvi_pos->offset));
00402       {
00403        int i;
00404        for (i=0;i<10;i++) 
00405          DEBUG_PRINT(DEBUG_DVI,(" %d",dvi_pos->count[i]));
00406        DEBUG_PRINT(DEBUG_DVI,(" (%d)\n",dvi_pos->count[10]));
00407       }
00408 #endif
00409       Message(BE_NONQUIET,"[%d", dvi_pos->count[(flags & DVI_PAGENUM)?0:10]);
00410       if (dvi_pos->count[(flags & DVI_PAGENUM)?0:10]!=dvi_pos->count[0])
00411        Message(BE_NONQUIET," (%d)", dvi_pos->count[0]);
00412       Message(REPORT_DEPTH," depth=%d", y_width-y_offset-1);
00413       Message(REPORT_HEIGHT," height=%d", y_offset+1);
00414       DrawPage(x_offset*dvi->conv*shrinkfactor,
00415               y_offset*dvi->conv*shrinkfactor);
00416       if ( ! (flags & MODE_PICKY && flags & PAGE_GAVE_WARN )) {
00417        WriteImage(dvi->outname,dvi_pos->count[(flags & DVI_PAGENUM)?0:10]);
00418 #ifdef TIMING
00419        ++ndone;
00420 #endif
00421       } else {
00422        exitcode=EXIT_FAILURE;
00423        Message(BE_NONQUIET," not rendered");
00424        DestroyImage();
00425       }
00426       Message(BE_NONQUIET,"] ");
00427       fflush(stdout);
00428       flags &= ~PAGE_GAVE_WARN;
00429       dvi_pos=NextPPage(dvi,dvi_pos);
00430     }
00431     Message(BE_NONQUIET,"\n");
00432     ClearPpList();
00433   }
00434 }