1/* 2 3Copyright (c) 1991 X Consortium 4 5Permission is hereby granted, free of charge, to any person obtaining 6a copy of this software and associated documentation files (the 7"Software"), to deal in the Software without restriction, including 8without limitation the rights to use, copy, modify, merge, publish, 9distribute, sublicense, and/or sell copies of the Software, and to 10permit persons to whom the Software is furnished to do so, subject to 11the following conditions: 12 13The above copyright notice and this permission notice shall be included 14in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of the X Consortium shall 25not be used in advertising or otherwise to promote the sale, use or 26other dealings in this Software without prior written authorization 27from 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 48static void ParseDrawFunction(DviWidget dw, char *buf); 49static void ParseDeviceControl(DviWidget dw); 50static void PutCharacters(DviWidget dw, unsigned char *src, int len); 51static void push_env(DviWidget dw); 52static void pop_env(DviWidget dw); 53 54#ifdef USE_XFT 55static int 56charWidth(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 72int 73ParseInput(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 260static void 261push_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 279static void 280pop_env(DviWidget dw) 281{ 282 DviState *old = dw->dvi.state; 283 dw->dvi.state = old->next; 284 XtFree((char *) old); 285} 286 287static void 288InitTypesetter(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 297static void 298SetFont(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 307static void 308PutCharacters(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 397static void 398ParseDrawFunction(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 437extern int LastPage, CurrentPage; 438 439static void 440ParseDeviceControl(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