Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2 
      3 Copyright (c) 1991  X Consortium
      4 
      5 Permission is hereby granted, free of charge, to any person obtaining
      6 a copy of this software and associated documentation files (the
      7 "Software"), to deal in the Software without restriction, including
      8 without limitation the rights to use, copy, modify, merge, publish,
      9 distribute, sublicense, and/or sell copies of the Software, and to
     10 permit persons to whom the Software is furnished to do so, subject to
     11 the following conditions:
     12 
     13 The above copyright notice and this permission notice shall be included
     14 in all copies or substantial portions of the Software.
     15 
     16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     19 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22 OTHER DEALINGS IN THE SOFTWARE.
     23 
     24 Except as contained in this notice, the name of the X Consortium shall
     25 not be used in advertising or otherwise to promote the sale, use or
     26 other dealings in this Software without prior written authorization
     27 from the X Consortium.
     28 
     29 */
     30 
     31 /*
     32  * parse.c
     33  *
     34  * parse dvi input
     35  */
     36 
     37 #ifdef HAVE_CONFIG_H
     38 # include "config.h"
     39 #endif
     40 
     41 #include <X11/Xos.h>
     42 #include <X11/IntrinsicP.h>
     43 #include <X11/StringDefs.h>
     44 #include <stdio.h>
     45 #include <ctype.h>
     46 #include "DviP.h"
     47 
     48 static void ParseDrawFunction(DviWidget dw, char *buf);
     49 static void ParseDeviceControl(DviWidget dw);
     50 static void PutCharacters(DviWidget dw, unsigned char *src, int len);
     51 static void push_env(DviWidget dw);
     52 static void pop_env(DviWidget dw);
     53 
     54 #ifdef USE_XFT
     55 static int
     56 charWidth(DviWidget dw, XftFont *font, char c)
     57 {
     58     XGlyphInfo extents;
     59 
     60     XftTextExtents8(XtDisplay(dw), font, (unsigned char *) &c, 1, &extents);
     61     return extents.xOff;
     62 }
     63 #else
     64 #define charWidth(dw,fi,c) (\
     65     (fi)->per_char ?\
     66 	(fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
     67     :\
     68 	(fi)->max_bounds.width\
     69 )
     70 #endif
     71 
     72 int
     73 ParseInput(DviWidget dw)
     74 {
     75     char Buffer[BUFSIZ];
     76 
     77     /*
     78      * make sure some state exists
     79      */
     80 
     81     if (!dw->dvi.state)
     82         push_env(dw);
     83     for (;;) {
     84         int c;
     85 
     86         switch (DviGetC(dw, &c)) {
     87         case '\n':
     88             break;
     89         case ' ':              /* when input is text */
     90         case 0:                /* occasional noise creeps in */
     91             break;
     92         case '{':              /* push down current environment */
     93             push_env(dw);
     94             break;
     95         case '}':
     96             pop_env(dw);
     97             break;
     98             /*
     99              * two motion digits plus a character
    100              */
    101         case '0':
    102         case '1':
    103         case '2':
    104         case '3':
    105         case '4':
    106         case '5':
    107         case '6':
    108         case '7':
    109         case '8':
    110         case '9':
    111         {
    112             int otherc;
    113             HorizontalMove(dw, (c - '0') * 10 + DviGetC(dw, &otherc) - '0');
    114         }
    115             /* fall through */
    116         case 'c':              /* single ascii character */
    117             (void) DviGetC(dw, &c);
    118             if (c == ' ')
    119                 break;
    120             else {
    121                 unsigned char tc = c;
    122                 PutCharacters(dw, &tc, 1);
    123             }
    124             break;
    125         case 'C':
    126             GetWord(dw, Buffer, BUFSIZ);
    127             {
    128                 DviCharNameMap *map;
    129                 int prevFont;
    130 
    131                 c = -1;
    132                 map = QueryFontMap(dw, dw->dvi.state->font_number);
    133                 if (map) {
    134                     c = DviCharIndex(map, Buffer);
    135                     if (c == -1) {
    136                         unsigned char *ligature = DviCharIsLigature(map, Buffer);
    137                         if (ligature) {
    138                             int l = strlen((char *) ligature);
    139                             PutCharacters(dw, ligature, l);
    140                             break;
    141                         }
    142                     }
    143                 }
    144                 prevFont = -1;
    145                 if (c == -1) {
    146                     for (int i = 1; (map = QueryFontMap(dw, i)); i++) {
    147                         if (map->special) {
    148                             if ((c = DviCharIndex(map, Buffer)) != -1) {
    149                                 prevFont = dw->dvi.state->font_number;
    150                                 dw->dvi.state->font_number = i;
    151                                 break;
    152                             }
    153                         }
    154                     }
    155                 }
    156                 if (c != -1) {
    157                     unsigned char tc = c;
    158                     PutCharacters(dw, &tc, 1);
    159                 }
    160                 if (prevFont != -1)
    161                     dw->dvi.state->font_number = prevFont;
    162             }
    163             break;
    164         case 'D':              /* draw function */
    165             GetLine(dw, Buffer, BUFSIZ);
    166             ParseDrawFunction(dw, Buffer);
    167             break;
    168         case 's':              /* ignore fractional sizes */
    169         {
    170             int n = GetNumber(dw);
    171             if (!dw->dvi.size_scale) {
    172                 static const int guesses[] = { 1, 4, 100, 1000, 1 };
    173                 int i;
    174 
    175                 for (i = 0; i < 4; i++) {
    176                     if (8 <= n / guesses[i] && n / guesses[i] <= 24) {
    177                         break;
    178                     }
    179                 }
    180                 dw->dvi.size_scale = guesses[i];
    181             }
    182             dw->dvi.state->font_size = n;
    183             dw->dvi.state->line_width = n * (dw->dvi.device_resolution /
    184                                              (720 * dw->dvi.size_scale));
    185         }
    186             break;
    187         case 'f':
    188         {
    189             int n = GetNumber(dw);
    190             dw->dvi.state->font_number = n;
    191         }
    192             break;
    193         case 'H':              /* absolute horizontal motion */
    194         {
    195             int k = GetNumber(dw);
    196             HorizontalGoto(dw, k);
    197         }
    198             break;
    199         case 'h':              /* relative horizontal motion */
    200         {
    201             int k = GetNumber(dw);
    202             HorizontalMove(dw, k);
    203         }
    204             break;
    205         case 'w':              /* word space */
    206             break;
    207         case 'V':
    208         {
    209             int n = GetNumber(dw);
    210             VerticalGoto(dw, n);
    211         }
    212             break;
    213         case 'v':
    214         {
    215             int n = GetNumber(dw);
    216             VerticalMove(dw, n);
    217         }
    218             break;
    219         case 'P':              /* new spread */
    220             break;
    221         case 'p':              /* new page */
    222         {
    223             int NextPage;
    224 
    225             (void) GetNumber(dw);
    226             NextPage = dw->dvi.current_page + 1;
    227             RememberPagePosition(dw, NextPage);
    228             FlushCharCache(dw);
    229             return (NextPage);
    230         }
    231         case 'n':              /* end of line */
    232             GetNumber(dw);
    233             GetNumber(dw);
    234             HorizontalGoto(dw, 0);
    235             break;
    236         case '#':              /* comment */
    237         case 'F':              /* file info */
    238             GetLine(dw, NULL, 0);
    239             break;
    240         case 't':              /* text */
    241             GetLine(dw, Buffer, BUFSIZ);
    242             PutCharacters(dw, (unsigned char *) Buffer, strlen(Buffer));
    243             dw->dvi.state->x = ToDevice(dw, dw->dvi.cache.x);
    244             break;
    245         case 'x':              /* device control */
    246             ParseDeviceControl(dw);
    247             break;
    248         case EOF:
    249             dw->dvi.last_page = dw->dvi.current_page;
    250             FlushCharCache(dw);
    251             return dw->dvi.current_page;
    252         default:
    253             GetLine(dw, Buffer, BUFSIZ);
    254             fprintf(stderr, "Unknown command %s\n", Buffer);
    255             break;
    256         }
    257     }
    258 }
    259 
    260 static void
    261 push_env(DviWidget dw)
    262 {
    263     DviState *new = (DviState *) XtMalloc(sizeof(*new));
    264 
    265     if (dw->dvi.state)
    266         *new = *(dw->dvi.state);
    267     else {
    268         new->font_size = 10 * dw->dvi.size_scale;
    269         new->font_number = 1;
    270         new->line_style = 0;
    271         new->line_width = 10;
    272         new->x = 0;
    273         new->y = 0;
    274     }
    275     new->next = dw->dvi.state;
    276     dw->dvi.state = new;
    277 }
    278 
    279 static void
    280 pop_env(DviWidget dw)
    281 {
    282     DviState *old = dw->dvi.state;
    283     dw->dvi.state = old->next;
    284     XtFree((char *) old);
    285 }
    286 
    287 static void
    288 InitTypesetter(DviWidget dw)
    289 {
    290     while (dw->dvi.state)
    291         pop_env(dw);
    292     dw->dvi.size_scale = dw->dvi.size_scale_set;
    293     push_env(dw);
    294     FlushCharCache(dw);
    295 }
    296 
    297 static void
    298 SetFont(DviWidget dw)
    299 {
    300     dw->dvi.cache.font_size = dw->dvi.state->font_size;
    301     dw->dvi.cache.font_number = dw->dvi.state->font_number;
    302     dw->dvi.cache.font = QueryFont(dw,
    303                                    dw->dvi.cache.font_number,
    304                                    dw->dvi.cache.font_size);
    305 }
    306 
    307 static void
    308 PutCharacters(DviWidget dw, unsigned char *src, int len)
    309 {
    310     char *dst;
    311 
    312     int xx = ToX(dw, dw->dvi.state->x);
    313     int yx = ToX(dw, dw->dvi.state->y);
    314     int fy = FontSizeInPixels(dw, dw->dvi.state->font_size);
    315     int fx = fy * len;
    316 
    317     /*
    318      * quick and dirty extents calculation:
    319      */
    320     if (yx + fy >= dw->dvi.extents.y1 &&
    321         yx - fy <= dw->dvi.extents.y2 &&
    322         xx + fx >= dw->dvi.extents.x1 && xx - fx <= dw->dvi.extents.x2) {
    323 #ifdef USE_XFT
    324         XftFont *font;
    325         DviTextItem *text;
    326 #else
    327         register XFontStruct *font;
    328         register XTextItem *text;
    329 #endif
    330 
    331         if (!dw->dvi.display_enable)
    332             return;
    333 
    334         if (yx != dw->dvi.cache.y ||
    335             dw->dvi.cache.char_index + len > DVI_CHAR_CACHE_SIZE)
    336             FlushCharCache(dw);
    337         /*
    338          * load a new font, if the current block is not empty,
    339          * step to the next.
    340          */
    341         if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
    342             dw->dvi.cache.font_number != dw->dvi.state->font_number) {
    343             SetFont(dw);
    344             if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
    345                 ++dw->dvi.cache.index;
    346                 if (dw->dvi.cache.index >= dw->dvi.cache.max)
    347                     FlushCharCache(dw);
    348                 dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
    349             }
    350         }
    351         if (xx != dw->dvi.cache.x) {
    352             if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
    353                 ++dw->dvi.cache.index;
    354                 if (dw->dvi.cache.index >= dw->dvi.cache.max)
    355                     FlushCharCache(dw);
    356                 dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
    357             }
    358         }
    359         if (!dw->dvi.cache.font)
    360             SetFont(dw);
    361         text = &dw->dvi.cache.cache[dw->dvi.cache.index];
    362         font = dw->dvi.cache.font;
    363         dst = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
    364         if (text->nchars == 0) {
    365             text->chars = dst;
    366 #ifdef USE_XFT
    367             text->x = xx;
    368 #else
    369             text->delta = xx - dw->dvi.cache.x;
    370 #endif
    371 #ifdef USE_XFT
    372             text->font = font;
    373 #endif
    374             if (font != dw->dvi.font) {
    375 #ifndef USE_XFT
    376                 text->font = font->fid;
    377 #endif
    378                 dw->dvi.font = font;
    379             }
    380 #ifndef USE_XFT
    381             else
    382                 text->font = None;
    383 #endif
    384             dw->dvi.cache.x = xx;
    385         }
    386         dw->dvi.cache.char_index += len;
    387         text->nchars += len;
    388         while (len--) {
    389             int c = *src++;
    390             *dst++ = c;
    391             if (font)
    392                 dw->dvi.cache.x += charWidth(dw, font, c);
    393         }
    394     }
    395 }
    396 
    397 static void
    398 ParseDrawFunction(DviWidget dw, char *buf)
    399 {
    400     int n, m, n1, m1;
    401 
    402     SetGCForDraw(dw);
    403     switch (buf[0]) {
    404     case 'l':                  /* draw a line */
    405         sscanf(buf + 1, "%d %d", &n, &m);
    406         DrawLine(dw, n, m);
    407         break;
    408     case 'c':                  /* circle */
    409         sscanf(buf + 1, "%d", &n);
    410         DrawCircle(dw, n);
    411         break;
    412     case 'e':                  /* ellipse */
    413         sscanf(buf + 1, "%d %d", &m, &n);
    414         DrawEllipse(dw, m, n);
    415         break;
    416     case 'a':                  /* arc */
    417         sscanf(buf + 1, "%d %d %d %d", &n, &m, &n1, &m1);
    418         DrawArc(dw, n, m, n1, m1);
    419         break;
    420     case '~':                  /* wiggly line */
    421         DrawSpline(dw, buf + 1, 1);
    422         break;
    423     case 't':                  /* line width */
    424         sscanf(buf + 1, "%d", &n);
    425         dw->dvi.state->line_width = n;
    426         break;
    427     case 's':                  /* line style */
    428         sscanf(buf + 1, "%d", &n);
    429         /* XXX */
    430         break;
    431     default:
    432         /* warning("unknown drawing function %s", buf); */
    433         break;
    434     }
    435 }
    436 
    437 extern int LastPage, CurrentPage;
    438 
    439 static void
    440 ParseDeviceControl(DviWidget dw)
    441 {                               /* Parse the x commands */
    442     char str[20];
    443     int c;
    444 
    445     GetWord(dw, str, 20);
    446     switch (str[0]) {           /* crude for now */
    447     case 'T':                  /* output device */
    448         GetWord(dw, str, 20);
    449         break;
    450     case 'i':                  /* initialize */
    451         InitTypesetter(dw);
    452         break;
    453     case 't':                  /* trailer */
    454         break;
    455     case 'p':                  /* pause -- can restart */
    456         break;
    457     case 's':                  /* stop */
    458         return;
    459     case 'r':                  /* resolution when prepared */
    460         SetDeviceResolution(dw, GetNumber(dw));
    461         break;
    462     case 'f':                  /* font used */
    463     {
    464         int n = GetNumber(dw);
    465         char str1[50];
    466 
    467         GetWord(dw, str, 20);
    468         GetLine(dw, str1, 50);
    469         SetFontPosition(dw, n, str, str1);
    470     }
    471         break;
    472     case 'H':                  /* char height */
    473         break;
    474     case 'S':                  /* slant */
    475         break;
    476     }
    477     while (DviGetC(dw, &c) != '\n')     /* skip rest of input line */
    478         if (c == EOF)
    479             return;
    480 }
    481